深入解析SAI接口:I2S、AC97、TDM与code/DSP的多模式应用

张开发
2026/4/13 16:24:20 15 分钟阅读

分享文章

深入解析SAI接口:I2S、AC97、TDM与code/DSP的多模式应用
1. SAI接口基础音频传输的多面手第一次接触SAI接口时我完全被它支持的多种音频协议搞晕了。直到在i.MX6UL项目上实际调试音频模块才发现这个接口的灵活性简直是为嵌入式音频系统量身定制的。SAISynchronous Audio Interface是NXP处理器中的同步音频接口它最大的特点就是能兼容I2S、AC97、TDM和code/DSP四种主流音频协议就像个万能插座可以连接各种不同类型的音频设备。SAI接口的信号线其实很好理解主要分为三组时钟信号、数据信号和同步信号。MCLK主时钟相当于整个系统的节拍器BCLK位时钟控制每个数据位的传输节奏而SYNC帧同步则标记左右声道的切换点。最妙的是它的双通道设计接收(RX)和发送(TX)通道有各自独立的时钟系统这意味着你可以同时进行录音和播放——想象成高速公路的双向车道来往车辆互不干扰。在实际项目中我常用i.MX6UL的SAI1接口连接主音频编解码器SAI2接口则留给蓝牙模块。这种设计让系统可以同时处理本地音频播放和蓝牙通话实测延迟能控制在20ms以内。记得第一次调试时我犯了个低级错误——把MCLK频率设错了结果音频像卡通片里小丑的声音。后来发现时钟配置是SAI接口最关键的部分不同音频协议对时钟的要求天差地别。2. I2S模式高保真音频的首选方案2.1 硬件连接实战I2S模式应该是SAI接口最常用的工作方式特别是在需要高音质的场景。去年做智能音箱项目时我们选用WM8960编解码器通过I2S连接i.MX6UL的SAI接口。硬件连接其实很简单只需要6根线SAI_TX_DATA接编解码器的DINSAI_RX_DATA接DOUT共享的BCLK和SYNC信号独立的MCLK输出别忘了共地这里有个坑要注意虽然标准I2S只需要3根信号线BCLK、SYNC、DATA但实际应用中建议始终启用MCLK。我遇到过因为省掉MCLK导致编解码器时钟漂移的问题表现为每隔几分钟就会出现啪的爆音。后来在原理图评审时硬件工程师老张教我个诀窍在MCLK线上串个22欧姆电阻能有效抑制振铃现象。2.2 软件配置要点在Linux驱动里配置SAI的I2S模式主要关注这几个寄存器/* 设置为主模式生成BCLK和SYNC */ IOMUXC_SetPinMux(SAI1_TX_BCLK, 1); IOMUXC_SetPinMux(SAI1_TX_SYNC, 1); /* 配置时钟分频 */ CCM_ANALOG-PLL_AUDIO CCM_ANALOG_PLL_AUDIO_ENABLE_MASK | CCM_ANALOG_PLL_AUDIO_DIV_SELECT(1); /* 设置数据格式 */ SAI1-TCR2 SAI_TCR2_MSEL(1) | // 使用MCLK SAI_TCR2_BCD_MASK; // 使能BCLK调试时建议先用arecord和aplay工具测试基础功能。有次客户反映录音有杂音最后发现是DMA缓冲区设置太小导致数据丢失。我的经验值是设置至少8个周期每个周期1024帧这样即使在系统负载高时也能保证流畅。3. AC97模式老当益壮的经典协议3.1 连接传统音频设备虽然AC97看起来像是上个世纪的技术确实也是但在某些工业设备升级改造中还是会遇到。去年帮一家工厂改造老式对讲系统他们的主控板用的就是AC97编解码器。SAI接口的AC97模式与I2S最大的不同在于采用固定的12.288MHz主时钟数据帧包含标签位和16位有效数据需要额外的RESET和SYNC信号硬件连接上要特别注意AC97要求SYNC信号在BCLK的上升沿采样这与I2S完全相反。我在第一次调试时没注意这个细节结果折腾了一整天都没出声音。后来用逻辑分析仪抓波形才发现相位反了在设备树里加个fsync-polarity属性就解决了。3.2 配置技巧与坑点AC97的Linux驱动配置比较特殊需要先初始化编解码器# 加载AC97编解码器驱动 echo wm9713-codec /sys/bus/platform/drivers/ac97_bus/bind在设备树中要明确指定AC97模式sai1: sai02034000 { compatible fsl,imx6ul-sai; pinctrl-names default; pinctrl-0 pinctrl_sai1_ac97; fsl,sai-ac97-mode; };实测中发现AC97对时序要求特别严格有次因为PCB走线过长导致信号延迟出现随机性断音。后来我们做了这些优化将SAI与编解码器的距离控制在10cm内所有信号线走等长线误差控制在±50ps在SYNC信号上加22pF电容滤波4. TDM模式多声道音频的解决方案4.1 实现8声道音频采集在车载娱乐系统项目中我们需要同时采集8个麦克风的信号。这时SAI的TDM模式就派上大用场了。TDMTime Division Multiplexing通过时分复用技术在单条数据线上传输多个音频通道。硬件连接与I2S类似但软件配置大不相同// 配置TDM 8声道模式 SAI1-TCR4 SAI_TCR4_FSD_MASK | // 帧同步检测 SAI_TCR4_FSP_MASK | // 帧同步极性 SAI_TCR4_SYWD(31) | // 每个时隙32位 SAI_TCR4_MF(1); // MSB优先调试TDM时最容易出错的是时隙配置。有次我把SYWD设成了1516位结果第3个声道以后的数据全乱了。后来总结出规律时隙宽度必须大于等于实际数据位数多余位会自动补零。4.2 与DSP的协同工作在语音识别设备中我们经常需要将SAI采集的音频直接送给DSP处理。这时可以用TDM的daisy-chain模式把多个设备串联起来。关键配置点包括设置SAI为主设备生成所有时钟启用TCR5寄存器的FBT位控制数据延迟调整DMA缓冲区的交错格式记得有次调试时DSP收到的数据总是错位。最后发现是DMA缓冲区没按interleaved格式配置导致声道数据混在一起。修正后的ALSA配置如下pcm.multi { type multi slaves.a.pcm hw:0,0 slaves.a.channels 8 bindings.0.slave a bindings.0.channel 0 # 绑定其他声道... }5. Codec/DSP模式定制化音频处理5.1 与专用音频处理器对接在高端音频设备中我们可能需要连接专用的音频DSP。SAI的code/DSP模式提供了最大的灵活性允许自定义帧格式和时钟极性。去年开发专业音频调音台时我们这样配置与SHARC DSP的接口sai2: sai02038000 { compatible fsl,imx6ul-sai; fsl,sai-synchronous-rx; fsl,sai-custom-format; bitclock-inversion; frame-inversion; assigned-clocks clks IMX6UL_CLK_SAI2_SEL; };这种模式下最麻烦的是时钟同步问题。有次发现音频每隔几分钟就会跳一下最后查出是SAI和DSP使用了不同的时钟源。解决方法是在DSP端启用SRC采样率转换或者改用SAI的异步模式。5.2 实战中的性能优化在实时音频处理系统中延迟是致命问题。通过SAI的异步模式DMA环形缓冲区我们实现了5ms的端到端延迟。关键优化点包括使用双缓冲DMA传输避免音频中断将SAI中断优先级设为最高禁用CPU频率调节器内存锁定DMA缓冲区测试时可以用这个命令测量实际延迟arecord -f dat | aplay -f dat --delay0记得有次客户要求同时支持蓝牙和本地音频我们巧妙利用了SAI1和SAI2的异步工作特性分别配置不同的时钟源完美解决了时钟冲突问题。这种设计后来成了我们产品的标准方案。

更多文章