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

news2024/11/17 3:33:02

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

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双声道的编码格式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/63657.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

了解3dmax坐标系

3dmax具有多种坐标系,其类别如下;默认的是View坐标系; 新建一个茶壶,此时默认是View坐标系; 切换到屏幕坐标系,看一下如下图;要保持视口区域激活; 根据资料,屏幕坐标系&a…

园区如何快速实现数据可视化分析?

对于园区运营方来说,如果没有专业针对性的管理方案以及管理系统辅助的话,实现园区可视化管理的难度非常大,而且操作成本会很高。但如果园区运营方选择引进快鲸智慧楼宇推出的园区数据孪生可视化管理系统的话就会简单很多。 快鲸智慧楼宇数据孪…

视频学习|Springboot在线学习系统

作者主页:编程千纸鹤 作者简介:Java、前端、Pythone开发多年,做过高程,项目经理,架构师 主要内容:Java项目开发、毕业设计开发、面试技术整理、最新技术分享 收藏点赞不迷路 关注作者有好处 文末获得源码 …

对文本进行情感分析(分类)snownlp模块

【小白从小学Python、C、Java】 【计算机等级考试500强双证书】 【Python-数据分析】 对文本进行情感分析(分类) snownlp模块 选择题 对于以下python代码表述错误的一项是? from snownlp import SnowNLP myText我爱学python! print("【显示】text"…

艾美捷ICT FLICA天冬氨酸蛋白酶(Caspase)活性检测试剂盒说明书

Caspases在细胞凋亡和炎症中发挥重要作用。艾美捷ICT FLICA天冬氨酸蛋白酶(Caspase)活性检测试剂盒被研究人员用于通过培养的细胞和组织中的胱天蛋白酶活性来定量凋亡。用FAM FLICA caspase-1测定试剂盒检测caspase-1活性。该体外试验使用荧光抑制剂探针…

[附源码]计算机毕业设计JAVA音乐网站

[附源码]计算机毕业设计JAVA音乐网站 项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven…

一步登顶还是步步维艰?Java 资深架构师撰下的“阿里 P7 成神之路”

很多刚接触到 Java 开发的程序员都以为 Java 资深开发工程师就已经是 Java 开发的顶了,或者是不清楚架构师是干什么的。 举个例子说吧: 房屋建造。 架构师们根据房屋造型的需求设计出适合的构造,然后再反复测算这个框架搭建的可行性&#…

C++文件操作

文章目录计算机文件到底是什么(通俗易懂)?C文件类(文件流类)及用法详解C open 打开文件(含打开模式一览表)使用 open 函数打开文件使用流类的构造函数打开文件文本打开方式和二进制打开方式的区…

Jetson nano 系统安装

ContentsJetson Nano在 EMMC 上安装镜像U 盘启动和 TF 卡启动U 盘启动 (复制 eMMC 上系统)TF 卡启动设置远程登录系统SDK 安装使用 SDK Manager 安装使用指令安装Linux 操作基础文件传输、系统备份风扇配置IMX219-83 Stereo CameraAI 环境搭建PIP3 安装安装机器学习领域重要的安…

MOSFET 和 IGBT 栅极驱动器电路的基本原理学习笔记(二)栅极驱动参考

栅极驱动参考 1.PWM直接驱动 2.双极Totem-Pole驱动器 3.MOSFET Totem-Pole驱动器 4.速度增强电路 5.dv/dt保护 1.PWM直接驱动 在电源应用中,驱动主开关晶体管栅极的最简单方法是利用 PWM 控制其直接控制栅极,如 图 8 所示。 直接栅极驱动最艰巨的任务…

5‘-二磷酸鸟嘌呤核苷-岩藻糖二钠盐,GDP-Fucose,15839-70-0

中文名 5-二磷酸鸟嘌呤核苷-岩藻糖二钠盐 英文名 Guanosine 5′-diphospho-β-L-fucose sodium salt 英文别名 [(2R,3S,4R,5R)-5-(2-Amino-6-oxo-1,6-dihydro-9H-purin-9-yl)-3,4-dihydroxytetrahydro-2-furanyl]methyl (3S,4R,5S,6S)-3,4,5-trihydroxy-6-methyltetrahydro-2…

Linux Podman安装DVWA靶场环境

一、DVWA靶场环境简介 1.DVWA一个用来进行安全脆弱性鉴定的PHP/MySQL Web应用,旨在为安全专业人员测试自己的专业技能和工具提供合法的环境,帮助web开发者更好的理解web应用安全防范的过程。 ​ 2.DVWA 一共包含了十个攻击模块,分别是&#…

Unity + Mirror实现原创卡牌游戏局域网联机

资源下载地址 局域网联机插件 Mirror:Mirror | 网络 | Unity Asset Store 本地客户端测试多人游戏(不用打包)插件 : ParrelSync Mirror官方文档:General - Mirror (gitbook.io) Mirror使用 前置准备 导入Mirror …

UNet 网络做图像分割DRIVE数据集

目录 1. 介绍 2. 搭建 UNet 网络 3. dataset 数据加载 4. train 训练网络 5. predict 分割图像 6. show 7. 完整代码 1. 介绍 项目的目录如下所示 DRIVE 存放的是数据集predict 是待分割的图像result 里面放分割predict 的结果dataset 是处理数据的文件、model存放une…

day5_redis学习

文章目录秒杀优化阻塞队列实现消息队列Redis实现消息队列List实现消息队列PubSub实现消息队列Stream实现消息队列发布以及查看探店笔记点赞以及点赞排行榜秒杀优化 上面的过程中,我们进行秒杀操作的基本步骤为: 所以这时候整个过程就耗费较长的时间,因…

【1687. 从仓库到码头运输箱子】

来源:力扣(LeetCode) 描述: 你有一辆货运卡车,你需要用这一辆车把一些箱子从仓库运送到码头。这辆卡车每次运输有 箱子数目的限制 和 总重量的限制 。 给你一个箱子数组 boxes 和三个整数 portsCount, maxBoxes 和 m…

python大数据毕业设计选题题目大全

文章目录0 前言1 大数据相关题目2 开题指导2.1 起因2.2 如何避坑(重中之重)2.3 为什么这么说呢?2.4 难度把控2.5 题目名称3 最后0 前言 这是学长亲手整理的,大数据毕设选题系列第二篇,都是经过学长精心审核的题目,适合作为毕设&a…

CPP 核心编程6-多态

#include "iostream" using namespace std;//多态 class Animal { public:void speak(){cout << "动物在说话" << endl;} };class Cat : public Animal { public:void speak(){cout << "cat在说话" << endl;} };//地址早…

【C语言航路】第七站:结构体初阶

目录 一、结构体的声明 1.结构的基础知识 2.结构的声明 3.结构体成员的类型 4.结构体变量的定义和初始化 二、结构体成员的访问 三、结构体传参 总结 一、结构体的声明 1.结构的基础知识 结构是一些值的集合&#xff0c;这些值称为成员变量&#xff0c;结构的每个成员可…

《少有人走的路:心智成熟的旅程》笔记

几乎人人都有心理问题&#xff0c;只是程度不同而已。 几乎人人都有横渡不同的心里疾病&#xff0c;只是得病的时间不同而已。 ps : 许多人都没有付出足够的时间和精力&#xff0c;去解决知识、社交、心理方面的问题 作者序言&#xff1a; 目录 一、痛苦的价值 二、对待痛苦…