ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于Vivado的FPGA I2S回环验证:IP核配置与调试实战

基于Vivado的FPGA I2S回环验证:IP核配置与调试实战 我最近在白嫖板子做音频验证时把两件事一起干了用Xilinx Vivado搭了一个完整的I2S回环测试环境分别拉出AXI I2S Receiver IP核和AXI I2S Transmitter IP核然后让音频数据从RX进去再从TX出来最后用逻辑分析仪和示波器确认数据完整性。整个过程听起来很简单真正跑起来遇到的坑并不少——时钟极性、左右声道对齐、FIFO溢出、甚至JTAG线驱动都有问题。这篇文章适合手里有Xilinx FPGA开发板、想快速验证I2S音频链路但不想从零手写RTL的人内容会覆盖IP核配置、Block Design搭建、软件控制、板级验证和问题排查尽量做到开箱就能复现。1. 项目动机与验证方案选型1.1 为什么用现成IP核而不手写RTLI2S串行音频协议本身不算复杂BCLK、LRCLK、SDATA三根线标准飞利浦时序手写一个发送器和接收器也就一两百行代码。但做音频验证和做IP设计是两码事验证的重点是链路完整性和数据正确性没必要花时间在RTL细节上反复打磨。尤其在时间紧迫的项目里直接用Vivado自带的AXI I2S Receiver和AXI I2S Transmitter IP核能省掉大量调试成本。另一个原因是接口整合成本。Xilinx平台上的音频IP核默认挂AXI4-Lite和AXI4-Stream总线这意味着MCU侧可以用标准寄存器读写来控制数据侧可以无缝接DMA或者FIFO后续不管是做单次采样还是连续音频流扩展都很方便。如果手写RTL最后还得自己封装AXI接口工作量翻倍。综合来看用IP核做音频验证是性价比最高的选择尤其适合验证音频Codec芯片、测试音频算法处理通路、或者给软核处理器加一个音频外设这类场景。1.2 回环验证的思路RX进、TX出、中间观察我的验证思路是搭一个回环链路外部音频源产生I2S信号FPGA通过Receiver IP核把串行数据变成并行音频流再经过一块缓冲逻辑直接喂给Transmitter IP核最终由TX引脚输出。这个回环链路可以完整覆盖三件事一是验证RX IP是否能正确恢复BCLK、LRCLK和数据位二是验证RX到TX的数据通路是否畅通AXI4-Stream握手是否正常三是验证TX IP是否能按目标Codec的时序把数据送出。在中间加一个观察点很关键。我没有让数据只从RX直接捅到TX而是在AXI4-Stream通路上挂了ILA实时抓取握手信号和音频采样值。这样一旦回环后听到爆音、左右声道交换或者数据整体错位能直接定位是接收端的问题还是发送端的问题。实际调试下来大部分问题都出在协议细节上ILA帮了大忙。2. Vivado中IP核配置与关键信号2.1 AXI I2S Receiver / Transmitter IP核使用前提与整体框图在Vivado中打开IP Catalog搜索I2S能看到AXI I2S Receiver和AXI I2S Transmitter两个独立IP核前者负责把外部串行音频信号转成AXI4-Stream后者把AXI4-Stream音频数据转成外部串行I2S信号。两个IP都是通过AXI4-Lite接口做寄存器配置支持使能控制、FIFO状态查询、中断上报等操作。使用前要确认几个前提。第一是Vivado版本和IP License多数版本下这两个IP可以免费使用但个别版本或器件系列可能需要额外License创建IP前先确认IP核状态是Available而不是锁定的。第二是器件选型我在Artix-7和Zynq-7000系列上都跑过资源占用很小Receiver和Transmitter加起来也就几百个LUT基本不影响其他逻辑。第三是总线接口如果做纯逻辑验证不接MicroBlaze或Zynq ARM核也没关系可以用AXI Verification IP或自己写一个简单的AXI Lite主设备来控制寄存器。整体结构上RX IP对外是三根I2S引脚输入对内是一条AXI4-Stream输出总线数据格式一般是左右声道交织bus宽度默认32位内部FIFO深度可以配置。TX IP的接口正好相反AXI4-Stream输入I2S引脚输出。中间无论接FIFO、接DMA还是直接对接都要保证AXI4-Stream握手的TREADY和TVALID信号处理正确否则数据流一旦打满就会丢数。2.2 关键配置参数与选型建议配置IP时有几个参数直接影响验证成败我逐个说下实测感受。第一个是Data Width。通常选32位虽然很多Codec只用到16位或24位但AXI4-Stream总线是32位选32位可以减少后续数据处理时的位宽转换麻烦。需要留意的是不同IP核在32位总线里存放样本的方式不完全一样有的左对齐有的右对齐拿到IP后先看一下数据手册或者用ILA抓一个已知正弦波确定位序不然很容易出现数据看起来有规律但完全不对的情况。第二个是FIFO Depth。RX和TX内部都会有FIFO默认深度可能只有16或者64如果中间不用DMA而是直接把RX和TX对接FIFO深度太小很容易溢出。我建议条件允许就配置到256甚至更大资源消耗很小但能有效降低瞬时背压导致丢数的概率。尤其在LRCLK是44.1kHz这种采样率下一帧数据间隔比较长FIFO深度大一点对调试更友好。第三个是时钟配置。有些AXI I2S IP核在主模式Master下要求输入一个MCLK然后IP内部根据寄存器配置分频产生BCLK和LRCLK。从模式Slave下则由外部提供BCLK和LRCLKIP只负责在正确边沿采样和发送数据。验证时建议先固定用外部信号源做主模式因为这样BCLK和LRCLK的相位关系可控排查问题更容易。具体支持哪种模式还是要以你拿到的IP核配置界面为准不要想当然。2.3 外部接口与时序协议细节I2S协议里最需要注意的是三根线的相位关系。标准I2S规定数据在BCLK下降沿发生变化接收端在BCLK上升沿采样LRCLK表示声道标准模式下LRCLK为低电平时是左声道高电平时是右声道并且数据位比LRCLK边沿延迟一个BCLK周期。正因为有这个延迟一个周期的细节很多第一次调I2S的人会在数据对齐上踩坑。另外很多音频Codec对MCLK有需求。I2S协议本身不需要MCLK但Sigma-Delta结构的ADC/DAC普遍需要MCLK提供内部时钟频率通常是LRCLK的256倍或512倍也就是11.2896MHz或12.288MHz这类非整数频率。我遇到过一位同事直接把BCLK当MCLK接给Codec结果输出全是噪声。做板级验证时要确认外部DAC/ADC是否需要MCLK如果Codec必须独立MCLK才能工作别忘了把它从FPGA或晶振引过去。还有一个容易忽略的细节是左右声道定义。不同Codec和不同IP对LRCLK极性要求可能有差异有的认为低电平是左声道有的认为高电平是左声道配置之前多看芯片手册。调试时可以先用一个只带左声道或者只带右声道的特殊测试音频比如单声道1kHz正弦波通过左右声道输出电平差异快速判断是否接反。3. 搭建完整验证链路从Block Design到板级调试3.1 创建BD与硬件连接我习惯用Vivado Block Design方式来做这个验证原因是连线直观而且MicroBlaze、AXI Interconnect、ILA这些模块都可以图形化添加。具体步骤是新建Block Design添加AXI I2S Receiver、AXI I2S Transmitter、Clocking Wizard、MicroBlaze或者AXI Verification IP、AXI Interconnect把Bus接口连好。连接时要注意三块。第一AXI4-Lite总线通常从一个MicroBlaze或者外部主设备出来经过AXI Interconnect分给RX和TX两个IP每个IP占一个独立地址段地址不要重叠。第二RX的AXI4-Stream输出和TX的AXI4-Stream输入我在前期直接短接了但中间加了一个简单的AXI4-Stream Register Slice来切断组合逻辑路径这样时序收敛更稳同时也能起到一点FIFO缓冲作用。第三时钟域要理清楚AXI总线时钟用100MHz或150MHz都可以I2S接口上的BCLK和LRCLK是独立时钟IP内部会做跨时钟域处理只要FIFO深度够一般不会出问题。硬件引脚分配上RX的SDATA_IN、BCLK、LRCLK按开发板原理图约束到对应引脚TX的SDATA_OUT也单独约束。要注意的是很多开发板的音频Codec输入输出引脚是固定接好的不一定能引出单独的I2S引脚。如果板子不带音频接口我建议用PMOD之类的扩展口自己飞线或者直接买一个支持I2S输入的DAC模块把SDATA、BCLK、LRCLK、GND四根线接上几块钱就能解决。3.2 软件控制流程寄存器读写示例BD搭好之后导出硬件到Vivado再导出到SDK/Vitis就可以写C代码控制IP了。控制流程不复杂一般是复位、配置分频、使能接收和发送、查询FIFO状态、读取中断标志。我写了一个最简单的寄存器读写示例思路是不用现成驱动直接通过物理地址读写的Xil_In32和Xil_Out32这样流程最透明也方便对接不同版本IP。#include xil_io.h #define I2S_RX_BASEADDR 0x44A00000 #define I2S_TX_BASEADDR 0x44A20000 /* 寄存器偏移按实际IP手册调整 */ #define I2S_REG_CTRL 0x00 #define I2S_REG_CLKDIV 0x04 #define I2S_REG_INTSTA 0x08 void i2s_init(void) { /* 先关闭两个IP保持复位状态 */ Xil_Out32(I2S_RX_BASEADDR I2S_REG_CTRL, 0x0); Xil_Out32(I2S_TX_BASEADDR I2S_REG_CTRL, 0x0); /* 配置时钟分频例如MCLK 12.288MHz目标BCLK 3.072MHz */ /* 具体分频系数需要根据IP内部逻辑计算 */ Xil_Out32(I2S_RX_BASEADDR I2S_REG_CLKDIV, 4); Xil_Out32(I2S_TX_BASEADDR I2S_REG_CLKDIV, 4); /* 使能接收和发送 */ Xil_Out32(I2S_RX_BASEADDR I2S_REG_CTRL, 0x1); Xil_Out32(I2S_TX_BASEADDR I2S_REG_CTRL, 0x1); } int main(void) { i2s_init(); while(1) { /* 调试时留空或者在这里查询FIFO状态、计数 */ } return 0; }这段代码没有处理中断而是纯轮询验证阶段完全够用。需要注意不同版本的AXI I2S IP寄存器偏移和位定义有差异上板前一定先对照IP的用户手册核对一遍。我的经验是很多问题不是I2S协议本身出错而是软件把寄存器地址写错导致IP根本没进入工作状态。3.3 回环通路与数据缓冲的选择把RX的AXI4-Stream直接连到TX的AXI4-Stream看起来最简单实际用起来会有隐患。AXI4-Stream是握手机制下游不准备好上游就要停住等TREADY而RX IP的I2S接口可不会因为下游停住就不接收外部数据如果内部FIFO满了新的采样数据就只能丢弃。这就导致回环链路上出现周期性丢数据反映在听感上是哒哒的爆音。所以中间加一个缓冲是非常必要的可以考虑三种方案。第一种是加AXI4-Stream Data FIFO把RX的数据先进FIFOTX再从FIFO读这个方案改动小适合纯回环。第二种是用AXI DMA把RX数据搬进DDR再让TX DMA从DDR读出去这个方案适合同时做录音和播放比如做音频处理算法的输入输出缓存。第三种是在MCU里做中转RX每产生一个中断就读取数据再写回TX这个方案最简单但实时性最差只能验证通路不适合连续音频流。我这次验证选择了第一种方案在BD里拖了一个AXI4-Stream Data FIFO插在RX和TX中间。实测下来FIFO深度设置256、数据位宽32位时回环播放16bit、44.1kHz音频非常稳定。ILA上观察到TREADY基本一直是高只有在极短暂的时候会拉低说明FIFO确实起到了吸收瞬时突发的作用。3.4 用ILA和示波器做板级确认板级调试阶段ILA和示波器要配合使用。ILA用来抓内部并行数据和握手信号示波器用来看外部I2S波形质量。我的习惯是先抓ILA再看示波器。在BD里给RX和TX的AXI4-Stream接口各挂一个ILA把TVALID、TREADY、TDATA抓出来同时把BCLK、LRCLK、SDATA_IN、SDATA_OUT这些引脚信号也引到ILA里观察。触发条件就设置为TVALID从低到高这样能抓到完整的一帧音频数据。然后对照LRCLK的电平看低电平时TDATA是否对应左声道采样值高电平时是否对应右声道这样能快速确认左右声道和位序是否正确。示波器部分主要看三根线的时序关系。用示波器测量BCLK和LRCLK的相位确认数据在BCLK上升沿被正确采样同时看SDATA的电平是否在BCLK下降沿附近变化是否符合标准I2S。如果示波器带宽不够只看出大致波形形状也可以真正精确的数据校验还是靠ILA抓出来的采样值更可靠。不过示波器有一个不可替代的作用就是检查信号完整性和噪声特别是SDATA线上的毛刺有时候会导致偶发采样错误。4. 调试中踩过的坑问题现象与排查方法4.1 典型问题速查表把这次调试过程遇到的问题整理成了一张速查表后续再碰到类似现象可以直接对照排查能省不少时间。问题现象可能原因排查方向RX接收数据一直为0LRCLK极性反了或SDATA引脚约束错误用ILA抓引脚信号测量SDATA是否有有效数据TX输出无声音TX IP使能未打开或MCLK没给到位检查寄存器配置示波器看BCLK是否正常产生有声音但爆音严重FIFO溢出或时钟不连续加大FIFO深度检查MCLK/BCLK分频配置左右声道互换LRCLK极性配置与对端Codec相反判断标准I2S高低电平定义修改极性配置音调偏高或偏低LRCLK频率不对或采样率配置错误用频率计测LRCLK频率核对分频系数数据全是0xFF或0x00样本位序或Word Length处理错误用已知正弦波抓ILA判断32位总线上的位对齐这个表是纯经验总结不同IP版本细节可能不同但排查思路是通用的。4.2 时钟相关的坑MCLK、BCLK、LRCLK和FFT IP时钟时钟是I2S验证里最折磨人的部分我前后栽了两个跟头。第一个跟头出在MCLK和BCLK的关系上。我最初用Clocking Wizard生成一个12.288MHz的MCLK然后让TX IP在Master模式下自动分频产生BCLK和LRCLK。当时为了省事直接按3.072MHz BCLK计算分频系数忽略了IP内部分频器是否整除。结果就是LRCLK变成了一个奇怪的频率回环后声音明显变调。后来用示波器一测才发现IP内部分频逻辑和我想的不一样。这个经验是确定目标采样率和BCLK之前先搞清IP内部时钟树再用频率计或ILA实测确认。第二个跟头是做FFT频谱分析时把采样时钟搞混了。I2S的采样率对应的是LRCLK频率而Vivado里FFT IP核的aclk只是IP的工作时钟两者不是一个概念。FFT IP核内部通常会有一个配置接口来告诉它数据的采样率如果你直接把FPGA工作时钟当成采样率去配置频率轴算出来的频谱位置全是错的。很多人抱怨FFT IP核无法设置小数时钟输入其实就是没分清IP工作时钟和信号采样时钟。在音频验证里真正决定频谱横轴位置的是LRCLK不是BCLK更不是AXI总线时钟。4.3 数据对齐问题左右声道、字长与位序I2S调试中数据对齐问题往往隐蔽且难以定位。我遇到的情况是回环后声音能通但左右声道串音严重。最开始怀疑是模拟电路串扰测了半天模拟端没问题最后用ILA抓数据才发现RX输出到TX输入的时候数据位序整体错了一位导致左右声道的数据混在一起。实际上I2S标准规定数据在LRCLK边沿之后延迟一个BCLK周期才有效就是为了给发送端留出切换时间。如果RX IP在处理这个延迟时和TX IP的发送判断不一致就会出现一位偏移。排查方法很简单给音频源播放一个左声道1kHz、右声道静音的测试文件然后在ILA里观察TDATA的值正常情况下应该是左声道采样值接近正弦波、右声道采样值接近0。如果看到的是左声道和右声道各有一半正弦波基本就是位偏移或对齐问题。字长问题也常见。我在用24位Codec时RX IP配置成32位总线后样本存在高24位还是低24位每个IP不一样。第一次调的时候我直接用32位数据原样回环结果放出来的声音音量很小且失真。后来查手册发现Codec要求24位数据左对齐放在高24位而IP输出默认是低24位对齐需要自己做一个左移8位的处理。遇到这种情况别急着改IP配置先用ILA抓数据格式确认对齐方式后再决定是软件移位还是加组合逻辑移位。4.4 调试环境问题Cable驱动与JTAG连接说一个和I2S无关但差点卡住整个验证的环境问题Xilinx Platform Cable USB在Windows上经常出现无法加载这个硬件的设备驱动的提示导致Vivado识别不到下载器。这个问题不是I2S本身但板级调试一卡住整个项目就停摆。我通常的解决方法是先拔掉Cable卸载设备管理里带感叹号的设备然后重新安装Vivado安装目录下的电缆驱动。具体路径一般在Vivado安装目录的data\xicom\cable_drivers\nt64下面手动选择该目录让Windows重新安装驱动。如果还不行检查USB线是否插在USB 2.0口有些旧型号的Platform Cable对USB 3.0口兼容性不好。最后实在不行就换用板载USB-JTAG方案现在很多开发板自带FTDI或Digilent USB-JTAG比老式Platform Cable省心很多。这类环境问题虽然不涉及协议原理但在实际项目里会浪费大量时间提前准备好驱动备份文件是一个很实用的习惯。5. 实测结果、判定标准与后续扩展5.1 怎样才算音频链路验证通过音频链路验证不能只停留在有声音这个模糊标准上我习惯建立一套明确的判断流程。第一步是通路检查播放1kHz正弦波示波器能在TX输出端看到干净的1kHz正弦波波形说明模拟链路正常。第二步是数字数据检查用ILA抓到的采样值与原始正弦波的理论值比对误差在一个LSB以内说明I2S传输没有丢数据。第三步是左右声道检查播放左右声道不同频率的测试音频比如左声道1kHz、右声道500Hz依次断开左右声道确认没有串音和交换。第四步是长时间稳定性测试连续播放至少30分钟观察FIFO溢出计数和IRQ标志确保不出现偶发丢数。如果做更严格的验证可以用音频分析仪测量THDN但普通开发板环境下的模拟噪声往往比数字链路本身还大测出的THDN更多反映的是开发板电源和DAC的性能不能直接归咎于I2S IP核。因此我建议把重点放在数字数据完整性上模拟指标只能作为参考。5.2 后续扩展到DMA、SPDIF、TDM、PDM的思路这次把RX/TX回环跑通之后后续可以沿着几个方向扩展。最直接的扩展是把FIFO替换成AXI DMA让音频数据直接流进DDR内存这样就能在处理器里做音频算法比如音量控制、EQ滤波、回声消除处理完再通过DMA送给TX IP播放。这也是很多音频嵌入式项目的标准架构。如果要扩展协议类型I2S的基础打牢之后理解SPDIF、TDM和PDM都会很快。SPDIF和I2S最大的区别是SPDIF把数据和时钟编码成单线传输要做双相标记编码TDM则是在一条数据线上时分复用多个声道本质是把I2S的左右声道扩展成更多时隙PDM是单比特流常见于MEMS麦克风需要用抽取滤波器转成PCM。这些协议的采样率、位深、时钟域问题和我前面提到的排查思路一脉相承问题也都集中在数据对齐和时钟关系上。最后再分享一个经验音频验证项目里多准备几个已知特征的测试音频很重要。我常用的是1kHz、500Hz、10kHz正弦波外加一个左右声道交替的语音文件。这些测试音源能帮你快速判断是数字链路问题还是模拟链路问题比在仿真里对着波形猜高效得多。I2S这套验证跑通之后后续再遇到其他音频接口我都会先把整个链路分节点画出来再逐个节点确认波形和数据这个习惯帮我把调试时间压缩了一半以上。
返回列表