FPGA 20个例程篇:18.SD卡存放音频WAV播放(中)

第七章 实战项目提升,完善简历

18.SD卡存放音频WAV播放(中)

    如图1所示是WM8731中11个寄存器功能说明概况图,我们需要对照手册,再去深入了解WM8731中的11个寄存器,怎么去配置这些寄存器达到预期的效果,起初笔者在刚接触这款芯片时,猛地一看这么多个寄存器,那么为了保险起见,就想着把所有的寄存器都按照顺序配置一遍,实际在这里走了一些弯路并且反复排查耽误了两天时间。

      注意到复位寄存器R15,其相当于之前PHY芯片对MDIO接口的软复位,当我们写入这个复位命令后实际上证明是WM8731就会将所有的控制寄存器都写入0,本来开发板一上电WM8731会自己复位,当然这里是写入默认值的设置,而软复位后等于清零所有寄存器了,就导致前面的操作都白干了。

图1 WM8731中11个寄存器功能说明概况图

        关于这11个寄存器应该如何去配置,因为数据手册上也已经写得非常清楚了,所以在这里笔者不想过多赘述,直接给出这个例程中的WM8731配置说明:

1. 8'h00   Left Line In寄存器配置成0x97,即为默认值

2. 8'h02   Right Line In寄存器配置成0x97,即为默认值

3. 8'h04   Left Headphone out寄存器配置成0x7f,即左耳机输出为+6dB分贝

4. 8'h06   Right Headphone out寄存器配置成0x7f,即右耳机输出为+6dB分贝

5. 8'h08   Analogue audio path control寄存器配置成0x15,即把MIC选择为DAC输出

6. 8'h0a   Digital Audio path control寄存器配置成0x06,即选择了48Khz的采样频率

7. 8'h0c   Power down control寄存器配置成0x00,即为默认值

8. 8'h0e   Digital Audio interface format寄存器配置成0x40,即选择了Right justified模式,主时钟模式,默认的32bit模式

9. 8'h10   Sampling control寄存器配置成0x00,即为默认值

10. 8'h12  Active control寄存器配置成0x01,即为默认值

       介绍完WM8731上关键的设计要点后,回归主题在这个例程,我们去实现SD卡存放音频WAV播放的目的,如图7-12所示是整个例程的设计示意图,和上一个例程可能有些类似的地方也有可以借鉴的地方,在程序设计方面,笔者个人认为有几点需要注意:

1. 通过对WM8731芯片手册的阅读,明白了需要先初始化WM8731芯片,再配置好相关寄存器后才能正常工作,所以需要i2c_wm8731和config_wm8731两个模块进行IIC初始化配置;

2. 对于FPGA端来说需要去按照顺序读出每个扇区512字节的数据,再检查每个扇区是否存在WAV格式的文件头,所以需要wav_query模块去查找并判断当前扇区是不是文件头,如果不是就跳转到下一个扇区继续查找,如果是则提取出WAV格式文件大小用来判断整首音乐是否播放完全,有关WAV文件头会在下面详细展开介绍;

3. 在整个设计中数据的产生是由SD卡而来,数据的消耗则是WM8731数字转模拟后通过耳机音频座子外放出去的,显然这里两个模块存在大量跨时钟域的数据,所以需要两个模块即wav_query查找并用FIFO缓存SD卡中的WAV音频数据,wav_play模块用来按照WM8731的音频格式播放WAV音频数据。

4. 通过对WM8731芯片手册的阅读,了解到了WM8731有不同的工作模式,而在这里使用了Right justified模式,主时钟模式和32bit模式,对应的时序逻辑后续会展开说明。

图2 SD卡存放音频WAV播放整体设计示意图

       如图3所示是SD卡存放音频WAV播放例程的功能框图,朋友们可以对照图7-12和图7-13再去构想下整个程序的设计思路,这里不妨去想想看数据来源、数据流向、数据缓存以及各个模块之间应该怎么去关联起来。

图3 SD卡存放音频WAV播放功能框图

       在阅读了WM8731芯片数据手册和梳理了例程的整体设计框图后,在模块设计之前,简单穿插介绍下WAV的文件头格式,结合WM8731配置,这里有些需要注意的地方,实话实说,笔者在最初设计这个例程时候也走错路,踩过坑,一点点摸索边调边试,最终才把一些细节琢磨清楚,在这里分享给大家。

        如图4所示是WAV文件头格式,起初在程序设计当中笔者只关心到了两点即如何判断文件报头和如何提取文件长度,仔细观察不难发现文件头前12个字节包含了核心信息,因为WAV文件是基于RIFF格式标准的,所以文件报头的第一个4字节是“RIFF”,第二个4字节是整个文件大小这里以字节为单位,第三个4字节则是“WAVE”。

图4 WAV文件头格式

       实际上对于wav_query模块的程序设计了解到这里就够了,在这个模块里我们只需要实现核心的4个功能:

      1. 遍历地查找并判断当前扇区是不是WAV文件头(WAV文件头的第一个4字节是“RIFF”和第三个4字节是“WAVE”),如果不是就跳转到下一个扇区继续查找,如果是则提取出WAV格式文件大小(WAV文件头的第二个4字节)用来判断整首音乐是否播放完全;

      2. 缓存从SD卡扇区中读到的WAV格式数据,合理地把上游SD卡中存储的音频数据送到下游WM8731的DACDAT引脚,下游的wav_play模块再通过芯片内部的数模转换把音乐外放到音频耳机座子上。这也是整个模块设计中最为关键的部分,因为读SD扇区音频数据的速度要快于WM8731数模转换播放的速度,简而言之数据的产生速度要大于数据的处理速度,所以我们用FIFO中的写入数据量作为标志,使用一个读写端口均是1024的FIFO作为缓存,当写入端口侧的数据量少于512个就继续读取下个扇区512字节数据,这样就非常合理地解决了数据产生和数据处理速度上不一致的问题;

      3. 计数每首WAV歌曲的音频数据量,这里注意到WAV文件头大小固定是88字节,所以在播放时需要把前88个字节的文件头去掉;

      4. 把从上游模块中SD卡扇区中读到的1字节8比特数据拼接成4字节32比特数据写入FIFO中,下游模块再从FIFO中读取数据,当然具体的原因会在wav_play模块中再进行详细讲解。

      如下表1所示是wav_query模块的信号列表,如图7-15所示是WAV音频查找模块的代码设计,和上个例程BMP图片查找模块的设计思想大同小异,但是在这个模块中需要注意下状态机的跳转,根据实际需求把模块划分为5个状态即WAV_IDLE、WAV_QUERY、WAV_CHECK_FIFO、WAV_READ_SEC、WAV_END,这里单独分开了一个WAV_CHECK_FIFO状态用来判断FIFO中写端口的写入数据量是否小于512,如果小于512跳到WAV_READ_SEC状态继续读取SD卡下个扇区的512字节数据,如果大于512则等待下游wav_play模块把FIFO中缓存的音频数据消耗了再去读取下个扇区。

信号列表

信号名

I/O

位宽

clk

I

1

rst_n

I

1

sd_rd_done

I

1

wav_en

I

32

wav_playrdy

I

32

sd_rd_dout

I

16

sd_rd_dout_vld

I

16

wav_data

O

48

wav_data_vld

O

48

sdcard_en

O

16

sec_rd_addr                 

O

32

led_wav

O

8

表1 wav_query模块信号列表

 图5 WAV音频查找模块的代码设计

       对于wav_play即WAV音频播放模块的设计,实际上笔者在这里也花费了很多精力和时间,不断调试磨合,最终才发现自己对WM8731手册或者说对WAV文件头的研究还不够细致。

       刚开始因为笔者对左声道和右声道这个概念没有太多理解,所以对照WM8731手册看得也是似懂非懂,更不知道怎么把SD卡中读到的WAV格式音频数据映射到左右声道,后来上板调试均失败后,静下心来把WM8731手册和WAV编码格式又反反复复地研究了几遍,最后才慢慢想明白了整个原理,下面就为大家逐一道来。

        为了更加直观地理解,如下图6所示是WinHex下查看Counting Stars的WAV格式二级制文件,这里方便大家查看,笔者也用红色方框把重要的内容都框了出来。

图6 WinHex下查看Counting Stars的WAV格式二级制文件

“52 49 46 46”即ASCII字符“RIFF”,固定格式表明这是一个WAV的文件头。

“58 7B B4 02”即WAV文件的所有数据大小,16进制的“58 7B B4 02”对应是十进制的45382488,这里注意到读取的方式应是低位在前高位在后,也就是“02 B4 7B 58”所对应的十进制数值。

“57 41 56 45”即ASCII字符“WAVE”,也是固定格式表明这是一个WAV的文件头。

“66 6D 74 20”即表示标识符“fmt”。

“10 00 00 00”即对应数字“16”,表示后面有一段的数据长度是16个字节,即偏移量从14H~23H。

“01 00” 即对应数字“1”,表示该数据以PCM方式进行编码。

“02 00” 即对应数字“2”,表示该文件是双声道文件。

“44 AC 00 00” 即对应数字“44100”,表示采样频率为44100Hz,表示每个通道的播放速度。

“10 B1 02 00” 即对应数字“176400”,表示波形音频数据传输速率为176400(2*44100*16/8)。

“04 00” 即对应数字“4”,表示块对其单位,表明WAV文件一次需要处理多个4字节大小的数据(2*16/8)。

“10 00” 即对应数字“16”,表示采样大小为16Bits,是每样本的数据位数。高八位表示左声道,低八位表示右声道。

         通过上面对WAV文件头进一步的深入分析,大家可以清楚地看到这首WAV格式的Counting Stars歌曲实际上是16 Bit双声道的,即对应表2的编码格式。

采样1

左声道数据1低字节

左声道数据1高字节

右声道数据1低字节

右声道数据1高字节

采样2

左声道数据2低字节

左声道数据2低字节

右声道数据2低字节

右声道数据2高字节

表2 WAV下16 Bit双声道的编码格式

FPGA 读写SD卡音乐播放例程Verilog逻辑源码Quartus工程文件+文档说明,,FPGA型号Cyclone4E系列的EP4CE6F17C8,Quartus版本17.1。 实验简介 在其他实验我们已经完成了 SD 卡读写和音频模块的录音播放,本实验通过搜索 SD 卡 WAV 音乐文件,然后送到音频模块播放,完成一个简单音乐播放器的功能。 2 实验原理 本实验一个关键是在没有文件系统的情况下,搜索 SD 卡每个扇区的内容,匹配出 WAV 文件, 这里有一个假设:假设每一个文件都是从一个扇区第一个字节开始而且文件是连续存储的,经过 大量实验,发现 FAT32 文件格式的文件确实如此。 2.1 WAV 文件格式 大部分的文件都有文件头,WAV 也丌例外,我们通过分析 SD 卡一个扇区的前几个字节,判 断这个文件是否为 WAV 文件。 WAV 文件作为多媒体使用的声波文件格式之一,它是以 RIFF 格式为标准的。RIFF 是英文 Resource Interchange File Format 的缩写,每个 WAV 文件的头四个字节便是“RIFF”,所以本实验 就简单的以每个扇区的前 4 个字节是否为“RIFF”判断该文件是否为 WAV 文件,紧接着 4 个字节 表示文件的大小,这样我们就可以确定要读取的数据量。WAV 文件头大小是 88 字节,在播放时 要把前 88 个字节的文件头去掉。 module top( input clk, input rst_n, input key1, input wm8731_bclk, //audio bit clock input wm8731_daclrc, //DAC sample rate left right clock output wm8731_dacdat, //DAC audio data output input wm8731_adclrc, //ADC sample rate left right clock input wm8731_adcdat, //ADC audio data input inout wm8731_scl, //I2C clock inout wm8731_sda, //I2C data output sd_ncs, //SD card chip select (SPI mode) output sd_dclk, //SD card clock output sd_mosi, //SD card controller data output input sd_miso, //SD card controller data input output [5:0] seg_sel, output [7:0] seg_data ); wire[9:0] lut_index; wire[31:0] lut_data; wire[3:0] state_code; wire[6:0] seg_data_0; //I2C master controller i2c_config i2c_config_m0( .rst (~rst_n ), .clk (clk ),
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值