本帖最后由 zhuotuzi 于 2015-11-12 16:11 编辑
//表格式:采样率/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采样率 }; 有了上面的fs-系数对应表,我们可以很方便的完成I2S的时钟配置。 接下来,我们看看本章需要用到的一些相关寄存器。 首先,是SPI_I2S配置寄存器:SPI_I2SCFGR,该寄存器各位描述如图48.1.3.5所示: 图48.1.3.5 寄存器SPI_I2SCFGR各位描述 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_I2SPR,该寄存器各位描述如图48.1.3.6所示: 图48.1.3.6 寄存器SPI_ I2SPR各位描述 本章我们设置MCKOE为1,开启MCK输出,ODD和I2SDIV则根据不同的fs,查表进行设置。 第三个是PLLI2S配置寄存器:RCC_PLLI2SCFGR,该寄存器各位描述如图48.1.3.7所示: 图48.1.3.7 寄存器RCC_ PLLI2SCFGR各位描述 该寄存器用于配置PLLI2SR和PLLI2SN两个系数,PLLI2SR的取值范围是:2~7,PLLI2SN的取值范围是:192~432。同样,这两个也是根据fs的值来设置的。 此外,还要用到SPI_CR2寄存器的bit1位,设置I2S TX DMA数据传输,SPI_DR寄存器用于传输数据,本章用DMA来传输,所以直接设置DMA的外设地址位SPI_DR即可。 最后,我们看看要通过STM32F4的I2S,驱动WM8978播放音乐的简要步骤。这里需要说明一下,I2S相关的库函数申明和定义跟SPI是同文件的,在stm32f4xx_spi.c以及头文件stm32f4xx_spi.h中。具体步骤如下: 1)初始化WM8978 这个过程就是在48.1.2节最后那十几个寄存器的配置,包括软复位、DAC设置、输出设置和音量设置等。在我们实验工程中是在文件wm8978.c中,大家可以打开实验工程参考。 2)初始化I2S 此过程主要设置SPI_I2SCFGR寄存器,设置I2S模式、I2S标准、时钟空闲电平和数据帧长等,最后开启I2S TX DMA,使能I2S外设。 在库函数中初始化I2S调用的函数为: void I2S_Init(SPI_TypeDef* SPIx, I2S_InitTypeDef* I2S_InitStruct); 第一个参数比较好理解,我们来着重看下第二个参数,这里我们主要讲解结构体I2S_InitTypeDef各个成员变量的含义。结构体I2S_InitTypeDef的定义为:
typedef struct { uint16_t I2S_Mode; uint16_t I2S_Standard; uint16_t I2S_DataFormat; uint16_t I2S_MCLKOutput; uint32_t I2S_AudioFreq; uint16_t I2S_CPOL; }I2S_InitTypeDef; 第一个参数用来设置I2S的模式,也就是设置SPI_I2SCFGR寄存器的I2SCFG相关位。可以配置为主模式发送I2S_Mode_MasterTx,主模式接受I2S_Mode_MasterRx,从模式发送I2S_Mode_SlaveTx以及从模式接受I2S_Mode_SlaveRx四种模式。 第二个参数I2S_Standard用来设置I2S标准,这个前面已经讲解过。可以设置为:飞利浦标准I2S_Standard_Phillips,MSB对齐标准I2S_Standard_MSB,LSB对齐标准I2S_Standard_LSB以及PCM标准I2S_Standard_PCMShort。 第三个参数I2S_DataFormat用来设置I2S的数据通信格式。这里实际包含设置SPI_I2SCFGR寄存器的HCLEN位(通道长度)以及DATLEN位(传输的数据长度)。当我们设置为16位标准格式I2S_DataFormat_16b的时候,实际上传输的数据长度为16位,通道长度为16位。当我们设置为其他值的时候,通道长度都为32位。 第四个参数I2S_MCLKOutput用来设置是否使能主时钟输出。我们实验会使能主时钟输出。 第五个参数I2S_AudioFreq用来设置I2S频率。实际根据输入的频率值,会来计算SPI预分频寄存器SPI_I2SPR的预分频奇数因子以及I2S线性预分频器的值。这里支持10中频率: #define I2S_AudioFreq_192k ((uint32_t)192000) #define I2S_AudioFreq_96k ((uint32_t)96000) #define I2S_AudioFreq_48k ((uint32_t)48000) #define I2S_AudioFreq_44k ((uint32_t)44100) #define I2S_AudioFreq_32k ((uint32_t)32000) #define I2S_AudioFreq_22k ((uint32_t)22050) #define I2S_AudioFreq_16k ((uint32_t)16000) #define I2S_AudioFreq_11k ((uint32_t)11025) #define I2S_AudioFreq_8k ((uint32_t)8000) #define I2S_AudioFreq_Default ((uint32_t)2) 第六个参数I2S_CPOL用来设置空闲状态时钟电平,这个比较好理解。取值为高电平I2S_CPOL_High以及低电平I2S_CPOL_Low。 3)解析WAV文件,获取音频信号采样率和位数并设置I2S时钟分频器 这里,要先解析WAV文件,取得音频信号的采样率(fs)和位数(16位或32位),根据这两个参数,来设置I2S的时钟分频,这里我们用前面介绍的查表法来设置即可。这是我们单独写了一个设置频率的函数为I2S2_SampleRate_Set,我们后面程序章节会讲解。 4)设置DMA I2S播放音频的时候,一般都是通过DMA来传输数据的,所以必须配置DMA,本章我们用I2S2,其TX是使用的DMA1数据流4的通道0来传输的。并且,STM32F4的DMA具有双缓冲机制,这样可以提高效率,大大方便了我们的数据传输,本章将DMA1数据流4设置为:双缓冲循环模式,外设和存储器都是16位宽,并开启DMA传输完成中断(方便填充数据)。DMA具体配置过程请参考我们光盘工程代码,前面DMA实验我们已经讲解过DMA相关配置过程。 5)编写DMA传输完成中断服务函数 为了方便填充音频数据,我们使用DMA传输完成中断,每当一个缓冲数据发送完后,硬件自动切换为下一个缓冲,同时进入中断服务函数,填充数据到发送完的这个缓冲。过程如图48.1.3.8所示: 图
48.1.3.8 DMA双缓冲发送音频数据流框图 6)开启DMA传输,填充数据 最后,我们就只需要开启DMA传输,然后及时填充WAV数据到DMA的两个缓存区即可。此时,就可以在WM8978的耳机和喇叭通道听到所播放音乐了。操作方法为: DMA_Cmd(DMA1_Stream4,ENABLE);//开启DMA TX传输,开始播放 |