Slave Receive

该示例通过使用 I2S 外设实现接收功能。

测试该示例时,可以使用另一颗 EVB 烧录发送程序作为发送端,与该 EVB 进行数据通信。

I2S 接收到数据后,触发中断,在中断函数内接收数据。

环境需求

该示例支持以下开发套件:

开发套件

Hardware Platforms

Board Name

RTL8752H HDK

RTL8752H EVB

更多信息请参考 快速入门

硬件连线

连接 P3_2(LRCK)至发送端的 LRCK 引脚,连接 P3_3(BCLK)至发送端的 BCLK 引脚,连接 P4_0(DATA_RX)至发送端的 DATA 引脚。

编译和下载

该示例的工程路径如下:

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

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

请按照以下步骤操作构建并运行该示例:

  1. 打开工程文件。

  2. 按照 快速入门编译 APP Image 给出的步骤构建目标文件。

  3. 编译成功后,在路径 mdk\bingcc\bin 下会生成 app bin app_MP_xxx.bin 文件。

  4. 按照 快速入门MP Tool 给出的步骤将 app bin 烧录至 EVB 内。

  5. 按下 reset 按键,开始运行。

测试验证

Slave 端收到数据后,在中断函数内,打印收到的数据。

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

代码介绍

该章节分为以下几个部分:

  1. 源码路径

  2. 初始化函数将在 初始化 章节介绍。

  3. 初始化后的功能实现将在 功能实现 章节介绍。

源码路径

  • 工程路径: sdk\board\evb\io_sample\I2S\I2S_Slave_Recv

  • 源码路径: sdk\src\sample\io_sample\I2S\I2S_Slave_Recv

该工程的工程文件代码结构如下:

└── 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

初始化

当 EVB 复位启动时,执行 main 函数,执行以下流程:

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

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

i2s_demo 中,包含了 PAD/PINMUX 设置,I2S 外设的初始化流程。

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

board_i2s_init 为 PAD 与 PINMUX 设置,包含如下流程:

  1. 配置 PAD:设置引脚、PINMUX 模式、Power On、无内部上拉。

  2. 配置 PINMUX:分配引脚分别为 BCLK_SPORT0、LRC_SPORT0、ADCDAT_SPORT0 功能。

driver_i2s_init 为对 I2S 外设的初始化,包含如下流程:

  1. 使能 RCC 时钟。

  2. 设置 I2S 时钟源为 40MHz。

  3. 设置采样率为 16kHz。

  4. 设置 I2S 为从设备模式。

  5. 设置 I2S 为双声道模式。

  6. 设置数据宽度和数据格式。

  7. 关闭 I2S DMA 传输。

  8. 将 I2S 的数据通信选择为外部通道。

  9. 使能 I2S TX 模式。

  10. 配置 I2S 接收完毕中断。

备注

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);
}

功能实现

当 I2S 接收到数据后,触发 I2S_INT_RX_READY ,进入中断处理函数 I2S0_RX_Handler ,读取收到的数据并打印。

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);
    }
}