若对I2S通讯协议不了解可先阅读《I2S BUS》文档的内容学习。
关于音频编译码器WM8978请参考其规格书《WM》来了解。
Inter-IC Sount Bus(I2S)是飞利浦半导体公司(现为恩智浦半导体公司)针对数字音频设备之間的音频数据传输而制定的一种总线标准在飞利浦公司的I2S标准中,既规定了硬件接口规范也规定了数字音频数据的格式。
现实生活中嘚声音是通过一定介质传播的连续的波它可以由周期和振幅两个重要指标描述。正常人可以听到的声音频率范围为20Hz~20KHz现实存在的声音是模拟量,这对声音保存和长距离传输造成很大的困难一般的做法是把模拟量转成对应的数字量保存,在需要还原声音的地方再把数字量嘚转成模拟量输出参考图 381。
模拟量转成数字量过程一般可以分为三个过程,分别为采样、量化、编码参考图 382。用一个比源声音频率高的采样信号去量化源声音记录每个采样点的值,最后如果把所有采样点数值连接起来与源声音曲线是互相吻合的只是它不是连续的。在图中两条蓝色虚线距离就是采样信号的周期即对应一个采样频率(FS),可以想象得到采样频率越高最后得到的结果就与源声音越吻合泹此时采样数据量越越大,一般使用44.1KHz采样频率即可得到高保真的声音每条蓝色虚线长度决定着该时刻源声音的量化值,该量化值有另外┅个概念与之挂钩就是量化位数。量化位数表示每个采样点用多少位表示数据范围常用有16bit、24bit或32bit,位数越高最后还原得到的音质越好數据量也会越大。
WM8978是一个低功耗、高质量的立体声多媒体数字信号编译码器集成DAC和ADC,可以实现声音信号量化成数字量输出也可以实现數字量音频数据转换为模拟量声音驱动扬声器。这样使用WM8978芯片解决了声音与数字量音频数据转换问题并且通过配置WM8978芯片相关寄存器可以控制转换过程的参数,比如采样频率量化位数,增益、滤波等等
WM8978芯片是一个音频编译码器,但本身没有保存音频数据功能它只能接收其它设备传输过来的音频数据进行转换输出到扬声器,或者把采样到的音频数据输出到其它具有存储功能的设备保存下来该芯片与其怹设备进行音频数据传输接口就是I2S协议的音频接口。
I2S总线接口有3个主要信号但只能实现数据半双工传输,后来为实现全双工传输有些设備增加了扩展数据引脚STM32f42x系列控制器支持扩展的I2S总线接口。
(1) SD(Serial Data):串行数据线用于发送或接收两个时分复用的数据通道上的数据(仅半双工模式),如果是全双工模式该信号仅用于发送数据。
(3) CK(Serial Clock):串行时钟线也称位时钟(BCLK),数字音频的每一位数据都对应有一个CK脉冲它的频率为:2*采样频率*量化位数,2代表左右两个通道数据
另外,有时为使系统间更好地同步还要传输一个主时钟(MCK),STM32F42x系列控制器固定输出为256* FS
随着技術的发展,在统一的I2S硬件接口下出现了多种不同的数据格式,可分为左对齐(MSB)标准、右对齐(LSB)标准、I2S Philips标准另外,STM32F42x系列控制器还支持PCM(脉冲编碼调)音频传输协议下面以STM32F42x系列控制器资源解释这四个传输协议。
STM32f42x系列控制器I2S的数据寄存器只有16bit并且耳机左右声道道数据一般是紧邻传輸,为正确得到左右两个声道数据需要软件控制数据对应通道数据写入或读取。另外音频数据的量化位数可能不同,控制器支持16bit、24bit和32bit彡种数据长度因为数据寄存器是16bit的,所以对于24bit和32bit数据长度需要发送两个为此,可以产生四种数据和帧格式组合:
当使用32位数据包中的16位数据时前16位(MSB)为有效位,16位LSB被强制清零无需任何软件操作或DMA请求(只需一个读/写操作)。如果程序使用DMA传输(一般都会用)则24位和32位数據帧需要对数据寄存器执行两次DMA操作。24位的数据帧硬件会将8位非有效位扩展到带有0位的32位。对于所有数据格式和通信标准而言始终会先发送最高有效位(MSB优先)。
使用WS信号来指示当前正在发送的数据所属的通道为0时表示左通道数据。该信号从当前通道数据的第一个位(MSB)之前嘚一个时钟开始有效发送方在时钟信号(CK)的下降沿改变数据,接收方在上升沿读取数据WS信号也在SCK的下降沿变化。参考图 383为24bit数据封装在32bit幀传输波形。正如之前所说WS线频率对于采样频率FS,一个WS线周期包括发送左声道和右声道数据在图中实际需要64个CK周期来完成一次传输。
茬WS发生翻转同时开始传输数据参考图 384,为24bit数据封装在32bit帧传输波形该标准较少使用。注意此时WS为1时传输的是左声道数据,这刚好与I2S Philips标准相反
与左对齐标准类似,参考图 385为24bit数据封装在32bit帧传输波形。
PCM即脉冲编码调制模拟语音信号经过采样量化以及一定数据排列就是PCM了。WS不再作为声道数据选择它有两种模式,短帧模式和长帧模式以WS信号高电平保持时间为判别依据,长帧模式保持13个CK周期短帧模式只保持1个CK周期,可以通过相关寄存器位选择如果有多通道数据是在一个WS周期内传输完成的,传完左声道数据就紧跟发送右声道数据图 386为單声道数据16bit扩展到32bit数据帧发送波形。
STM32f42x系列控制器有两个I2SI2S2和I2S3,两个的资源是相互独立的但分别与SPI2和SPI3共用大部分资源。这样I2S2和SPI2只能选择一個功能使用I2S3和SPI3相同道理。资源共用包括引脚共用和部分寄存器共用当然也有部分是专用的。SPI已经在之前相关章节做了详细讲解建议先看懂SPI相关内容再学习I2S。
控制器的I2S支持两种工作模式主模式和从模式;主模式下使用自身时钟发生器生成通信时钟。I2S功能框图参考图 387
I2S嘚SD映射到SPI的MOSI引脚,ext_SD映射到SPI的MISO引脚WS映射到SPI的NSS引脚,CK映射到SPI的SCK引脚MCK是I2S专用引脚,用于主模式下输出时钟或在从模式下输入时钟I2S时钟发生器可以由控制器内部时钟源分频产生,亦可采用CKIN引脚输入时钟分频得到一般使用内部时钟源即可。控制器I2S引脚分布参考表 381
其中,PI0和PI1不能用于I2S的全双工模式
I2S有一个与SPI共用的SPI数据寄存器(SPI_DR),有效长度为16bit用于I2S数据发送和接收,它实际由三个部分组成一个移位寄存器、一个發送缓冲区和一个接收缓冲区,当处于发送模式时向SPI_DR写入数据先保存在发送缓冲区,总线自动把发送缓冲区内容转入到移位寄存器中进荇传输;在接收模式下实际接收到的数据先填充移位寄存器,然后自动转入接收缓冲区软件读取SPI_DR时自动从接收缓冲区内读取。I2S是挂载茬APB1总线上的
I2S的逻辑控制通过设置相关寄存器位实现,比如通过配置SPI_I2S配置寄存器(SPI_I2SCFGR)的相关位可以实现选择I2S和SPI模式切换、选择I2S工作在主模式还昰从模式并且选择是发送还是接收、选择I2S标准、传输数据长度等等SPI控制寄存器2(SPI_CR2)可用于设置相关中断和DMA请求使能,I2S有5个中断事件分别为發送缓冲区为空、接收缓冲区非空、上溢错误、下溢错误和帧错误。SPI状态寄存器(SPI_SR)用于指示当前I2S状态
I2S比特率用来确定I2S数据线上的数据流和I2S時钟信号频率。I2S比特率=每个通道的位数×通道数×音频采样频率
SPI_I2S预分频器寄存器(SPI_I2SPR)的MCKOE位用于设置MCK引脚时钟输出使能;ODD位设置预分频器的奇数洇子,实际分频值=I2SDIV*2+ODD;I2SDIV为8位线性分频器不可设置为0或1。
当使能MCK时钟输出即MCKOE=1时,采样频率计算如下:
当禁止MCK时钟输出即MCKOE=0时,采样频率计算如下:
WM8978是一个低功耗、高质量的立体声多媒体数字信号编译码器它主要应用于便携式应用。它结合了立体声差分麦克风的前置放大与揚声器、耳机和差分、立体声线输出的驱动减少了应用时必需的外部组件,比如不需要单独的麦克风或者耳机的放大器
高级的片上数芓信号处理功能,包含一个5路均衡功能一个用于ADC和麦克风或者线路输入之间的混合信号的电平自动控制功能,一个纯粹的录音或者重放嘚数字限幅功能另外在ADC的线路上提供了一个数字滤波的功能,可以更好的应用滤波比如"减少风噪声"。
WM8978可以被应用为一个主机或者一个從机基于共同的参考时钟频率,比如 12MHz和13MHz内部的PLL可以为编译码器提供所有需要的音频时钟。与STM32控制器连接使用STM32一般作为主机,WM8978作为从機
图 389为WM8978芯片内部结构示意图,参考来自《WM》该图给人的第一印象感觉就是很复杂,密密麻麻很多内容特别有很多"开关"。实际上每個开关对应着WM8978内部寄存器的一个位,通过控制寄存器的就可以控制开关的状态
WM8978结构图的左边部分是输入部分,可用于模拟声音输入即鼡于录音输入。有三个输入接口一个是由LIN和LIP、RIN和RIP组合而成的伪差分立体声麦克风输入,一个是由L2和R2组合的立体声麦克风输入还有一个昰由AUXL和AUXR组合的线输入或用来传输告警声的输入。
WM8978结构图的右边部分是声音放大输出部分LOUT1和ROUT1用于耳机驱动,LOUT2和ROUT2用于扬声器驱动OUT3和OUT4也可以配置成立体声线输出,OUT4也可以用于提供一个耳机左右声道道的单声道混合
WM8978结构图的中边部分是芯片核心内容,处理声音的AD和DA转换ADC部分對声音输入进行处理,包括ADC滤波处理、音量控制、输入限幅器/电平自动控制等等DAC部分控制声音输出效果,包括DAC5路均衡器、DAC 3D放大、DAC输出限幅以及音量控制等等处理
WM8978有两个通信接口,一个是数字音频通信接口另外一个是控制接口。音频接口是采用I2S接口支持左对齐、右对齊和I2S标准模式,以及DSP模式A和模拟B控制接口用于控制器发送控制命令配置WM8978运行状态,它提供2线或3线控制接口对于STM32控制器,我们选择2线接ロ方式它实际就是I2C总线方式,其芯片地址固定为0011010通过控制接口可以访问WM8978内部寄存器,实现芯片工作环境配置总共有58个寄存器,标示為R0至R57限于篇幅问题这里不再深入探究,每个寄存器意义参考《WM》了解
WM8978寄存器是16bit长度,高7位([15:9]bit)用于标示寄存器地址低9为有实际意义,比洳对于图 389中的某个开关所以在控制器向芯片发送控制命令时,必须传输长度为16bit的指令芯片会根据接收命令高7位值寻址。
WM8978作为主从机都必须对时钟进行管理由内部PLL单元控制。另外还有电源管理单元
WAV是微软公司开发的一种音频格式文件,用于保存Windows平台的音频信息资源咜符合资源互换文件格式(Resource Interchange File Format,RIFF)文件规范标准格式化的WAV文件和CD格式一样,也是44.1K的取样频率16位量化数字,因此在声音文件质量和CD相差无几!WAVE昰录音时用的标准的WINDOWS文件格式文件的扩展名为"WAV",数据本身的格式为PCM或压缩型属于无损音乐格式的一种。
RIFF有不同数量的chunk(区块)组成每个chunk甴"标识符"、"数据大小"和"数据"三个部分组成,"标识符"和"数据大小"都是占用4个字节空间简单RIFF格式文件结构参考图 3810。最开始是ID为"RIFF"的chunkSize为"RIFF"chunk数据字節长度,所以总文件大小为Size+8一般来说,chunk不允许内部再包含chunk但有两个例外,ID为"RIFF"和"LIST"的chunk却是允许对此"RIFF"在其"数据"首4个字节用来存放"格式标识碼(Form
WAVE文件是非常简单的一种RIFF文件,其"格式标识码"定义为WAVERIFF chunk包括两个子chunk,ID分别为fmt和data还有一个可选的fact chunk。Fmt chunk用于标示音频数据的属性包括编码方式、声道数目、采样频率、每个采样需要的bit数等等信息。fact chunk是一个可选chunk一般当WAVE文件由某些软件转化而成就包含fact
data chunk是WAVE文件主体部分,包含声音數据一般有两个编码格式:PCM和ADPCM,ADPCM(自适应差分脉冲编码调制)属于有损压缩现在几乎不用,绝大部分WAVE文件是PCM编码PCM编码声音数据可以说是茬"数字音频技术"介绍的源数据,主要参数是采样频率和量化位数
利用winhex工具软件可以非常方便以十六进制查看文件,图 3811为名为"张国荣-一盏尛明灯.wav"文件使用winhex工具打开的部分界面截图这部分截图是WAVE文件头部分,声音数据部分数据量非常大有兴趣可以使用winhex查看。
下面对文件头進行解读参考表 384。
声道数目:0x01为单声道0x02为双声道 |
每秒字节数:0x02B110,等于声道数*采样频率*量化位数/8 |
每个采样点字节数:0x04等于声道数*量化位数/8 |
图2 声音的频率(语音信号频率范围:300Hz-3kHz)
声音的传播携带了信息,它是人类传播信息的一种主要媒体 声音的三种类型:图3 声音数字化过程
图4 声音数字化过程示意圖
|
||
每秒钟抽取声波幅度样本的次数 |
|
每个采样点用多少二进制位表示数据范围 |
|
立体声比单声道的表现力丰富,但数据量翻倍 |
|
|
对于系统而言产生SCK和WS的信号端就是主设备,用MASTER表示简单系统示意图如图1所示:
图1 简单系统配置和基本接口时序
图2 I2S典型的接口时序
在IIS总线中,任何设备都可以通过提供必需的时钟信号成为系统的主设备置而从属设备通过外部时钟信号來得到它的内部时钟信号,这就意味着必须重视主设备和数据以及命令选择信号之间的传播延迟总的延迟主要由两部分组成:
1.外部时钟囷从设备的内部时钟之间的延迟
2.内部时钟和数据信号以及命令选择信号之间的延迟
对于数据和命令信号的输入,外部时钟和内部时的延迟鈈占据主导的地位它只是延长了有效的建立时间(set-up time)。延迟的主要部分是发送端的传输延迟和设置接收端所需的时间见图3和图4:
T是时钟周期,Tr是最小允许时钟周期T>Tr这样发送端和接收端才能满足数据传输速率的要求。
对于所有的数据速率发送端和接收端均发出一个具有固萣的传号空号比(mark—space ratio)的时钟信号,所以t LC和tHC是由T所定义的 t LC和tHC必须大于0.35T,这样信号在从属装置端就可以被检测到
延迟(tdtr)和最快的传输速度(由Ttr定義)是相关的,快的发送端信号在慢的时钟上升沿可能导致tdtr不能超过tRC而使thtr为零或者负只有tRC不大于tRCmax的时候(tRCmax>:0.15T),发送端才能保证thtr大于等于0
为叻允许数据在下降沿被记录,时钟信号上升沿及T相关的时间延迟应该给予接收端充分的建立时间(set-up time)
数据建立时间(set-up time)和保持时间(hold time)不能小于指定接收端的建立时间和保持时间。
Bus)是飞利浦公司针对数字音频设备の间的音频数据传输而制定的一种总线标准,采用沿独立的导线传输时钟与数据信号的设计通过分离数据和时钟信号,避免了时差诱发嘚失真I2S总线简单有效,可以有效提升输出数据的质量在各种嵌入式音频系统中有广泛应用。但是在嵌入式音频系统设计中并不是所囿的MCU都支持I2S总线格式,再加上I2S还没有统一的接口标准不同的厂家生产的设备接口也是五花八门,采用软件模拟实现I2S总线可有效解决在不支持其的MCU和设备之间通过I2S总线实现数据传输时出现的问题
本文通过在以太网数字语音广播系统中软件模拟I2S总线实现语音数据传输,给出叻软件模拟实现I2S总线的方法
I2S为三线总线,3个信号分别为:
① 串行时钟SCK也叫位时钟(BCK)。即每发送1位数字音频数据SCK上都有1个脉冲。SCK的頻率=2×采样频率×采样位数。在数据传输过程中,I2S总线的发送器和接收器都可以作为系统的主机来提供系统的时钟频率
② 帧时钟WS,即命囹(声道)选择用于切换耳机左右声道道的数据。WS的频率等于采样频率由系统主机提供。WS为“1”表示传输的是左声道的数据WS为“0”表示传输的是右声道的数据。
③ 串行数据信号SD用于传输二进制补码表示的音频数据。
I2S格式的信号无论有多少位有效数据数据位的最高位(MSB)总是被最先传输,1次能够发送的数据决定于I2S格式的有效位数
1个典型的I2S信号时序如图1所示
图1 I2S总线典型时序图
随着技术的发展,在统┅的I2S接口下出现了多种不同的数据格式根据SD信号相对于SCK和WS位置的不同,分为左对齐和右对齐2种格式如图2和图3所示。
图2 16位有效位数的左對齐格式
图3 16位有效位数的右对齐格式
在上面2种数据传输格式中当WS为“1”时传输的是左声道的数据,当WS为“0”时传输的是右声道的数据為了保证数字音频信号的正确传输,发送端和接收端必须采用相同的数据格式
以太网数字语音广播系统主要是指以以太网为传播介质提供音频服务的广播系统,将语音信号以标准IP包的形式在以太网上进行传送以实现语音广播功能。该系统在PC机端通过麦克风采集语音数据然后将采集到的语音数据通过以太网发送给嵌入式终端,嵌入式终端将接收到的语音数据进行数/模转换后进行播放系统实现框图如图4所示[5]。
图4 以太网数字语音广播系统框图
广播系统终端的MCU LM3S8962将接收到的语音数据通过I2S总线发送给语音解码芯片MS6336进行数/模转换并播放,
LM3S8962和MS6336的连接如圖5所示为了完整还原出语音信号,需要保证软件模拟I2S信号时序严格精确,高低电平的转换采用延时程序实现MS6336为16位D/A芯片,其I2S时序如图6所示
该系统中的语音数据双声道,16位采样1个采样点的数据为4字节,1个采样点数据通过MCU发送给MS6336数据发送流程如图7所示。
图7 1个采样点数据发送流程
软件模拟I2S引脚的定义如下:
根据MS6336的I2S总线格式以及数据发送流程软件模拟I2S总线的步骤如下:
① 根据语音数据采样率及采样位数计算嘚到SCK的值和WS的值(WS的值等于采样频率)。
② 将WS、BCK和DATA均置为高电平
③ 选择耳机左右声道道。首先发送左声道数据将WS置低(若发送右声道數据则将WS置高)。
else{//左声道选择信号为低电平
④ 选择高低字节将左声道数据以高低字节的顺序发送,在发送高字节第1位数据之前先发送1个周期的串行时钟
delayI2S(2);//发送第一个数据位之前需要延迟一个位时钟周期
⑤ 开始传输音频数据(音频数据的传输在SCK下降沿准备数据,在SCK的上升沿發
送给数据接收端)将采样点左声道数据的高字节最高位送给SD,设置SCK为低电平此时为SCK的下降沿,数据准备好延时半个SCK周期以后将 SCK置為高电平,此时SD线上的数据发送给数据接收端延时半个SCK周期。依次将左声道剩余位数据按照最高位的方式发送出去
delayI2S(1); //延时半个SCK时钟周期置时钟线为高,开始传输数据位
⑥ 当将1个采样点的左声道的数据发送完以后延时2个SCK周期,然后发送右声道的数据(同左声道数据的发送過程)
根据以上的过程对每个采样点的数据进行处理,就可以实现通过软件模拟I2S总线传输音频数据了以上实现的是典型I2S时序模拟,而咗对齐和右对齐2种格式只是时序稍有差异模拟实现过程同典型I2S总线模拟实现过程基本相同。
在以太网数字语音广播系统中应用软件模拟實现I2S总线时序能够成功地实现语音信号的数据传输,实现语音信号的实时广播表明了软件模拟实现 I2S总线的可行性,为解决不支持I2S总线嘚MCU和各种I2S总线设备间的通信提供了一种可行的方法但是,在应用软件模拟实现I2S的以太网数字语 音广播系统实时播放语音信号时存在一些噪声,表明在采用软件模拟实现I2S的时序精确性上存在一些欠缺
I2S(Inter-IC Sound Bus)是飞利浦公司为数字音频设备之间的音频数据传输而制定的一种总線标准。在飞利浦公司的I2S标准中既规定了硬件接口规范,也规定了数字音频数据的格式I2S有3个主要信号:
1、串行时钟SCLK,也叫位时钟BCLK即對应数字音频的每一位数据,SCLK有1个脉冲SCLK的频率=2×采样频率×采样位数。
2、帧时钟LRCK,用于切换耳机左右声道道的数据LRCK为“0”表示正在传輸的是左声道的数据,为“1”则表示正在传输的是右声道的数据LRCK的频率等于采样频率。
3、串行数据SDATA就是用二进制补码表示的音频数据。
有时为了使系统间能够更好地同步还需要另外传输一个信号MCLK,称为主时钟也叫系统时钟(Sys Clock),是采样频率的256倍或384倍
I2S 格式的信号无論有多少位有效数据,数据的最高位总是出现在LRCK变化(也就是一帧开始)后的第2个SCLK脉冲处见下面I2S格式图。这就使得接收端 与发送端的有效位数可以不同如果接收端能处理的有效位数少于发送端,可以放弃数据帧中多余的低位数据;如果接收端能处理的有效位数多于发送端可以自行 补足剩余的位。这种同步机制使得数字音频设备的互连更加方便而且不会造成数据错位。
随着技术的发展在统一的 I2S接口丅,出现了多种不同的数据格式根据SDATA数据相对于LRCK和SCLK的位置不同,分为左对齐(较少使用)、I2S格式(即飞利浦规定的格式)和右对齐(也叫日本格式、普通格式)
对非I2S格式而言,为了保证数字音频信号的正确传输发送端和接收端应该采用相同的数据格式和长度。对I2S格式來说数据长度可以不同而且帧时钟LRCK高低电平对应耳机左右声道道的意义也不同?
注意I2S总线和I2S格式的区别I2S总线是一种总线标准,I2S格式是飛利浦制定的数据格式在统一的I2S总线接口下,出现了左对齐和右对齐等非I2S格式
符。引用“如果接收端能处理的有效位数少于发送端鈳以放弃数据帧中多余的低位数据;如果接收端能处理的有效位数多于发送端,可以自行补足剩余的位”因 此这是可以解释的。
PCM(PCM-clock、PCM-sync、PCM-in、PCM-out)脉冲编码调制模拟语音信号经过采样量化以及一定数据排列就是PCM了。理论上可以传输单声道双声道立体声和多声道。是数字音频嘚raw data.
全套200集视频教程和1000页PDF教程请到秉吙论坛下载:
野火视频教程优酷观看网址:/firege
Helix解码库支持浮点和定点计算实现将该算法移植到STM32控制器运行使用定点计算实现,它支持MPEG-1、MPEG-2以忣MPEG-2.5标准的Layer3解码Helix解码库支持可变位速率、恒定位速率,以及立体声和单声道音频格式更多信息可参考网站:https://datatype.helixcommunity.org/Mp3dec。
因为Helix解码库需要占用的资源比Libmad解码库更少特别是RAM空间的使用,这对STM32控制器来说是比较重要的所以在实验工程中我们选择Helix解码库实现MP3文件解码。这两个解码库都昰一帧为解码单位的一次解码一帧,这在应用解码库时是需要着重注意的
Helix解码库涉及算法计算,整个界面过程复杂有兴趣可以深入探究,这里我们着重讲解Helix移植和使用方法
Helix网站有提供解码库代码,经过整理移植Helix解码库需要用到的的文件如图 3813。有优化解码速度部汾解码过程使用汇编实现。
在"录音与回放实验"已经实现了WM8978驱动代码现在我们可以移植Helix解码库工程中,实现MP3文件解码将解码输出的PCM数据通过I2S接口发送到WM8978芯片实现音乐播放。
我们在"录音与回放实验"工程文件基础上移植Helix解码首先将需要用到的文件添加到工程中,如图 3814MP3文件夾下文件是Helix解码库源码,工程移植中是不需要修改文件夹下代码的我们只需直接调用相关解码函数即可。建议自己移植时直接使用例程Φmp3文件夹内文件我们是在mp3Player.c文件中调用Helix解码库相关函数实现MP3文件解码的,该文件是我们自己创建的
接下来还需要在工程选项中添加Helix解码庫的文件夹路径,编译器可以寻找到相关头文件见图 3815。
"录音与回放实验"中的回放功能实际上就是从SD卡内读取WAV格式文件数据然后提取里邊音频数据通过I2S传输到WM8978芯片内实现声音播放。MP3播放器的功能也是类似的只不过现在音频数据提取方法不同,MP3需要先经过解码库解码后才鈳得到"可直接"播放的音频数据由此可以看到,MP3播放器只是添加了MP3解码库实现代码在硬件设计上并没有任何改变,即这里直接使用"录音與回放实验"中硬件设计即可
实验工程代码中创建mp3Player.c和mp3Player.h两个文件存放MP3播放器实现代码。Helix解码库是用来解码MP3数据帧一次解码一帧,它是不能鼡来检索ID3V1和ID3V2标签的如果需要获取歌名、作者等信息需要自己编程实现。解码过程可能用到的Helix解码库函数有:
MP3InitDecoder函数初始化解码器它会申請分配一个存储空间用于存放解码器状态的一个数据结构并将其初始化,该数据结构由MP3DecInfo结构体定义它封装了解码器内部运算数据信息。MP3InitDecoder函数会返回指向该数据结构的指针
MP3FindSyncWord函数用于寻址数据帧同步信息,实际上就是寻址数据帧开始的11bit都为"1"的同步信息它有两个形参,第一個为源数据缓冲区指针第二个为缓冲区大小,它会返回一个int类型变量用于指示同步字较缓冲区起始地址的偏移量,如果在缓冲区中找鈈到同步字则直接返回-1。
MP3Decode函数用于解码数据帧它有五个形参,第一个为解码器数据结构指针一般由MP3InitDecoder函数返回值赋值;第二个参数为指向解码源数据缓冲区开始地址的一个指针,注意这里是地址的指针即是指针的指针;第三个参数是一个指向存放解码源数据缓冲区有效数据量的变量指针;第四个参数是解码后输出PCM数据的指针,一般由我们定义的缓冲区地址赋值对于双声道输出数据缓冲区以LRLRLR…顺序排列;第五个参数是数据格式选择,一般设置为0表示标准的MPEG格式函数还有一个返回值,用于返回解码错误返回ERR_MP3_NONE说明解码正常。
MP3GetLastFrameInfo函数用于獲取数据帧信息它有两个形参,第一个为解码器数据结构指针一般由MP3InitDecoder函数返回值赋值;第二个参数为数据帧信息结构体指针,该结构體定义见代码清单
代码清单 3825 MP3数据帧信息结构体
该结构体成员包括了该数据帧的位率、声道、采样频率等等信息它实际上是从数据帧的帧頭信息中提取的。
35 /* 调节音量左右相同音量 */
64 //寻找帧同步,返回第一个同步字的位置
66 //没有找到同步字
81 /* 注意这个地方因为采用的是DMA读取所以┅定要4字节对齐 */
91 //开始解码参数:mp3解码结构体、输入流指针、输入流大小、输出流指针、数据格式
124 //单声道数据需要复制一份到另一个声道
133 /* 根據解码信息设置采样率 */
mp3PlayerDemo函数是MP3播放器的实现函数,篇幅很长需要我们仔细分析。它有一个形参用于指定待播放的MP3文件,需要用MP3文件的絕对路径加全名称赋值
read_ptr是定义的一个指针变量,它用于指示解码器源数据地址把它初始化为用来存放解码器源数据缓冲区(inputbuf数组)的首地址。read_offset和bytes_left主要用于MP3FindSyncWord函数read_offset用来指示帧同步相对解码器源数据缓冲区首地址的偏移量,bytes_left用于指示解码器源数据缓冲区有效数据量
mp3player是一个MP3_TYPE结构體类型变量,指示音量、状态和采样频率信息
f_open函数用于打开文件,如果文件打开失败则直接退出播放MP3InitDecoder函数用于初始化Helix解码器,分配解碼器必须内存空间如果初始化解码器失败直接退出播放。
接下来配置WM8978芯片功能使能耳机输出,设置音量使用I2S Philips标准和16bit数据长度。还要設置I2S外设工作环境同样是I2S
f_read函数从SD卡读取MP3文件数据,存放在inputbuf缓冲区中bw变量保存实际读取到的数据的字节数。如果读取数据失败则运行MP3FreeDecoder函數关闭解码器后退出播放器
接下来是循环解码帧数据并播放。MP3FindSyncWord用于选择帧同步信息如果在源数据缓冲区中找不到同步信息,read_offset值为-1需偠读取新的MP3文件数据,重新寻找帧同步信息一般MP3起始部分是ID3V2信息,所以可能需要循环几次才能寻找到帧同步信息如果找到帧同步信息說明找到数据帧,接下来数据就是数据帧的帧头以及MAIN_DATA
有时找到了帧同步信息,但可能源数据缓冲区并没有包括整帧数据这时需要把从幀同步信息开始的源数据,复制到源数据缓冲区起始地址上再使用f_read函数读取新数据填充满整个源数据缓冲区,保证源数据缓冲区保存有整帧源数据
MP3Decode函数开始对源数据缓冲区中帧数据进行解码,通过函数返回值可判断得到解码状态如果发生解码错误则执行对应的代码。
茬解码无错误时就可以使用MP3GetLastFrameInfo函数获取帧信息,如果有数据输出并且是单声道需要把数据复制成双声道数据格式如果采样频率与上一次囿所不同则执行通过串口打印帧信息到串口调试助手,可能还需要调整I2S的工作环境还调用I2S_Play_Start启动播放。因为mp3player.ucFreq缺省值为I2S_AudioFreq_Default一般都不会与Mp3FrameInfo.samprate相等,所以会至少进入if语句内即会执行I2S_Play_Start函数。
如果文件读取已经都了文件末尾就退出循环MP3文件已经播放完整。循环中还需要等待DMA数据传输唍成才进行下一帧的解码操作
MP3Player_I2S_DMA_TX_Callback函数用于在DMA发送完成后切换缓冲区。DMA数据流x配置寄存器的CT位用于指示当前目标缓冲區如果为1,当前目标缓冲区为存储器1;如果为0则为存储器0。
11 /* 初始化调试串口一般为串口1 */
21 /* 初始化系统滴答定时器 */
main函数主要完成各个外設的初始化,包括初始化禁用WIFI模块、调试串口初始化、SD卡文件系统挂载还有系统滴答定时器初始化
wm8978_Init初始化I2C接口用于控制WM8978芯片,并复位WM8978芯爿如果初始化成功则进入无限循环,执行MP3播放器实现函数mp3PlayerDemo它有一个形参,用于指定播放文件
另外,为使程序正常运行还需要适当增加控制器的栈空间见代码清单 3829,Helix解码过程需要用到较多局部变量需要调整栈空间,防止栈空间溢出
代码清单 3829 栈空间大小调整
将工程攵件夹中的"音频文件放在SD卡根目录下"文件夹的内容拷贝到Micro SD卡根目录中,把Micro SD卡插入到开发板右侧的卡槽内使用USB线连接开发板上的"USB TO UART"接口到电腦,电脑端配置好串口调试助手参数在开发板的上边沿的耳机插座(左边那个)插入耳机。编译实验程序并下载到开发板上程序运行后在串口调试助手可接收到开发板发过来的提示信息,如果没有提示错误信息则直接在耳机可听到音乐播放完后自动切换下一首,如此循环
实验主要展示MP3解码库移植过程和实现简单MP3文件播放,跟实际意义上的MP3播放器在功能上还有待完善比如快进快退功能、声音调节、音效調节等等。
7. 在MP3播放器实验例程基础上实现每过1秒通过串口打印一次当前播放时间和歌曲总时间,同时实现按键控制音量大小调节