一、I2S简介
1、什么是I2S?
I2S(也叫IIS,即:Inter IC Sound)总线,又称集成电路内置音频总线,是飞利浦公司为数字音频设备之间的音频数据传输而定制的一种总线标准,该线专负责于音频设备之间的数据传输,广泛应用于各种多媒体系统。它采用了沿独立导线传输时钟与数据信号的设计,通过将数据和时钟信号分离,避免了因时诱发的失真,为用户节省了购买抵抗音频抖动的专业设备的费用。
2、STM32F4的I2S特点
1、支持全双工/半双工通信
2、支持主/从模式设置
3、8位可编程线性预分频器,可实现精确的音频采样频率(8~192Khz)
4、支持16位/32位/64位数据格式
5、数据包帧固定为16位(仅数据帧十六位)或32位(可容纳16/32/64位数据帧)
6、可编程时钟极性
7、支持MSB对齐(左对齐)、LSB(右对齐)、飞利浦标准和PCM标准等I2S标准
8、支持DMA数据输出(16位宽)
9、数据方向固定位MSB在前
10、支持主时钟输出(固定为256*fs,fs即音频采样率)
3、STM32F4的I2S框图
STM32F4的I2S是与SPI部分共用的,通过设置SPI_I2SCFGR寄存器的I2SMOD位即可开启I2S功能,I2S接口使用了几乎与SPI相同的引脚、标志和中断。
4、I2S用到的信号有:
1、SD:串行数据(映射到MOSI引脚),用于发送或接收两个分时复用的数据通道上的数据(仅半双工模式)。
2、WS:字选择(映射到NSS脚),即左右时钟,用于切换左右声道的数据。WS频率等于音频信号采样率(fs)
3、CK:串行时钟(映射到SCK引脚),即位时钟,是主模式下的串行时钟输出以及从模式下的串行模式输入。CK频率=WS频率(fs)*2*16(十六位宽),如果是32位宽,则是:CK频率=WS频率(fs)*2*32(三十二位宽)
4、I2S2ext_SD和I2S3ext_SD:用于控制I2S全双工模式的附加串行数据引脚(映射到MISO引脚),这两个引脚仅用于全双工模式。
5、MCK:即主时钟输出,当I2S配置为主模式(且SPI_I2SPR寄存器的MCKOE位置1)时,使用此时钟,该时钟频率为256×fs,fs:音频信号采样频率。
5、STM32F4的I2S全双工
STM32F4为支持I2S全双工模式,除了I2S2和I2S3,还可以使用两个额外的I2S,它们称为扩展I2S(I2S2_ext、I2S3_ext),其框图为:
扩展I2S(I2Sx_ext)只能用于全双工模式。I2Sx_ext始终在从模式下工作。I2Sx和I2Sx_ext均可用于发送和接收。
6、STM32F4的I2S帧格式
STM32F4的I2S支持4中数据和帧格式组合,分别是:
1、将16位数据封装在16位帧中;
2、将16位数据封装在32位帧中;
3、将24位数据封装在32位帧中;
4、将32位数据封装在32位帧中;
将16位数据封装在32位帧中时,前16位(MSB)为有效位,16位LSB被强制清零,无需任何软件操作或DMA请求(只需一个读/写操作)。如果应用程序选择DMA,则24位和32位数据帧需要对SPI_DR执行两次CPU读取或写入操作,或者需要两次DMA操作。24位的数据帧,硬件会将8位非有效位扩展到带有0位的32位数据帧。
7、STM32F4的帧标准
STM32F4的I2S支持4种帧标准,分别是:
1、飞利浦标准
2、MSB对齐(左对齐)标准
3、LSB对齐(右对齐)标准
4、PCM标准
8、I2S飞利浦标准:
I2S飞利浦标准24位数据,32位帧格式波形图:
I2S飞利浦标准,使用WS信号来指示当前正在发送的数据所属的通道。该信号从当前通道数据的第一个位(MSB)到来之前的一个时钟开始有效。发送方在时钟信号(CK)的下降沿改变数据,接收方在上升沿读取数据。WS信号也在CK的下降沿变化。
在24位模式下数据传输,需要对SPI_DR执行两次读取或者写入操作。比如要发送0X8EAA33这个数据,就要分两次写入SPI_DR,第一次写入:0X8EAA,第二次写入0X33xx(xx可以为任意值),这样就把0X8EAA33发出去了。
注意:从SD卡读取到的24位WAV数据流,是低字节在前,高字节在后的,比如,我们读到一个声道的数据(24bit),存储在buff[3]里面,那么要通过SPI_DR发送这个24位数据,过程如下:
SPI_DR=((u16)buf[2]<<8)+buf[1];
SPI_DR=(u16)buf[0]<<8;
这样,第一次发送高16位数据,第二次发送低8位数据,完成一次24bit数据的发送。
9、STM32F4的I2S时钟发生器
STM32F4的I2S时钟发生器,其架构如下图:
上图的I2SxCLK,可以来自PLLI2S输出(通过R系数分频)或者来自外部时钟(I2S_CKIN引脚),一般我们使用前者作为I2SxCLK输入时钟。
我们需要根据音频采样率(fs)来计算各分频器的值,常用的音频采样率有:22.05Khz、44.1Khz、48Khz、96Khz、196Khz等。
当MCK输出使能时,fs频率计算公式如下:
fs=I2SxCLK/[256*(2*I2SDIV+ODD)]
其中:I2SxCLK=(HSE/pllm)*PLLI2SN/PLLI2SR。HSE我们是8Mhz,而pllm在系统时钟初始化就确定了,是8,这样结合以上两式,可得计算公式如下:
fs=(1000*PLLI2SN/PLLI2SR)/[256*(2*I2SDIV+ODD)]
fs单位是:Khz。其中:PLLI2SN取值范围:192~432;PLLI2SR取值范围:2~7;I2SDIV取值范围:2~255;ODD取值范围:0/1。
根据以上约束条件,便可以根据fs来设置各个系数的值了,不过很多时候并不能取得和fs一摸一样的频率,只能近似等于fs,比如44.1Khz采样率,我们设置PLLI2SN=271,PLLI2SR=2,I2SDIV=6,ODD=0,得到fs=44.108073Khz,误差为:0.0183%。晶振频率决定了有时无法通过分频得到我们所要的fs,所以,某些fs如果要实现0误差,大家必须得选用外部时钟才可以。
如果要通过程序去计算这些系数的值是比较麻烦的,所以,我们事先计算好fs对应的系统值,建立一个表,这样用的时候,只需要查表取值就可以了,大大简化了代码,常用fs对应系数表如下:
二、STM32F4的I2S寄存器
1、SPI_I2S配置寄存器(SPI_I2SCFGR)
2、SPI_I2S预分频器寄存器(SPI_I2SSPR)
3、PLLI2S配置寄存器(RCC_PLLI2SCFGR)
4、PLLI2S配置寄存器(RCC_PLLI2SCFGR)
该寄存器用于配置PLLI2SR和PLLI2SN两个系数,PLLI2SR的取值范围是:2~7,PLLI2SN的取值范围是:192~432。同样,这两个也是根据fs的值来设置的。此外,还要用到SPI_CR2寄存器的bit1位,设置I2S TX DMA数据传输,SPI_DR寄存器用于传输数据。
三、初始化步骤
(一)
1、初始化WM8978
2、初始化I2S
此过程主要设置SPI_I2SCFGR寄存器,设置I2S模式、I2S标准、时钟空闲电平和数据帧长等,最后开启I2S TX DMA,使能I2S外设。
3、解析WAV文件,获取音频信号采样率和位数并设置I2S时钟分频器。
解析WAV文件,取得音频信号的采样率(fs)和位数(16位或24位),根据这两个参数,来设置I2S的时钟分频。
4、设置DMA
I2S播放音频,一般采用DMA来传输数据,这里我们用I2S2,其TX用DMA1数据流4的通道0来传输数据。并且,STM32F4的DMA具有双缓冲机制,这样可以提高效率。这里我们将DMA1数据流4设置为:双缓冲循环模式,外设和存储器都是16位宽,并开启DMA传输完成中断。
5、编写DMA传输完成中断服务函数
为了方便填充音频数据,我们使用DMA传输完成中断,每当一个缓冲数据发送完之后,硬件自动切换为下一个缓冲,同时进入中断服务函数,填充数据到发送完的这个缓冲。如下图:
6、开启DMA传输,填充数据
最后,我们就只需要开启DMA传输,然后及时填充WAV数据到DMA的两个缓存区即可。此时,就可以在WM8978的耳机和喇叭通道听到所播放的音乐了。
四、硬件连接
(I2S_MCLK和DCMI_D0共用PC6,需要分时复用。)