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:
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:
Open sample project file.
To build the target, follow the steps listed on the Generating App Image in Quick Start.
After a successful compilation, the app bin
app_MP_xxx.bin
will be generated in the directorymdk\bin
orgcc\bin
.To download app bin into EVB board, follow the steps listed on the MP Tool Download in Quick Start.
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:
Peripheral initialization will be introduced in chapter Initialization.
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:
Configure PAD: set pins, PINMUX mode, PowerOn, internal pull-none.
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:
Enable RCC clock.
Set I2S clock source to 40MHz.
Set the Sample rate to 16kHz.
Set I2S to slave device mode.
Set I2S to stereo mode.
Set data width and data format.
Disable I2S DMA transfer.
Select I2S data communication to external channel.
Enable I2S TX mode.
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);
}
}