I2S(也叫IIS,即:Inter IC Sound)总线, 又称集成电路内置音频总线,是飞利浦公司为数字音频设备之间的音频数据传输而制定的一种总线标准,该总线专责于音频设备之间的数据传输,广泛应用于各种多媒体系统。它采用了沿独立的导线传输时钟与数据信号的设计,通过将数据和时钟信号分离,避免了因时差诱发的失真,为用户节省了购买抵抗音频抖动的专业设备的费用。
F4的I2S特点
●支持全双工/半双工通信
●支持主/从模式设置
●8位可编程线性预分频器,可实现精确的音频采样频率(8~192Khz)
●支持16位/24位/32位数据格式
●数据包帧固定为16位(仅16位数据帧)或32位(可容纳16/24/32位数据帧)
●可编程时钟极性
●支持MSB对齐(左对齐)、LSB对齐(右对齐)、飞利浦标准和PCM标准等I2S标准
●支持DMA数据传输(16位宽)
●数据方向固定位MSB在前
●支持主时钟输出(固定为256*fs,fs即音频采样率)
F4的I2S框图
STM32F4的I2S是与SPI部分共用的,通过设置SPI_I2SCFGR寄存器的I2SMOD位即可开启I2S功能,I2S接口使用了几乎与SPI相同的引脚、标志和中断。
I2S用到的信号有:
1,SD:串行数据(映射到 MOSI 引脚),用于发送或接收两个时分复用的数据通道上的数据(仅半双工模式)。
2,WS:字选择(映射到NSS引脚),即左右时钟,用于切换左右声道的数据。WS频率等于音频信号采样率(fs)。
3,CK:串行时钟(映射到SCK引脚),即位时钟,是主模式下的串行时钟输出以及从模式下的串行时钟输入。CK频率=WS频率(fs)216(16位宽),如果是32位宽,则是:CK频率=WS频率(fs)232(32位宽)。
4,I2S2ext_SD和I2S3ext_SD:用于控制I2S全双工模式的附加串行数据引脚(映射到MISO引脚),这两个引脚仅用于全双工模式。
5,MCK:即主时钟输出,当I2S配置为主模式(且SPI_I2SPR寄存器的MCKOE位置1)时,使用此时钟,该时钟频率为 256×fs,fs:音频信号采样频率。
STM32F4为支持I2S全双工模式,除了I2S2和I2S3,还可以使用两个额外的I2S,它们称为扩展I2S(I2S2_ext、I2S3_ext),其框图为:
扩展I2S (I2Sx_ext)只能用于全双工模式。I2Sx_ext始终在从模式下工作。I2Sx和I2Sx_ext 均可用于发送和接收。
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位数据帧。
STM32F4的I2S支持4种帧标准,分别是:
1,飞利浦标准;
2,MSB 对齐(左对齐)标准;
3,LSB 对齐(右对齐)标准;
4,PCM标准;
I2S飞利浦标准
I2S飞利浦标准24位数据,32位帧格式波形图:
I2S飞利浦标准,使用WS信号来指示当前正在发送的数据所属的通道。该信号从当前通道数据的第一个位(MSB)之前的一个时钟开始有效。发送方在时钟信号(CK)的下降沿改变数据,接收方在上升沿读取数据。WS信号也在CK的下降沿变化。
在24位模式下数据传输,需要对SPI_DR执行两次读取或写入操作。比如要发送0X8EAA33这个数据,就要分两次写入SPI_DR,第一次写入:0X8EAA,第二次写入0X33xx(xx可以为任意数值),这样就把0X8EAA33发送出去了。
注意:从SD卡读取到的24位WAV数据流,是低字节在前,高字节在后的,比如,我们读到一个声道的数据(24bit),存储在buf[3]里面,那么要通过SPI_DR发送这个24位数据,过程如下:
SPI_DR=((u16)buf[2]<<8)+buf[1];
SPI_DR=(u16)buf[0]<<8;
这样,第一次发送高16位数据,第二次发送低8位数据,完成一次24bit数据的发送。
STM32F4的I2S时钟发生器,其架构如下图:
上图中的I2SxCLK,可以来自PLLI2S输出(通过R系数分频)或者来自外部时钟(I2S_CKIN引脚),一般我们使用前者作为I2SxCLK输入时钟。
我们需要根据音频采样率(fs)来计算各个分频器的值,常用的音频采样率有:22.05Khz、44.1Khz、48Khz、96Khz、196Khz等。
当MCK输出使能时,fs频率计算公式如下:
fs=I2SxCLK/[256*(2I2SDIV+ODD)]
其中:I2SxCLK=(HSE/pllm)PLLI2SN/PLLI2SR。HSE我们是8Mhz,而pllm在系统时钟初始化就确定了,是8,这样结合以上2式,可得计算公式如下:
fs= (1000PLLI2SN/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对应系数表如下:
//表格式:采样率/10,PLLI2SN,PLLI2SR,I2SDIV,ODD
const u16 I2S_PSC_TBL[][5]=
{
{800 ,256,5,12,1}, //8Khz采样率
{1102,429,4,19,0}, //11.025Khz采样率
{1600,213,2,13,0}, //16Khz采样率
{2205,429,4, 9,1}, //22.05Khz采样率
{3200,213,2, 6,1}, //32Khz采样率
{4410,271,2, 6,0}, //44.1Khz采样率
{4800,258,3, 3,1}, //48Khz采样率
{8820,316,2, 3,1}, //88.2Khz采样率
{9600,344,2, 3,1}, //96Khz采样率
{17640,361,2,2,0}, //176.4Khz采样率
{19200,393,2,2,0}, //192Khz采样率
};
I2SMOD位,设置为1,选择I2S模式,注意,必须在I2S/SPI禁止的时候,设置该位。
I2SE位,设置为1,使能I2S外设,该位必须在I2SMOD位设置之后再设置。
I2SCFG[1:0]位, 这两个位用于配置I2S模式,设置为10,选择主模式(发送)。
I2SSTD[1:0]位,这两个位用于选择I2S标准,设置为00,选择飞利浦标准。
CKPOL位,用于设置空闲时时钟电平,设置为0,空闲时时钟低电平。
DATLEN[1:0]位,用于设置数据长度,00,表示16位数据;01表示24位数据。
CHLEN位,用于设置通道长度,即帧长度,0,表示16位;1,表示32位。
SPI_I2S预分频器寄存器(SPI_I2SSPR)
本例程我们设置MCKOE为1,开启MCK输出,ODD和I2SDIV则根据不同的fs,查表进行设置。
PLLI2S配置寄存器(RCC_PLLI2SCFGR)
该寄存器用于配置PLLI2SR和PLLI2SN两个系数,PLLI2SR的取值范围是:27,PLLI2SN的取值范围是:192432。同样,这两个也是根据fs的值来设置的。
此外,还要用到SPI_CR2寄存器的bit1位,设置I2S TX DMA数据传输,SPI_DR寄存器用于传输数据,本例程用DMA来传输,所以设置DMA的外设地址为SPI_DR即可。
初始化步骤
1)初始化WM8978
这个过程就是配置第一讲介绍的WM8978那十几个寄存器,包括软复位、DAC设置、输出设置和音量设置等。
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的耳机和喇叭通道听到所播放音乐了。
探索者STM32F407开发板,板载了WM8978芯片,硬件连接原理图如下:
I2S_MCLK和DCMI_D0共用PC6,需要分时复用!