[I2S]I2S多数据线同时使用介绍
一、先楫I2S多数据线介绍
先楫的I2S外设支持4条TXD和4条RXD数据线,使用1个I2S外设,即可同时与4个Codec传输音频数据。
注意: 因为共享数据格式配置寄存器,4个TXD和4个RXD数据线需要工作在相同的数据格式。
1.1 I2S外设结构框图
1.2 I2S多数据线连接框图
二、实现I2S 4数据线同时使用
2.1 配置I2S外设
使用i2s_config_multiline_transfer
API进行多数据线收发,如下是配置I2S 4数据线TXD进行发送的配置示例。
/*
* I2S主模式多数据线配置函数
* 配置I2S 4数据线TXD进行发送
*/
void i2s_master_multiline_config(void)
{
i2s_config_t i2s_config;
i2s_multiline_transfer_config_t transfer;
uint32_t i2s_mclk_hz;
/* 配置I2S接口 */
i2s_get_default_config(I2S_MASTER, &i2s_config);
i2s_config.tx_fifo_threshold = I2S_TX_FIFO_THRESHOLD; /* 设置发送FIFO阈值 */
i2s_config.enable_mclk_out = true; /* 使能主时钟输出 */
i2s_init(I2S_MASTER, &i2s_config);
/* 配置I2S传输参数 */
i2s_get_default_multiline_transfer_config(&transfer);
transfer.sample_rate = audio_data.sample_rate; /* 设置采样率 */
transfer.channel_num_per_frame = 2; /* 每帧通道数 */
transfer.audio_depth = audio_data.audio_depth; /* 设置位深 */
transfer.channel_length = i2s_channel_length_32_bits; /* 通道长度 */
transfer.master_mode = true; /* 主模式 */
transfer.protocol = I2S_PROTOCOL_MSB_JUSTIFIED; /* MSB对齐协议 */
/* 使能4个发送数据线 */
transfer.tx_data_line_en[0] = true;
transfer.tx_data_line_en[1] = true;
transfer.tx_data_line_en[2] = true;
transfer.tx_data_line_en[3] = true;
/* 配置通道槽掩码 */
transfer.tx_channel_slot_mask[0] = (1 << audio_data.channel_num) - 1;
transfer.tx_channel_slot_mask[1] = (1 << audio_data.channel_num) - 1;
transfer.tx_channel_slot_mask[2] = (1 << audio_data.channel_num) - 1;
transfer.tx_channel_slot_mask[3] = (1 << audio_data.channel_num) - 1;
/* 配置I2S数据格式 */
i2s_mclk_hz = clock_get_frequency(I2S_MASTER_CLOCK_NAME);
if (status_success != i2s_config_multiline_transfer(I2S_MASTER, i2s_mclk_hz, &transfer)) {
printf("I2S config failed!\n");
}
}
2.2 音频数据搬运
需要连续将源数据写入I2S->TXD[0-3]寄存器实现音频发送。
需要连续从I2S->RXD[0-3]寄存器数据读出实现音频接收。
2.2.1 使用中断方式处理数据搬运
设置I2S的FIFO阈值,并使能对应中断,在中断服务函数中写入数据到I2S的发送寄存器TXD和从I2S的接收寄存器RXD读取数据。
可以适用于先楫支持I2S的全部系列
可以参考附件中的参考例程i2s_multiline_interrupt
2.2.2 使用DMA方式处理数据搬运
-
在HPM6700/HPM6400/HPM6300/HPM6800系列中,I2S的多条数据线共享一个DMA请求,且这些平台上的DMA外设并不支持burst小循环,无法实现DMA同时为多个I2S数据线搬运数据。
原因说明:例如想实现I2S 4个数据线的数据发送,由于DMA不支持burst小循环,需要使用4个DMA通道处理4个数据线的发送请求,这造成1个DMA请求要用于4个DMA通道,这是DMA不能不支持的使用情况。
-
在HPM6E00系列,I2S的4条数据线还是共享一个DMA请求,但是其DMAv2外设支持Burst小循环,能够将I2S->TXD[0-3]或者I2S0->RXD[0-3]作为一个burst进行遍历,使用一个DMA通道就可以完成I2S4根数据线的发送任务或者接收任务。
可以参考附件中的参考例程
i2s_multiline_dmav2
-
在HPM6P00系列,I2S的4条数据线有4个独立TX/RX DMA请求,这样可以使用4个DMA通道来处理4个I2S数据线的发送或接收任务。
可以参考附件中的参考例程
i2s_4_dma_req_multiline
参考例程和说明
例程同样可以在hpm_sdk_extra中获取,其网址:
github: github: hpm_sdk_extra
gitee: gitee: hpm_sdk_extra
参考例程是按照先楫HPM_SDK中的samples形式组织,可以使用相应工具构建工程,进行编译和测试。
由于先楫的EVK并未考虑I2S的4数据线使用情况,附件例程实现的I2S数据4数据线发送并不能在EVK上直接运行观察效果,需要自行设计板子,留出I2S 4数据线的接口,运行程序使用逻辑分析仪等工具测量I2S 4数据线的发送情况。
例程中的引脚需要按照实际板子进行修改:
void init_i2s_multiline_pin(void)
{
/* 配置I2S引脚功能 */
HPM_IOC->PAD[IOC_PAD_PB11].FUNC_CTL = IOC_PB11_FUNC_CTL_I2S0_MCLK; /* 主时钟 */
HPM_IOC->PAD[IOC_PAD_PB01].FUNC_CTL = IOC_PB01_FUNC_CTL_I2S0_BCLK; /* 位时钟 */
HPM_IOC->PAD[IOC_PAD_PB10].FUNC_CTL = IOC_PB10_FUNC_CTL_I2S0_FCLK; /* 帧时钟 */
HPM_IOC->PAD[IOC_PAD_PB00].FUNC_CTL = IOC_PB00_FUNC_CTL_I2S0_TXD_0; /* TX数据线0 */
HPM_IOC->PAD[IOC_PAD_PB03].FUNC_CTL = IOC_PB03_FUNC_CTL_I2S0_TXD_1; /* TX数据线1 */
HPM_IOC->PAD[IOC_PAD_PB05].FUNC_CTL = IOC_PB05_FUNC_CTL_I2S0_TXD_2; /* TX数据线2 */
HPM_IOC->PAD[IOC_PAD_PB02].FUNC_CTL = IOC_PB02_FUNC_CTL_I2S0_TXD_3; /* TX数据线3 */
}
使用逻辑分析观察引脚信号: