如何从SD卡读取音频文件并将其输出到扬声器上?

2024-01-22

开篇第一步,在上一篇教程中,创建了一个 I2S 发送器用来发送来从FPGA内部 ROM 的音频数据。下一步,我们向该 I2S 发送器添加 AXI-Stream 接口,这样我们就可以将发送器与 ZYNQ 的处理系统连接,还可以从 SD 卡读取音频数据。
为此,创建一个新的top设计。本设计应具有以下接口>
如何从SD卡读取音频文件并将其输出到扬声器上? (https://ic.work/) 音视频电子 第1张
该块设计产生以下代码>
SCLK与MCKL的比率通过RATIO参数定义,每个通道的数据字宽度通过WIDTH参数定义。
PS:此实现仅支持每个通道 16 位数据字(即立体声 32 位)。
‌设计中必须实现以下组件>
用于为 I2S 发送器创建输入时钟的时钟预分频器,AXI-Stream 从接口,I2S发送器的控制逻辑‌,为分频器创建了一个过程,该过程在MCLK时钟上升沿对计数器进行计数,并在半个周期后切换信号SCLK_Int。
下一步是实现 AXI-Stream 接口。为此使用状态机>
复位后,机器从State_Reset状态变为State_WaitForTransmitter等待I2S 发送器发出就绪Ready信号的状态。一旦发送器准备好,TREADY_RXD就会设置 AXI-Stream 接口的信号,通知主机从机已准备好接收数据。然后从机改变为State_WaitForValid状态。
‌在此状态下,从机等待主机置位信号TVALID_RXD标记有效数据。一旦置位了信号,数据就会写入内部 FIFO。然后机器改变到State_WaitForTransmitterBusy状态。
‌现在状态机等待I2S发送器开始发送数据并“删除”就绪信号。一旦完成,状态机就会切换回State_WaitForTransmitterReady状态并再次等待,直到 I2S 发送器准备就绪。
‌这样,理论上 AXI-Stream 接口就完成了。不幸的是,最后变得有点棘手,因为当前的电路设计使用两个不同的时钟域>
ACLK的时钟域,MCLK的时钟域,一般来说,这两个时钟信号不能从时钟源生成(例如通过时钟分频器),因为 AXI 接口通常以 100 MHz 运行,而音频接口需要可以整齐地分频至采样频率的时钟速率,例如 12.288 MHz。因此,由于最差负裕量 (WNS) 和总负裕量 (TNS) 过多,在实现过程中会出现时序错误>
如何从SD卡读取音频文件并将其输出到扬声器上? (https://ic.work/) 音视频电子 第2张
此外,由于触发器在不同时钟域中发生亚稳态而导致数据不正确的风险非常高。
因此,各个时钟域所使用的信号必须在每种情况下经由相应的电路传送到另一时钟域。Xilinx 在文档UG953(https://www.xilinx.com/support/documentation/sw_manuals/xilinx2018_3/ug953-vivado-7series-libraries.pdf)中描述了可用于此目的的相应宏。
xpm_cdc_gray - 该功能块使用格雷码将数据总线从一个时钟域 (src) 传输到另一个时钟域 (dest)。
xpm_cdc_single - 将单个信号从一个时钟域 (src) 转换到另一个时钟域 (dest)。
宏的示例可以直接用于 VHDL 代码>
最后,必须插入 I2S 发送器并传递生成的信号。
I2S 发送器的 AXI-Stream 接口现已准备就绪并可供使用。完整的代码如下所示>
接下来,我们希望使用该接口从 SD 卡读取波形文件,并使用 CS4344 D/A 转换器通过连接的扬声器输出音乐。
该项目需要以下IP核>
具有 AXI-Stream 接口的 I2S 发送器,处理系统从 SD 卡读取数据并将其写入 FIFO,AXI-Stream FIFO,用于生成音频时钟的PLL,如何从SD卡读取音频文件并将其输出到扬声器上? (https://ic.work/) 音视频电子 第3张
时钟向导生成时钟,然后将其用作 CS4344 的主时钟。输出时钟可以通过 AXI-Lite 接口适应音频文件的采样率。
如何从SD卡读取音频文件并将其输出到扬声器上? (https://ic.work/) 音视频电子 第4张
AXI-Stream FIFO 充当处理系统和 I2S 发送器之间的链接。处理系统通过 AXI-Lite(或 AXI)接口将数据写入 FIFO,然后将数据传输至 I2S 发送器。
如何从SD卡读取音频文件并将其输出到扬声器上? (https://ic.work/) 音视频电子 第5张
根据设计创建比特流,然后可以开发软件。
读取 SD 卡需要 Xilinx 的 xilffs FAT 库,该库必须集成到 Vitis 项目的板级支持包中(不要忘记启用LFN支持大文件名的选项)>
如何从SD卡读取音频文件并将其输出到扬声器上? (https://ic.work/) 音视频电子 第6张
第一步,软件使用该AudioPlayer_Init函数初始化音频播放器,从而初始化 FIFO、GIC 和中断处理程序,以及时钟向导和 SD 卡。
一旦初始化完成,就会调用AudioPlayer_LoadFile函数从 SD 卡加载Audio.wav文件 。
加载音频文件并且调整时钟向导的输出频率后,将从波形文件中读取第一个数据块并将其复制到 FIFO>
程序流程的其余部分在 FIFO 的回调中进行>
一旦 FIFO 触发TFPE中断(发送 FIFO 可编程空),FIFO 就会被来自内部缓冲区的新数据填充。当从处理系统到 FIFO 的传输完成时,会触发TC中断(传输完成),并从 SD 卡读取下一个数据块。之后重复进行上面步骤,直到文件完全播放。
现在需要一个波形文件。简单的测试信号可以wavtones.com上生成(https://www.wavtones.com/functiongenerator.php)。
然后,只需将相应的文件以Audio.wav名称复制到 SD 卡上,即可开始使用。
或者使用立体声音频>
如何从SD卡读取音频文件并将其输出到扬声器上? (https://ic.work/) 音视频电子 第7张

文章推荐

相关推荐