stm32 VM8978 音乐播放

news2024/11/28 12:39:37

一、WAV文件

1、WAV文件简介

2、WAV文件的解析

二、WM8978

1、WM8978介绍

2、WM8978特点

3、WM8978接口

4、WM8978框架

5、 WM8978 寄存器

三、IIS详解

1、IIS介绍

2、 IIS 的特点

3、IIS框架

4、 音频协议

5、 IIS Philips 标准

6、 IIS 时钟

四、音乐播放硬件设计 

五、音乐播放软件设计

 1、软件设计思路

2、部分程序编程以及分析

wm8978.c文件中,WM8978芯片初始化

WM8978IIS 写寄存器功能

WM8978开启DAC功能

WM8978IIS模式

WM8978设置耳机音量功能


一、WAV文件

1、WAV文件简介

WAV 为微软公司(Microsoft)开发的一种声音文件格式,它符合 RIFF(Resource Interchange File Format)文件规范,用于保存 Windows 平台的音频信息资源,被 Windows 平台及其应用程序所广泛支持,该格式也支持 MSADPCM,CCITT A LAW 等多种压缩运算法,支持多种音频数字,取样频率和声道,标准格式化的 WAV 文件和 CD 格式一样,也是 44.1K 的取样频率,16 位量化数字,因此在声音文件质量和 CD 相差无几!通常使用三个参数来表示声音,量化位数,取样频率和采样点振幅。量化位数分为 8 位,16 位,24 位三种,声道有单声道和立体声之分。
取样频率一般有 11025Hz(11.025kHz) ,22050Hz(22.05kHz)和 44100Hz(44.1kHz) 三种。

2、WAV文件的解析

WAV 文件是由若干个 Chunk 组成的。按照在文件中的出现位置包括: RIFF WAVE Chunk、Format Chunk、 FactChunk(可选)、LIST 块(可选)和 Data Chunk。 每个 Chunk 由块标识符、数据大小和数据三部分组成。其中块标识符由 4 个 ASCII 码构成, 数据大小则标出紧跟其后的数据的长度( 单位为字节) , 注意这个长度不包含块标识符和数据大小的长度, 即不包含最前面的 8 个字节。 所以实际 Chunk 的大小为数据大小加 8。WAV 文件格式如下表 :

HHH

偏移地址字节数类型内容
00H-03H4字符资源交换文件标志(RIFF),16进制52 49 46 46=”RIFF“的ASCII
04H-07H4长整型除去档头的8个字节后,wav文件总长度(字节)
08H-0BH4字符wav文件标志,16进制57 41 56 56 = ”wave"的ASCII码
0CH-0FH4字符波形格式标志(FMT ),16进制66 6D 74 20="fmt”的 ASCII码
10H-3H4整数描述fmt chunk 的大小,该chunk去除ID和size所占的字节数后剩下的其他字节数目,OxO0000010表示后面的16字节用于描述fmt chunk,不同的格式数值可能不一样
14H-15H2整数格式种类(值为1时,表示数据为线性PCM编码,其他格式将是其他数值)
16H-17H2整数通道数,单声道为1,双声音为2
18H-1BH4长整数采样频率,描述每秒有多少个采样点
1CH-1FH4长整数波形数据传输速率(每秒平均字节数), wav每秒字节数=采样率*bit_解析度通道数/8,
20H-21H2整数数据的调整数(按字节计算) , wav每个数据块字节数,pcm格式,一个采样点就是一个块
22H-23H2整数样本数据位数,一般取值是8/16/32
 
24H-27H4字符数据标志符( data ) ,16进制646174 61= "data"的ASCI码
28H-2BH4长整数采样数据总数,描述data chunk 的大小,该chunk去除ID和size所占的字节数后剩下的其他字节数目,此信息后的所有字节都是音频数据
2CH-...从此位置开始到文件结束,全部用来记录音颍信息

由表可知,WAV文件组成

  • RIFF 块(RIFF WAVE Chunk)

 该块以“ RIFF” 作为标示,紧跟 WAV 文件大小,该大小是 WAV
文件的总大小减去 8,然后数据段为“ WAVE” ,表示是 WAC 文件。RIFF 块的 Chunk 结构代码可写成如下
所示:

//RIFF块
//添加_packed关键字表示结构体成员间紧密排列packed typedef struct
{
u32 RiffID;
//RiffID:里面定为"RIFF",即0X46464952
  u32 ChunkSize ;
//集合大小;文件总大小减去8
u32 WaveID;
//格式;WAVE,即0X45564157
}RIFFChunk ;
  • Format 块( Format Chunk)

 该块以“ fmt ”作为标示(注意有个空格),一般情况下,该段的大小为 16 个字节(不包括 ID 和 Size),但是有些软件生成的 WAV 格式,该部分可能有 18 个字节,含有 2 个字节的附加信息。 Format 块结构代码可写成如下所示:

_packed typedef struct
{
  u32 FmtID ;
  //FmtID ;这里固定为"fmt ",即0X20746D66
  u32 ChunkSize ;
  //数值为16或18,18则最后又附加信息
  u16 AudioFormat;
  //音频格式;0X01,表示线性PCM:0X11表示IMA ADPCM
  u16 NumOfChannels;
  //通道数量;1,表示单声道;2,表示双声道;
  u32 SampleRate;
  //采样率:0X1F40,表示8Khz
  u32 ByteRate;
  //每秒所需字节数
  u16 BlockAlign;
  //数据块对齐单位(每个采样需要的字节数)
  u16 BitsPerSample,
  //每个采样需要的bit 数
  //u16 ByteExtraData;
  //附加信息(可选,通过Size来判断有无)
}FMTChunk;
  • Fact块( Fack Chunk)

该块为可选块,以“ fact”作为标示,不是每个 WAV 文件都有, 在非 PCM 格式的文件中, 一般会在 Format结构后面加入一个 Fact 块,Fact 块结构代码可写成如下所示: 

__packed typedef struct
{
u32 FACTID; //FACTID;这里固定为"fact",即 0X74636166;
u32 FACTSize ; //子集合大小(不包括 ID 和 Size);这里为:4.
u32 NumOfSamples; //采样的数量;
}FACTChunk;

  • Data块 (Data Chunk)

该块是真正保存 wav 数据的地方,以“ data”'作为该 Chunk 的标示, 然后是数据的大小。Data 块结构代码,可写成如下所示:

__packed typedef struct
{
u32 DATAID; //DATAID;这里固定为"data",即 0X5453494C
u32 DATASize ; //子集合大小(不包括 ID 和 Size)

}DATAChunk;

DATAChunk 数据块中 DATASize 之后就是音乐文件数据部分了。我们可以根据 ChunkFMT 块中的声道数和位数,可以分为如下几种形式,如下表:

 如果是 16 位或 24 位,每个取样为 4 或 6 个字节,低字节在前,高字节在后。在得到这些 WAV 数据之后,通过I2S 送给 WM8978,就可以播放音乐了。我们可以用 stc-isp-15xx-v6.85.exe 软件打开一个 WAV 文件,打开后如图所示:

 

wav文件内容

 如图可得:

1.“52 49 46 46”,这个是 ASCII 字符“RIFF”,这部分是固定格式,表明这是一个 RIFF 文件头。
2.“AE 6D A4 00” ,这个是 WAV 文件的数据大小, 这个大小包括除了前面 4 个字节的所有字节, 也就等于文件总字节数减去 8。 由于 STM32 为小端模式,所以转换为 16 进制为0xA46DAE,对应是十进制的“10775982”,即为文件的大小。

3.“57 41 56 45 66 6D 74 20”,也是 ASCII 字符“ WAVEfmt”,这部分是固定格式。
4.“10 00 00 00” , 16 进制为 0x10, 对应十进制数为 16, 这个对应定义中的 ChunkSize 部分的大小,
可以看到后面的这个段内容正好是 16 个字节。 一般情况下大小为 16, 此时最后附加信息没有,如果为 18,
则上面这个文件多了两个字节的附加信息。
5.“01 00” , 16 进制为 0x01, 对应十进制数为 1, 这个对应定义中的 AudioFormat,如果为 1 说明音
频格式为 PCM,如果为其他,说明是其他格式。
6.“02 00” , 16 进制为 0x02, 对应十进制数为 2, 这个对应定义中的 NumOfChannels,如果 1 说明
是单声道,如果为 2,说明是双声道。
7.“11 2B 00 00”,16 进制为 0x2B11,对应十进制数为 11025,代表的是采样频率 11025,采样率(每秒样
本数),表示每个通道的播放速度。
8.“44 AC 00 00”,16 进制为 0xAC44,对应十进制数为 44100,代表的是每秒的数据量,波形音频数据传
送速率,其值为通道数×每秒样本数×每样本的数据位数/8(1*22050*16/8)。播放软件利用此值可以估计缓冲
区的大小。
9.“04 00”,16 进制为 0x04,对应十进制数为 4, 表示块对齐的内容。 数据块的调整数( 按字节算的),
其值为通道数×每样本的数据位值/8。 播放软件需要一次处理多个该值大小的字节数据, 以便将其值用于缓
冲区的调整。
10.“10 00”, 16 进制为 0x10,对应十进制数为 16,即采样大小为 16Bits,每样本的数据位数,表示每
个声道中各个样本的数据位数。如果有多个声道,对每个声道而言,样本大小都一样。
11.“4C 49 53 54”,这个是 ASCII 字符“LIST”,这部分是固定格式,表明这是 LIST 文件部分。
12.“64 61 74 61”,这个是 ASCII 字符“DATA”,表示文件头结束,开始数据区域。
13.“00 6D A4 00” 十六进制数是“0xA46D00” ,对应十进制 10775808, 是数据区的开头,之后是数据
总数,看一下前面正好可以看到,文件大小是 10775982, 从(2) 到(12) 包括(12)正好是 10775982-
10775808=174 字节。
14.之后就是真正的 Wave 文件的数据

二、WM8978

1、WM8978介绍

  WM8978 是一个低功耗、高质量的立体声多媒体数字信号编译码器。它主要应用于便携式应用,比如数码照相机、可携式数码摄像机。它结合了立体声差分麦克风的前置放大与扬声器、耳机和差分、立体声线输出的驱动, 减少了应用时必需的外部组件,比如不需要单独的麦克风或者耳机的放大器。
  高级的片上数字信号处理功能,包含一个 5 路均衡功能,一个用于 ADC 和麦克风或者线路输入之间的混合信号的电平自动控制功能, 一个纯粹的录音或者重放的数字限幅功能。另外在 ADC 的线路上提供了一个数字滤波的功能,可以更好的应用滤波,比如“减少风噪声”。
  WM8978 可以被应用为一个主机或者一个从机。基于共同的参考时钟频率,比如 12MHz 和 13MHz,内部的PLL 可以为编译码器提供所有需要的音频时钟。
WM8978 工作在模拟电源电压 2.5V 到 3.3V,尽管它的数字核心部分为了节省电能可以把工作电压下降到1.62V。如果需要增大输出功率, 扬声器和 OUT3/4 线输出可以在 5V 电源运行。芯片的个别部分也可以通过软件进行断电控制。

2、WM8978特点

  • DAC 的信噪比为 98dB, 总谐波失真为-84dB
  •  ADC 的信噪比为 90dB, 总谐波失真为-80dB
  •  立体声差分或者单声道麦克风接口
  •  为驻极体麦克风提供低噪音偏置
  •  增强的 3D 功能用于提高立体声分离
  • 5 路均衡器(录音或者重放)
  • 可调的 ADC 高通滤波器(减少风噪声)
  • 低功耗、低电压
  • I2S 接口,支持最高 192K,24bit 音频播放
  • 左右声道音量独立调节

3、WM8978接口

WM8978 的控制通过 IIS 接口(数字音频接口)跟 MCU 进行音频数据传输(支持音频接收和发送), 通过两线(MODE=0,IIC 接口)或三线( MODE=1)接口进行配置。 WM8978 的 I2S 接口,由 4 个引脚组成:
1.ADCDAT:ADC 数据输出
2.DACDAT:DAC 数据输入
3.LRC:数据左/右对齐时钟
4.BCLK:位时钟,用于同步


WM8978 芯片可以作为 IIS 主机,用于输出 LRC 和 BLCK 时钟,本实验中,我们把 WM8978 作为从机使用,用于接收 LRC 和 BLCK。此外, WM8978 的 IIS 接口一共支持 5 中不同的音频数据模式:
1.左对齐标准( MSB)
2.右对齐标准( LSB)
3.飞利浦标准( IIS)
4.DSP 模式 A
5. DSP 模式 B


本实验中,使用的是飞利浦标准来传输 I2S 数据。
飞利浦标准模式(IIS),指的是数据在跟随 LRC 传输的 BCLK 的第二个上升沿时传输 MSB,其他位一直到LSB 按顺序传输。传输依赖于字长、BCLK 频率和采样率,在每个采样的 LSB 和下一个采样的 MSB 之间都应该有未用的 BCLK 周期。飞利浦标准模式(IIS)数据传输协议如图

 

从图中可知,fs 即音频信号的采样率,比如 44.1Khz,因此, LRC 的频率就是音频信号的采样率。 此外,WM8978 还需要一个 MCLK,本实现中采用 STM32F4 为 WM8978 提供一个 MCLK 时钟, MCLK 的频率为音频采样率的 256 倍,即 MCLK=256 * fs。

4、WM8978框架

 如图,WM8978 内部有很多的模拟开关,用来选择通道,同时还有很多调节器,用来设置增益和音量的。本实现中,使用的是 IIC 接口( MODE=0)来跟 WM8978 进行通信,不过,WM8978 的 IIC 接口跟我们之前学习的 IIC 接口有一些不同之处:
1.只可以写数据,不可以读数据
2.寄存器的位宽为 7 位,数据的位宽为 9 位
3.寄存器字节的最低位用于传输数据的最高位的数据
4.WM8978 的器件地址为:0011010 b(0X1A)


5、 WM8978 寄存器

WM8978 芯片有很多的寄存器,在这里,我们只介绍比较常用的那些寄存器。
1.R0 寄存器(00H)。此寄存器功能用于控制 WM8978 的软件复位,写任意值到该寄存器地址,即可实现WM8978 的软件复位。
2.R1 寄存器(01H)。此寄存器需要使能 BIASEN(Bit3)位,该位置 1,模拟部分的放大器才会工作,只有使能了该位才可以听到声音。
3.R2 寄存器(02H)。此寄存器需要设置 ROUT1EN (Bit8)位、LOUT1EN(Bit7)和 SLEEP(Bit6)这三个位, ROUT1EN 和 LOUT1EN 位设置为 1,使能耳机输出, SLEEP 设置为 0,进入正常工作模式。
4.R3 寄存器( 03H)。此存器需要要设置 LOUT2EN (Bit6), ROUT2EN (Bit5),RMIXER(Bit3),LMIXER(Bit2), DACENR(Bit1)和 DACENL(Bit0)这 6 个位。其中,LOUT2EN 和 ROUT2EN 位设置为 1,使能喇叭输出; LMIXER 和 RMIXER 位设置为 1, 使能左右声道混合器; DACENL 和 DACENR 位设置为 1,使能则左右声道的 DAC。
5. R4 寄存器( 04H)。此寄存器需要要设置 WL(Bit6:5)和 FMT(Bit4:3)这 4 个位。 WL(Bit6:5)用于设置字长,即音频数据有效位数。00 表示 16 位音频,10 表示 24 位音频;FMT(Bit4:3)位用于设置 IIS音频数据模式,这里设置为 10,表示 使用飞利浦模式(IIS)。
6. R6 寄存器( 06H)。此寄存器全部设置为 0 ,即设置 MCLK 和 BCLK 时钟源都来源于外部,本实验来源于 STM32F4 芯片。
7. R10 寄存器(0AH)。此寄存器需要设置 SOFTMUTE(Bit6)和 DACOSR128(Bit3)这两个位,其中SOFTMUTE 位设置为 0,即关闭软件静音;DACOSR128 位设置为 1,即 DAC 得到最好的 SNR。
8. R43 寄存器(2BH)。此寄存器只需要把 INVROUT2 位置 1 ,即反转 ROUT2 输出,这样以使于更好的驱动喇叭。 

9. R49 寄存器(31H)。此寄存器需要设置 SPKBOOST(Bit2)和 TSDEN(Bit1)这两个位。SPKBOOST
位用于设置喇叭的增益,可以设置为 0 ,如果想获得更大的声音,则设置为 1; TSDEN 位用于设置过热保护,
如果需要开启过热保护,则设置为 1,不开启设置为 0 即可。
10.R50 寄存器(32H)。此寄存器只需要设置 DACL2LMIX(Bit0),该位用于设置将左声道的 DAC 输出
接入左声道混合器里面,才能在耳机或者喇叭听到音乐。
11.R51 寄存器(33H)。此寄存器只需要设置 DACR2RMIX(Bit0),该位用于设置将右声道的 DAC 输出
接入右声道混合器里面,才能在耳机或者喇叭听到音乐。
12.R52 寄存器(34H)。此寄存器用于设置耳机左声道的音量,HPVU(Bit8)用于设置是否更新左声道的
音量。LOUT1VOL(Bit5:0)位用于设置左声道的音量。
13.R53 寄存器(35H)。此寄存器用于设置耳机右声道的音量,HPVU(Bit8)用于设置是否更新右声道的
音量。ROUT1VOL(Bit5:0)位用于设置右声道的音量。
14.R54 寄存器(36H)。此寄存器用于设置喇叭左声道的音量,HPVU(Bit8)用于设置是否更新左声道的
音量。LOUT1VOL(Bit5:0)位用于设置左声道的音量。
15.R55 寄存器(37H)。此寄存器用于设置喇叭右声道的音量,HPVU(Bit8)用于设置是否更新右声道的
音量。ROUT1VOL(Bit5:0)位用于设置右声道的音量。

三、IIS详解

1、IIS介绍

IIS,Inter IC Sound 的简称,又称集成电路内置音频总线,是飞利浦公司为数字音频设备之间的音频数据传输而
制定的一种总线标准,该总线专责于音频设备之间的数据传输,广泛应用于各种多媒体系统。它采用了沿独立的
导线传输时钟与数据信号的设计,通过将数据和时钟信号分离,避免了因时差诱发的失真,为用户节省了购买抵
抗音频抖动的专业设备的费用。


2、 IIS 的特点

 全双工通信或半双工通信
 主模式或从模式操作
 8 位可编程线性预分频器,可实现精确的音频采样频率(从 8 kHz 到 192 kHz)
 数据格式可以是 16 位、 24 位或 32 位
 数据包帧由音频通道固定为 16 位(可容纳 16 位数据帧)或 32 位(可容纳 16 位、24 位、32 位数据帧)
 可编程的时钟极性
 发送和接收使用同一个 16 位数据寄存器
 支持的 IIS 协议:
 I2S Phillps 标准
 MSB 对齐标准(左对齐)
 LSB 对齐标准(右对齐)
 PCM 标准
 数据方向始终为 MSB 在前
 用于发送和接收的 DMA 功能( 16 位宽)
 可输出主时钟以驱动外部音频元件。比率固定为 256 * FS(其中 FS 为音频采样频率)

3、IIS框架

STM32F4 的 IIS 是与 SPI 部分共用的,我们可以通过设置 SPI_I2SCFGR 寄存器的 I2SMOD 位来开启 IIS功能, IIS 接口使用了几乎与 SPI 相同的引脚、标志和中断。由图 9.4.4 可知,IIS 使用的信号线主要有:
1.SD:串行数据。此信号线映射到 SPI 中的 MOSI 引脚,用于发送或接收两个时分复用的数据通道上的数据,仅在半双工模式下使用。
2.I2S2ext_SD / I2S3ext_SD:用于控制 I2S 全双工模式的附加引脚,此引脚映射到 SPI 中的 MISO 引脚。
3.WS:字选择。此信号线映射到 SPI 中的 NSS 引脚,此引脚在 IIS 中为帧时钟,用于切换左右声道的数据。 WS 频率等于音频信号采样率(FS)。
4. CK:串行时钟。此信号线映射到 SPI 中的 SCK 引脚,此引脚在 IIS 中为位时钟,是主模式下的串行时钟输出以及从模式下的串行时钟输入。 CK 频率=WS 频率(FS) * 2 * 16(16 位宽),如果是 32 位宽,则是: CK 频率=WS 频率(FS)* 2 * 32( 32 位宽)。
5.MCK:主时钟输出。 当 IIS 配置为主模式,并且 SPI_I2SPR 寄存器中的 MCKOE 位设置为 1 时,则使用该时钟,该时钟输出频率为 256 * FS,其中 FS 为采样频率。

为支持 IIS 全双工模式,除了 IIS2 和 IIS3,还可以使用两个额外的 IIS,它们称为扩展 IIS( IIS2_ext、IIS3_ext)如下图所示:

 由图 可知,第一个 IIS 全双工接口基于 IIS2 和 IIS2_ext,第二个基于 IIS3 和 IIS3_ext。IIS2_ext 和
IIS3_ext 仅用于全双工模式。
IISx 可以在主模式下工作。因此:
 只有 IISx 可在半双工模式下输出 SCK 和 WS
 只有 IISx 可在全双工模式下向 IIS2_ext 和 IIS3_ext 提供 SCK 和 WS。
扩展 IIS (IISx_ext) 只能用于全双工模式。 IISx_ext 始终在从模式下工作。IISx 和 IISx_ext 均可用于发送和接
收。


4、 音频协议

STM32F4 有四种数据和帧格式组合,可采用下列格式发送数据:
1. 将 16 位数据封装在 16 位帧中
2. 将 16 位数据封装在 32 位帧中
3. 将 24 位数据封装在 32 位帧中
4. 将 32 位数据封装在 32 位帧中
当使用 32 位数据包中的 16 位数据时,高 16 位 (MSB) 为有效位, 低 16 位 LSB 被强制清零,无需任何软
件操作或 DMA 请求(只需一个读/写操作)。如果应用程序首选 DMA,则 24 位和 32 位数据帧需要对 SPI_DR
执行两次 CPU 读取或写入操作,或者需要两次 DMA 操作。 24 位的数据帧,硬件会将 8 位非有效位扩展到
带有 0 位的 32 位。对于所有数据格式和通信标准而言,始终会先发送最高有效位( MSB 优先)。


5、 IIS Philips 标准

使用 WS 信号来指示当前正在发送的数据所属的通道。该信号从当前通道数据的第一个位(MSB) 之前的一个时钟开始有效。以 24 位为例 IIS Philips 协议波形图如图所示:

 由图  可知,在 24 位模式下数据传输,需要对 SPI_DR 执行两次读取或写入操作。比如我们要发送0X8EAA33 这个数据,就要分两次写入 SPI_DR,第一次写入:0X8EAA,第二次写入 0X33xx( xx 可以为任意数值),这样就把 0X8EAA33 发送出去了。
需要注意的是, 当我们从 SD 卡读取 24 位 WAV 数据流时,是低字节在前,高字节在后的,例如,当我们读到一个声道的数据(24bit),存储在一个 buf[3]的数据中,那么需要通过 SPI_DR 寄存器来发送这 24 位数据,那么就需要分两次来发送,第一次发送高 16 位数据,第二次发送低 8 位数据。代码可按以下过程来操作:
SPI_DR=((u16)buf[2]<<8)+buf[1]; //发送高 16 位数据
SPI_DR=(u16)buf[0]<<8; //发送低 8 位数据


6、 IIS 时钟

IIS 比特率用来确定 IIS 数据线上的数据流和 IIS 时钟信号频率。
IIS 比特率 = 每个通道的位数 * 通道数 * 音频采样频率。
对于 16 位双通道音频, IIS 比特率的计算公式如下:
IIS 比特率 = 16 × 2 × FS
如果数据包为 32 位宽,则 IIS 比特率 = 32 x 2 x FS。
IIS 时钟发生器架构如图所示:


由图可知, I2SxCLK 时钟源来自于 PLLI2S 输出(通过 R 分频系数)或外部时钟(映射到 I2S_CKIN 引脚)。本实验中使用 PLLI2S 输出作为 I2SxCLK 的时钟。
我们需要根据音频采样率( Fs,即 CK 的频率)来计算各个分频器的值,常用的音频采样率有: 22.05Khz、44.1Khz、 48Khz、 96Khz、 196Khz 等。为达到所需频率,需要根据以下公式对线性分频器进行编程:输出主时钟( SPI_I2SPR 寄存器中的 MCKOE 置 1)时:
Fs = I2SxCLK / [(16*2)*((2*I2SDIV)+ODD)*8)](通道帧宽度为 16 位时)
Fs = I2SxCLK / [(32*2)*((2*I2SDIV)+ODD)*4)](通道帧宽度为 32 位时)
关闭主时钟输出( MCKOE 位清零)时:
Fs = I2SxCLK / [(16*2)*((2*I2SDIV)+ODD))](通道帧宽度为 16 位时)
Fs = I2SxCLK / [(32*2)*((2*I2SDIV)+ODD))](通道帧宽度为 32 位时)
输出主时钟时,音频频率精度可按表所示:


四、音乐播放硬件设计 

 

 

五、音乐播放软件设计

 1、软件设计思路

 软件设计思想

  1. 初始化 SD 卡。本实验中需要播放 SD 卡中的 WAV 格式的音乐文件,因此需要初始化 SD 卡。
  2. 初始化 WM8978 芯片。配置 9.5.3 章节介绍的 WM8978 芯片的相关寄存器。主要包括软件复位、DAC 设置,输出设置和音量设置等。
  3. 初始化 IIS。主要设置 SPI_I2SCFGR 寄存器,设置 I2S 模式、 I2S 标准、时钟空闲电平和数据帧长等,最后开启 I2S TX DMA,使能 I2S 外设。
  4. 解析 WAV 文件。解析文件主要是获取音频信号采样率和位数并设置 I2S 时钟分频器。
  5. 设置 DMA。本实验中使用到 DMA 来传输数据,并且我们使用 IIS2,其 TX 是使用的 DMA1 数据流 4的通道 0 来传输的。STM32F4 的 DMA 支持双缓冲功能,这样可以提高数据传输的效率。本实验中我们需要将 DMA1 数据流 4 设置为:双缓冲循环模式,外设和存储器都是 16 位宽,并开启 DMA 传输完成中断。
  6. FATFS 文件系统打开播放文件。
  7. 启动 DMA 传输数据。播放音乐。

2、部分程序编程以及分析

wm8978.c文件中,WM8978芯片初始化

u8 WM8978_Init(void)
{
u8 res;
RCC->AHB1ENR|=1<<1; //使能外设 PORTB 时钟
RCC->AHB1ENR|=1<<2; //使能外设 PORTC 时钟
//配置 PB 口 PB12/13 复用功能输出
GPIOB->MODER &= ~( 0x03<<24 | 0x03<<26 );
GPIOB->MODER |= ( 0x02<<24 | 0x02<<26);
GPIOB->OTYPER &= ~( 0X01<<12 | 0X01<<13); //输出类型----推挽
GPIOB->OSPEEDR |= ( 0x03<<24 | 0x03<<26);//输出速度----100M
//配置 PC 口 PC2/PC3/PC6 复用功能输出
GPIOC->MODER &= ~( 0x03<<4 | 0x03<<6 | 0x03U<<12);
GPIOC->MODER |= ( 0x02<<4 | 0x02<<6 | 0x02U<<12);
GPIOC->OTYPER &= ~( 0X01<<2 | 0X01<<3 | 0X01<<6); //输出类型----推挽
GPIOC->OSPEEDR |= ( 0x03<<4 | 0x03<<6 | 0x03U<<12);//输出速度----100M
//配置 IO 口复用功能
Set_GPIO_AF(GPIOB,12,5);
Set_GPIO_AF(GPIOB,13,5);
Set_GPIO_AF(GPIOC,3,5);
Set_GPIO_AF(GPIOC,2,6);
Set_GPIO_AF(GPIOC,6,5);
res=WM8978_Write_Reg(0,0); //软复位 WM8978
if(res)return 1; //发送指令失败,WM8978 异常
WM8978_Write_Reg(1,0X1B); //配置 R1 寄存器
WM8978_Write_Reg(2,0X1B0); //配置 R2 寄存器
WM8978_Write_Reg(3,0X6C); //配置 R3 寄存器
WM8978_Write_Reg(6,0); //配置 R4 寄存器
WM8978_Write_Reg(43,1<<4); //配置 R43 寄存器
WM8978_Write_Reg(47,1<<8); //配置 R47 寄存器
WM8978_Write_Reg(48,1<<8); //配置 R48 寄存器
WM8978_Write_Reg(49,1<<1); //配置 R49 寄存器
WM8978_Write_Reg(10,1<<3); //配置 R10 寄存器
WM8978_Write_Reg(14,1<<3); //配置 R10 寄存器
return 0;
}

WM8978IIS 写寄存器功能


/********************************************************************
* 函数名: u8 WM8978_Write_Reg(u8 reg,u16 val)
* 功能描述: WM8978 芯片写寄存器的值
* 输入参数: reg:寄存器地址
val:要写入寄存器的值
* 输出参数: 无
* 返回值: 0,写成功 1,写放失败
*********************************************************************/
u8 WM8978_Write_Reg(u8 reg,u16 val)
{
IIC_Start();
IIC_Send_Byte((WM8978_ADDR<<1)|0);//发送器件地址+写命令
if(IIC_Wait_Ack()) //等待应答
{
return 1;
}
IIC_Send_Byte(((reg<<1)& 0xFE)|((val>>8)&0X01));//写寄存器地址+数据的最高位
if(IIC_Wait_Ack()) //等待应答
{
return 1;
}
IIC_Send_Byte(val&0XFF); //发送数据
if(IIC_Wait_Ack())
{
return 1; //等待应答
}
IIC_Stop();
wm8978_RegCash[reg]=val; //保存寄存器值到本地
return 0;
}

WM8978开启DAC功能

/********************************************************************
* 函数名: void WM8978_DAC_Init(void)
* 功能描述: 开启 WM8978 芯片 DAC 功能
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*********************************************************************/
void WM8978_DAC_Init(void)
{
u16 regval;
regval=WM8978_Read_Reg(3); //读取 R3 寄存器的值
regval|=3<<0; //R3 寄存器最低 2 个位设置为 1,即开启 DACR&DACL
WM8978_Write_Reg(3,regval); //配置 R3 寄存器
regval=WM8978_Read_Reg(2); //读取 R3 寄存器的值
WM8978_Write_Reg(50,0x01); //配置 R50 寄存器
WM8978_Write_Reg(51,0x01); //配置 R51 寄存器
}

WM8978IIS模式


/********************************************************************
* 函数名: void WM8978_I2S_Mode(u8 fmt,u8 len)
* 功能描述: 设置 WM8978 芯片 IIS 工作模式
* 输入参数: fmt: 0,LSB(右对齐);1,MSB(左对齐);2,飞利浦标准 I2S;3,PCM/DSP;
len: 0,16 位;1,20 位;2,24 位;3,32 位
* 输出参数: 无
* 返回值: 无
* 其他:
* 作者:
*********************************************************************/
void WM8978_I2S_Mode(u8 fmt,u8 len)
{
fmt&=0X03;//限定范围
len&=0X03;//限定范围
WM8978_Write_Reg(4,(fmt<<3)|(len<<5)); //R4,WM8978 工作模式设置
}

WM8978设置耳机音量功能


/********************************************************************
* 函数名: void WM8978_Set_Vol(u8 voll,u8 volr)
* 功能描述: 设置耳机音量
* 输入参数: voll ,左声道音量
volr ,右声道音量
* 输出参数: 无
* 返回值: 无
*********************************************************************/
void WM8978_Set_Vol(u8 voll,u8 volr)
{
voll&=0X3F;
volr&=0X3F;//限定范围
WM8978_Write_Reg(52,voll); //R52,耳机左声道音量设置
WM8978_Write_Reg(53,volr|(1<<8)); //R53,耳机右声道音量设置,同步更新(HPVU=1)
}

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

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

相关文章

力扣-删除重复的电子邮箱

大家好&#xff0c;我是空空star&#xff0c;本篇带大家了解一道简单的力扣sql练习题。 文章目录前言一、题目&#xff1a;196. 删除重复的电子邮箱二、解题1.正确示范①提交SQL运行结果2.正确示范②提交SQL运行结果3.正确示范③提交SQL运行结果4.正确示范④提交SQL运行结果5.其…

2.22Linux系统搭建

一.搭建Linux运行环境需要部署Java程序到服务器上,这样程序才能被外面的用户访问到1.安装jdkyum install develop x86_642.安装tomcat1)下载好,通过xshell直接拖到服务器上,依赖了rz命令2)解压缩unzip命令3)使.sh都有可执行权限chmod x *.sh4)启动 sh startup.sh5) 验证 ①ps a…

MAC配置pycharm

Mac配置pycharm 恢复出厂配置 # configuration rm -rf ~/library/preferences/JetBrains/ # caches rm -rf ~/library/caches/JetBrains/ # plugins rm -rf ~/library/application support/JetBrains/ # logs rm -rf ~/library/logs/JetBrains/文件头部 Python #!/usr/bin/e…

Mind+Python+Mediapipe项目——AI健身之跳绳

原文&#xff1a;MindPythonMediapipe项目——AI健身之跳绳 - DF创客社区 - 分享创造的喜悦 【项目背景】跳绳是一个很好的健身项目&#xff0c;为了获知所跳个数&#xff0c;有的跳绳上会有计数器。但这也只能跳完这后看到&#xff0c;能不能在跳的过程中就能看到&#xff0c;…

【Linux】virtualbox获取虚拟机串口日志方法,值得收藏

环境 宿主机&#xff1a;redhat 7.8 virtualbox &#xff1a;6.1.10 虚拟机&#xff1a;UOS 1050u1a x86 一、virtualbox设置 在串口栏中勾选 []启用串口 端口编号选择COM1 端口模式选择裸文件 Port/File Path: 填上 /tmp/box 也就是说我们在宿主机器的/tmp/中创建了vbox的…

C语言知识总结

" "和’ 的比较 " "视为字符串&#xff0c;且编译器在后面自动加上’\0’ 则视为单个字符&#xff0c;整型 1、本质区别 双引号里面的是字符串&#xff0c; 而单引号里面的代表字符。 2、输出区别 str “a”输出的就是a这个字母&#xff1b; str ‘a’…

GSON入门篇(内含教学视频+源代码)

GSON入门篇&#xff08;内含教学视频源代码&#xff09; 教学视频源代码下载链接地址&#xff1a;https://download.csdn.net/download/weixin_46411355/87474475 目录GSON入门篇&#xff08;内含教学视频源代码&#xff09;教学视频源代码下载链接地址&#xff1a;[https://d…

j6-IO流泛型集合多线程注解反射Socket

IO流 1 JDK API的使用 2 io简介 输入流用来读取in 输出流用来写出Out 在Java中&#xff0c;根据处理的数据单位不同&#xff0c;分为字节流和字符流 继承结构 java.io包&#xff1a; File 字节流&#xff1a;针对二进制文件 InputStream --FileInputStream --BufferedInputStre…

【数据结构与算法】字符串1:反转字符串I 反转字符串II 反转字符串里的单词 剑指offer(替换空格、左旋转字符串)

今日任务 344.反转字符串541.反转字符串II剑指Offer 05.替换空格151.反转字符串里的单词剑指Offer58-II.左旋转字符串 1.Leetcode344.反转字符串 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;https://leetcode.cn/problems/reverse-string &#…

项目管理工具dhtmlxGantt甘特图入门教程(十一):后端集成问题解决方法

这篇文章给大家讲解如何解决dhtmlxGantt后端集成的问题。 dhtmlxGantt是用于跨浏览器和跨平台应用程序的功能齐全的Gantt图表&#xff0c;可满足应用程序的所有需求&#xff0c;是完善的甘特图图表库 DhtmlxGantt正版试用下载https://www.evget.com/product/4213/download …

联想小新 Air-14 2019IML电脑 Hackintosh 黑苹果efi引导文件

原文来源于黑果魏叔官网&#xff0c;转载需注明出处。硬件型号驱动情况主板Lenovo LNVNB161216处理器Intel Core i5-10210U / i7-10510U已驱动内存8GB DDR4 2666已驱动硬盘康佳KAK0500B128(128 GB/固志硬盘)已驱动显卡Intel UHD 620Nvidia GeForce MX250(屏蔽)无法驱动声卡Cone…

中国社科院与美国杜兰大学金融管理硕士——努力看到别样的风景

卡耐基曾说过&#xff0c;现在的努力是为了换取走更远的路&#xff0c;看到别人看不到的风景。现在卖命是为了让年老的时候&#xff0c;可以不用疲于奔命。对于这段话我深以为然&#xff0c;现在不努力&#xff0c;更待何时呢&#xff0c;就像在职的我们&#xff0c;想发展的更…

编译原理笔记(1)绪论

文章目录1.什么是编译2.编译系统的结构3.词法分析概述4.语法分析概述5.语义分析概述6.中间代码生成和后端概述1.什么是编译 编译的定义&#xff1a;将高级语言翻译成汇编语言或机器语言的过程。前者称为源语言&#xff0c;后者称为目标语言。 高级语言源程序的处理过程&#…

2020蓝桥杯真题回文日期 C语言/C++

题目描述 2020 年春节期间&#xff0c;有一个特殊的日期引起了大家的注意&#xff1a;2020 年 2 月 2 日。因为如果将这个日期按 “yyyymmdd” 的格式写成一个 8 位数是 20200202&#xff0c;恰好是一个回文数。我们称这样的日期是回文日期。 有人表示 20200202 是 “千年一遇…

JUC-day03

JUC-day03 线程池: 核心参数(核心线程数 最大线程数 闲置时间 闲置时间单位 阻塞队列 拒绝策略 工厂对象)—理论异步编排: 代码能并行的运行起来—练习(业务能力)流式编程: 串行化编程(List—>数据流—>逻辑一致(过滤器)—>新数据)----练习(编码能力) 1 阻塞队列 1…

ActiveReports.NET 17.0.1 Crack 2023-02-14

ActiveReports.NET v17 现已可用&#xff01;作为我们的主要年度版本&#xff0c;此更新为 ActiveReports 生态系统提供了大量令人兴奋的新功能和改进。 RDL 仪表板 - 新报告类型 ActiveReports 17 带来的最令人兴奋的功能之一是新的 RDL Dashboard 报告类型&#xff01;RDL 仪…

基于SpringBoot的外卖项目(详细开发过程)

基于SpringBootMyBatisPlus的外卖项目1、软件开发整体介绍软件开发流程角色分工2、外卖项目介绍项目介绍产品展示后台系统管理移动端技术选型功能结构角色3、开发环境的搭建开发环境说明建库建表Maven项目搭建项目的目录结构pom.xmlapplication.ymlReggieApplication启动类配置…

WSO2 apim Subscribe to an API

WSO2 apim Application Subscribe to an API1. Published an Api2. Subscribe to an API using Key Generation Wizard3. Subscribe to an existing application4. AwakeningWSO2安装使用的全过程详解: https://blog.csdn.net/weixin_43916074/article/details/127987099. Offi…

SpringCloud第五讲 Nacos注册中心-服务注册到Nacos

1.引入依赖&#xff1a; 在父工程中添加spring-cloud-alibaba的管理依赖 <!-- Nacos的管理依赖--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version…

Leetcode12. 整数转罗马数字

一、题目描述&#xff1a; 罗马数字包含以下七种字符&#xff1a; I&#xff0c; V&#xff0c; X&#xff0c; L&#xff0c;C&#xff0c;D 和 M。 字符数字I1V5X10L50C100D500M1000 例如&#xff0c; 罗马数字 2 写做 II &#xff0c;即为两个并列的 1。12 写做 XII &…