Slave Receive

This example demonstrates the reception function using the I2S peripheral.

To test this example, it can use another EVB programmed with the sending program as the transmitter to communicate data with this EVB.

After the I2S receives the data, it triggers an interrupt, and the data is received within the interrupt function.

Requirements

The sample supports the following development kits:

Development Kits

Hardware Platforms

Board Name

RTL8752H HDK

RTL8752H EVB

For more requirements, please refer to Quick Start.

Wiring

Connect P3_2 (LRCK) to the LRCK pin of the transmitter, connect P3_3 (BCLK) to the BCLK pin of the transmitter, and connect P4_0 (DATA_RX) to the DATA pin of the transmitter.

Building and Downloading

This sample can be found in the SDK folder:

Project file: board\evb\io_sample\I2S\I2S_Slave_Recv\mdk

Project file: board\evb\io_sample\I2S\I2S_Slave_Recv\gcc

Please follow these steps to build and run the example:

  1. Open sample project file.

  2. To build the target, follow the steps listed on the Generating App Image in Quick Start.

  3. After a successful compilation, the app bin app_MP_xxx.bin will be generated in the directory mdk\bin or gcc\bin.

  4. To download app bin into EVB board, follow the steps listed on the MP Tool Download in Quick Start.

  5. Press reset button on EVB board and it will start running.

Experimental Verification

After the Slave device receives the data, it prints the received data within the interrupt function.

length = xx
data[0] = xxx
data[1] = xxx
data[2] = xxx
...

Code Overview

This chapter will be introduced according to the following several parts:

  1. Source Code Directory.

  2. Peripheral initialization will be introduced in chapter Initialization.

  3. Functional implementation after initialization will be introduced in chapter Function Implementation.

Source Code Directory

  • Project directory: sdk\board\evb\io_sample\I2S\I2S_Slave_Recv

  • Source code directory: sdk\src\sample\io_sample\I2S\I2S_Slave_Recv

Source files are currently categorized into several groups as below.

└── Project: i2s_slave_recv
    └── secure_only_app
        └── include
            ├── app_define.h
            └── rom_uuid.h
        ├── cmsis                    includes CMSIS header files and startup files
            ├── overlay_mgr.c
            ├── system_rtl876x.c
            └── startup_rtl876x.s
        ├── lib                      includes all binary symbol files that user application is built on
            ├── rtl8752h_sdk.lib
            ├── gap_utils.lib
            └── ROM.lib
        ├── peripheral               includes all peripheral drivers and module code used by the application
            ├── rtl876x_rcc.c
            ├── rtl876x_pinmux.c
            ├── rtl876x_nvic.c
            └── rtl876x_i2s.c
        ├── profile
        └── app                      includes the ble_peripheral user application implementation
            └── main.c

Initialization

When the EVB reset is initiated, the main function is executed, following these steps:

int main(void)
{
    __enable_irq();
    i2s_demo();

    while (1)
    {
        __NOP();
        __NOP();
        __NOP();
        __NOP();
        __NOP();
        __NOP();
    }
}

In i2s_demo, it includes PAD/PINMUX settings and the initialization process of the I2S peripheral.

void i2s_demo(void)
{
    board_i2s_init();
    driver_i2s_init();
}

board_i2s_init is for PAD and PINMUX settings and includes the following steps:

  1. Configure PAD: set pins, PINMUX mode, PowerOn, internal pull-none.

  2. Configure PINMUX: assign pins to BCLK_SPORT0, LRC_SPORT0, and ADCDAT_SPORT0 functions.

driver_i2s_init is for I2S peripheral initialization and includes the following steps:

  1. Enable RCC clock.

  2. Set I2S clock source to 40MHz.

  3. Set the Sample rate to 16kHz.

  4. Set I2S to slave device mode.

  5. Set I2S to stereo mode.

  6. Set data width and data format.

  7. Disable I2S DMA transfer.

  8. Select I2S data communication to external channel.

  9. Enable I2S TX mode.

  10. Configure I2S receive complete interrupt.

Note

BCLK=I2S_ClockSource*(I2S_BClockNi/I2S_BClockMi)=1024K,LRCK=BCLK/64=16K

void driver_i2s_init(void)
{
    RCC_PeriphClockCmd(APB_I2S, APB_I2S_CLOCK, ENABLE);

    I2S_InitTypeDef I2S_InitStruct;
    I2S_StructInit(&I2S_InitStruct);
    I2S_InitStruct.I2S_ClockSource      = I2S_CLK_40M;
    /* BCLK = 40MHz*(ni/mi),  LRCK = BCLK/64 */
    I2S_InitStruct.I2S_BClockMi         = 0x271;    /* <!LRCK = 16K */
    I2S_InitStruct.I2S_BClockNi         = 0x10;     /* <!BCLK = 1024K */
    I2S_InitStruct.I2S_DeviceMode       = I2S_DeviceMode_Slave;
    I2S_InitStruct.I2S_ChannelType      = I2S_Channel_stereo;
    I2S_InitStruct.I2S_DataWidth        = I2S_Width_16Bits;
    I2S_InitStruct.I2S_DataFormat       = I2S_Mode;
    I2S_InitStruct.I2S_DMACmd           = I2S_DMA_DISABLE;
    I2S_Init(I2S_NUM, &I2S_InitStruct);
    /* Change the I2S transmission into external codec .*/
    I2S_CLK_SOURCE_REG_224 |= BIT(3);
//    DBG_DIRECT("I2S_CLK_SOURCE_REG_224 = 0x%X",I2S_CLK_SOURCE_REG_224);
    I2S_Cmd(I2S_NUM, I2S_MODE_RX, ENABLE);
    I2S_INTConfig(I2S_NUM, I2S_INT_RX_READY, ENABLE);

    NVIC_InitTypeDef NVIC_InitStruct;
    NVIC_InitStruct.NVIC_IRQChannel = I2S0_RX_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPriority = 3;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);
}

Functional Implementation

When the I2S receives data, it triggers I2S_INT_RX_READY, enters the interrupt handler function I2S0_RX_Handler, reads the received data and prints it.

void I2S0_RX_Handler(void)
{
    /* Notes: DBG_DIRECT is only used in debug demo, do not use in app project.*/
    DBG_DIRECT("I2S0_RX_Handler");
    if (I2S_GetINTStatus(I2S_NUM, I2S_INT_RX_READY))
    {
        uint8_t len = I2S_GetRxFIFOLen(I2S_NUM);
        DBG_DIRECT("length = %d", len);
        for (uint8_t i = 0; i < len; i++)
        {
            DBG_DIRECT("data[%d] = 0x%X", i, I2S_ReceiveData(I2S_NUM));
        }
        I2S_ClearINTPendingBit(I2S_NUM, I2S_INT_RX_READY);
    }
}