前几年,MP3曾经风行一时,几乎人手一个。如果能自己做一个MP3,我想对于很多朋友来说,是十分骄傲的事情。ALIENTEK战舰STM32开发板自带了一颗非常强劲的MP3解码芯片:VS1053,利用该芯片,我们可以实现MP3/OGG/WMA/WAV/FLAC/AAC/MIDI等各种音频文件的播放。本章,我们将利用战舰STM32开发板实现一个简单的MP3播放器。本章分为如下几个部:
49.1 MP3简介
49.2 硬件设计
49.3 软件设计
49.4 下载验证
VS1053是继VS1003后荷兰VLSI公司出品的又一款高性能解码芯片。该芯片可以实现对MP3/OGG/WMA/FLAC/WAV/AAC/MIDI等音频格式的解码,同时还可以支持ADPCM/OGG等格式的编码,性能相对以往的VS1003提升不少。VS1053拥有一个高性能的DSP处理器核VS_DSP,16K的指令RAM,0.5K的数据RAM,通过SPI控制,具有8个可用的通用IO口和一个串口,芯片内部还带了一个可变采样率的立体声ADC(支持咪头/咪头+线路/2线路)、一个高性能立体声DAC及音频耳机放大器。
VS1053的特性如下:
●支持众多音频格式解码,包括OGG/MP3/WMA/WAV/FLAC(需要加载patch)/MIDI/AAC等。
●对话筒输入或线路输入的音频信号进行OGG(需要加载patch)/IMA ADPCM编码
●高低音控制
●带有EarSpeaker空间效果(用耳机虚拟现场空间效果)
●单时钟操作12..13MHz
●内部PLL锁相环时钟倍频器
●低功耗
●内含高性能片上立体声DAC,两声道间无相位差
●过零交差侦测和平滑的音量调整
●内含能驱动30 欧负载的耳机驱动器
●模拟,数字,I/O 单独供电
●为用户代码和数据准备的16KB片上RAM
●可扩展外部DAC的I2S接口
●用于控制和数据的串行接口(SPI)
●可被用作微处理器的从机
●特殊应用的SPI Flash引导
●供调试用途的UART接口
●新功能可以通过软件和8 GPIO 添加
VS1053相对于它的前辈VS1003,增加了编解码格式的支持(比如支持OGG/FLAC,还支持OGG编码,VS1003不支持)、增加了GPIO数量到8个(VS1003只有4个)、增加了内部指令RAM容量到16KiB(VS1003只有5.5KiB)、增加了I2S接口(VS1003没有)、支持EarSpeaker空间效果(VS1003不支持)等。同时VS1053的DAC相对于VS1003有不少提高,同样的歌曲,用VS1053播放,听起来比1003效果好很多。
VS1053的封装引脚和VS1003完全兼容,所以如果你以前用的是VS1003,则只需要把VS1003换成VS1053,就可以实现硬件更新,电路板完全不用修改。不过需要注意的是VS1003的CVDD是2.5V,而VS1053的CVDD是1.8V,所以你还需要把稳压芯片也变一下,其他都可以照旧了。
VS1053通过SPI接口来接受输入的音频数据流,它可以是一个系统的从机,也可以作为独立的主机。这里我们只把它当成从机使用。我们通过SPI口向VS1053不停的输入音频数据,它就会自动帮我们解码了,然后从输出通道输出音乐,这时我们接上耳机就能听到所播放的歌曲了。
ALIENTEK战舰STM32开发板,自带了一颗VS1053音频编解码芯片,所以,我们直接可以通过开发板来播放各种音频格式,实现一个音乐播放器。战舰STM32开发板自带的VS1053解码芯片电路原理图,如图49.1.1所示:
VS1053通过7根线同STM32连接,他们是:VS_MISO、VS_MOSI、VS_SCK、VS_XCS、VS_XDCS、VS_DREQ和VS_RST。这7根线同STM32的连接关系如表49.1.1所示:
表49.1.1 VS1053各信号线与STM32连接关系
其中VS_RST是VS1053的复位信号线,低电平有效。VS_DREQ是一个数据 请求信号,用来通知主机,VS1053可以接收数据与否。VS_MISO、VS_MOSI和VS_SCK则是VS1053的SPI接口他们在VS_XCS和VS_XDCS下面来执行不同的操作。从上表可以看出,VS1053的SPI是接在STM32的SPI1上面的。
VS1053的SPI支持两种模式:1,VS1002有效模式(即新模式)。2,VS1001兼容模式。这里我们仅介绍VS1002有效模式(此模式也是VS1053的默认模式)。表49.1.2是在新模式下VS1053的SPI信号线功能描述:
表49.1.2 VS1053新模式下SPI口信号线功能
VS1053的SPI数据传送,分为SDI和SCI,分别用来传输数据/命令。SDI和前面介绍的SPI协议一样的,不过VS1053的数据传输是通过DREQ控制的,主机在判断DREQ有效(高电平)之后,直接发送即可(一次可以发送32个字节)。
这里我们重点介绍一下SCI。SCI串行总线命令接口包含了一个指令字节、一个地址字节和一个16位的数据字。读写操作可以读写单个寄存器,在SCK的上升沿读出数据位,所以主机必须在下降沿刷新数据。SCI的字节数据总是高位在前低位在后的。第一个字节指令字节,只有2个指令,也就是读和写,读为0X03,写为0X02。
一个典型的SCI读时序如图49.1.2所示:
图49.1.2 SCI读时序
从图49.1.2可以看出,向VS1053读取数据,通过先拉低XCS(VS_XCS),然后发送读指令(0X03),再发送一个地址,最后,我们在SO线(VS_MISO)上就可以读到输出的数据了。而同时SI(VS_MOSI)上的数据将被忽略。
看完了SCI的读,我们再来看看SCI的写时序,如图49.1.3所示:
图49.1.3 SCI写时序
图49.1.3中,其时序和图49.1.2基本类似,都是先发指令,再发地址。不过写时序中,我们的指令是写指令(0X02),并且数据是通过SI写入VS1053的, SO则一直维持低电平。细心的读者可能发现了,在这两个图中,DREQ信号上都产生了一个短暂的低脉冲,也就是执行时间。这个不难理解,我们在写入和读出VS1053的数据之后,它需要一些时间来处理内部的事情,这段时间,是不允许外部打断的,所以,我们在SCI操作之前,最好判断一下DREQ是否为高电平,如果不是,则等待DREQ变为高。
了解了VS1053的SPI读写,我们再来看看VS1053的SCI寄存器,VS1053的所有SCI寄存器如表49.1.3所示:
SCI寄存器 |
||||
寄存器 |
类型 |
复位值 |
缩写 |
描述 |
0X00 |
RW |
0X0800 |
MODE |
模式控制 |
0X01 |
RW |
0X000C |
STATUS |
VS0153状态 |
0X02 |
RW |
0X0000 |
BASS |
内置低音/高音控制 |
0X03 |
RW |
0X0000 |
CLOCKF |
时钟频率+倍频数 |
0X04 |
RW |
0X0000 |
DECODE_TIME |
解码时间长度(秒) |
0X05 |
RW |
0X0000 |
AUDATA |
各种音频数据 |
0X06 |
RW |
0X0000 |
WRAM |
RAM 写/读 |
0X07 |
RW |
0X0000 |
WRAMADDR |
RAM 写/读的基址 |
0X08 |
R |
0X0000 |
HDAT0 |
流的数据标头0 |
0X09 |
R |
0X0000 |
HDAT1 |
流的数据标头1 |
0X0A |
RW |
0X0000 |
AIADDR |
应用程序起始地址 |
0X0B |
RW |
0X0000 |
VOL |
音量控制 |
0X0C |
RW |
0X0000 |
AICTRL0 |
应用控制寄存器0 |
0X0D |
RW |
0X0000 |
AICTRL1 |
应用控制寄存器1 |
0X0E |
RW |
0X0000 |
AICTRL2 |
应用控制寄存器2 |
0X0F |
RW |
0X0000 |
AICTRL3 |
应用控制寄存器3 |
表49.1.3 SCI寄存器
VS1053总共有16个SCI寄存器,这里我们不介绍全部的寄存器,仅仅介绍几个我们在本章需要用到的寄存器。
首先是MODE寄存器,该寄存器用于控制VS1053的操作,是最关键的寄存器之一,该寄存器的复位值为0x0800,其实就是默认设置为新模式。表49.1.4是MODE寄存器的各位描述:
表49.1.4 MODE寄存器各位描述
这个寄存器,我们这里只介绍一下第2和第11位,也就是SM_RESET和SM_SDINEW。其他位,我们用默认的即可。这里SM_RESET,可以提供一次软复位,建议在每播放一首歌曲之后,软复位一次。SM_SDINEW为模式设置位,这里我们选择的是VS1002新模式(本地模式),所以设置该位为1(默认的设置)。其他位的详细介绍,请参考VS1053的数据手册。
接着我们看看BASS寄存器,该寄存器可以用于设置VS1053的高低音效。该寄存器的各位描述如表49.1.5所示:
表49.1.5 BASS寄存器各位描述
通过这个寄存器以上位的一些设置,我们可以随意配置自己喜欢的音效(其实就是高低音的调节)。VS1053的EarSpeaker效果则由MODE寄存器控制,请参考表49.1.4。
接下来,我们介绍一下CLOCKF寄存器,这个寄存器用来设置时钟频率、倍频等相关信息,该寄存器的各位描述如表49.1.6所示:
表49.1.6 CLOCKF寄存器各位描述
此寄存器,重点说明SC_FREQ,SC_FREQ是以4Khz为步进的一个时钟寄存器,当外部时钟不是12.288M的时候,其计算公式为:
SC_FREQ=(XTALI-8000000)/4000
式中为XTALI的单位为Hz。表49.1.6中CLKI是内部时钟频率,XTALI是外部晶振的时钟频率。由于我们使用的是12.288M的晶振,在这里设置此寄存器的值为0X9800,也就是设置内部时钟频率为输入时钟频率的3倍,倍频增量为1.0倍。
接下来,我们看看DECODE_TIME这个寄存器。该寄存器是一个存放解码时间的寄存器,以秒钟为单位,我们通过读取该寄存器的值,就可以得到解码时间了。不过它是一个累计时间,所以我们需要在每首歌播放之前把它清空一下,以得到这首歌的准确解码时间。
HDAT0和HDTA1是两个数据流头寄存器,不同的音频文件,读出来的值意义不一样,我们可以通过这两个寄存器来获取音频文件的码率,从而可以计算音频文件的总长度。这两个寄存器的详细介绍,请参考VS1053的数据手册。
最后我们介绍一下VOL这个寄存器,该寄存器用于控制VS1053的输出音量,该寄存器可以分别控制左右声道的音量,每个声道的控制范围为0~254,每个增量代表0.5db的衰减,所以该值越小,代表音量越大。比如设置为0X0000则音量最大,而设置为0XFEFE则音量最小。注意:如果设置VOL的值为0XFFFF,将使芯片进入掉电模式!
关于VS1053的介绍,我们就介绍到这里,更详细的介绍请看VS1053的数据手册。接下来我们说说如何控制通过最简单的步骤,来控制VS1053播放一首歌曲。
1) 复位VS1053
这里包括了硬复位和软复位,是为了让VS1053的状态回到原始状态,准备解码下一首歌曲。这里建议大家在每首歌曲播放之前都执行一次硬件复位和软件复位,以便更好的播放音乐。
2) 配置VS1053的相关寄存器
这里我们配置的寄存器包括VS1053的模式寄存器(MODE)、时钟寄存器(CLOCKF)、音调寄存器(BASS)、音量寄存器(VOL)等。
3) 发送音频数据
当经过以上两步配置以后,我们剩下来要做的事情,就是往VS1053里面扔音频数据了,只要是VS1053支持的音频格式,直接往里面丢就可以了,VS1053会自动识别,并进行播放。不过发送数据要在DREQ信号的控制下有序的进行,不能乱发。这个规则很简单:只要DREQ变高,就向VS1053发送32个字节。然后继续等待DREQ变高,直到音频数据发送完。
经过以上三步,我们就可以播放音乐了。这一部分就先介绍到这里。
本章实验功能简介:开机先检测字库是否存在,如果检测无问题,则对VS1053进行RAM测试和正弦测试,测试完后开始循环播放SD卡MUSIC文件夹里面的歌曲(必须在SD卡根目录建立一个MUSIC文件夹,并存放歌曲在里面),在TFTLCD上显示歌曲名字、播放时间、歌曲总时间、歌曲总数目、当前歌曲的编号等信息。KEY0用于选择下一曲,KEY2用于选择上一曲,WK_UP和KEY1用来调节音量。DS0还是用于指示程序运行状态,DS1用于指示VS1053正在初始化。
本实验用到的资源如下:
1) 指示灯DS0和DS1
2) 四个按键(WK_UP/KEY0/KEY1/KEY2)
3) 串口
4) TFTLCD模块
5) SD卡
6) SPI FLASH
7) VS1053
8) 74HC4052
9) TDA1308
这些硬件我们都已经介绍过了,其中74HC4052和TDA1308分别是用作音频选择和耳机驱动,在第四十章,我们已经介绍过。本章,我们使用的VS1053同STM32的连接关系详见表49.1.1。
本实验,大家需要准备1个SD卡(在里面新建一个MUSIC文件夹,并存放一些歌曲在MUSIC文件夹下)和一个耳机,分别插入SD卡接口和耳机接口,然后下载本实验就可以通过耳机来听歌了。
打开上一章的工程,首先在HARDWARE文件夹所在的文件夹下新建一个APP的文件夹。在该文件夹里面新建mp3player.c和mp3player.h两个文件。并将APP文件夹加入头文件包含路径。
然后在HARDWARE文件夹下新建一个VS10XX的文件夹,在该文件夹里面新建VS10XX.c、VS10XX.h和flac.h等三个文件。
首先打开VS10XX.c,里面的代码我们不一一贴出了,这里挑几个重要的函数给大家介绍一下,首先要介绍的是VS_Soft_Reset,该函数用于软复位VS1003,其代码如下:
void VS_Soft_Reset(void)
{
u8 retry=0;
while(VS_DQ==0); //等待软件复位结束
VS_SPI_ReadWriteByte(0Xff);//启动传输
retry=0;
while(VS_RD_Reg(SPI_MODE)!=0x0800)// 软件复位,新模式
{
VS_WR_Cmd(SPI_MODE,0x0804);// 软件复位,新模式
delay_ms(2);//等待至少1.35ms
if(retry++>100)break;
}
while(VS_DQ==0);//等待软件复位结束
retry=0;
while(VS_RD_Reg(SPI_CLOCKF)!=0X9800)//设置VS10XX的时钟,3倍频 ,1.5xADD
{
VS_WR_Cmd(SPI_CLOCKF,0X9800);//设置VS10XX的时钟,3倍频 ,1.5xADD
if(retry++>100)break;
}
delay_ms(20);
}
非常抱歉,由于编辑器篇幅所限,剩下内容,请看附件。
文章评论(0条评论)
登录后参与讨论