I2S_Mode_SlaveTx I2S_Mode_SlaveRx I2S_Mode_MasterTx I2S_Mode_MasterRx 从模式发送 从模式接收 主模式发送 主模式接收 0x0000 0x0100 0x0200 0x0300 [2]、I2S_Standard:I2S标准选择 Table.03-2 I2S 标准选择值如下表
I2S_Standard I2S_Standard_MSB I2S_Standard_LSB I2S_Standard_PCMLong 意义/I2SCFGR 左<高位>对齐标准 右<低位>对齐标准 PCM模式下的长帧同步 #define 0x0000 0x0010 0x0020 0x0030 0x00B0 单位或组合意义 bit5-4 = I2SSTD =0b00 bit5-4 = I2SSTD =0b01 bit5-4 = I2SSTD =0b10 I2SSTD=11(bit5-4/PCM标准)下,PMCSYNC(bit7)才有意义:0-短帧同步,1-短帧同步 I2S_Standard_Phillips I2S飞利浦标准 I2S_Standard_PCMShort PCM模式下的短帧同步 [3]、I2S_DataFormat:设定通道数据长度值 Table.03-3通道数据长度
I2S_DataFormat I2S_DataFormat_16b 意义/I2SCFGR 待传输数据长度16位 #define 0x0000 单位或组合意义 bit0(CHLEN)=0:通道数据长度固定为16位。 bit2-1(DATLEN)为任何值都是16位数据。 bit0=1(32位位宽): bit2-1=00—16位扩展数据 bit2-1=01—24位数据 bit2-1=10—32位数据 bit2-1=11—保留 I2S_DataFormat_16bextended 待传输数据长度扩展16位 0x0001 I2S_DataFormat_24b 待传输数据长度24位 0x0003 I2S_DataFormat_32b 待传输数据长度32位 0x0005 上述“扩展16位”、“24位”、“32位”表示数据以32位包的形式传输。由CHLEN = 1(32位包)决定。对于“扩展16位”,数据16位放在32位包的MSB处,后16位LSB强制位0填充;对于“24位”、“32位”,放在MSB除,LSB也强制填充为0,发送时分2次发送。 [4]、I2S_MCLKOutput:主设备时钟输出使能 Table.03-4主设备时钟输出使能
I2S_MCLKOutput I2S_MCLKOutput_Enable 意义/I2SPR.bit9 使能主设备时钟输出 #define 0x0200 I2S_MCLKOutput_Disable 关闭主设备时钟输出 0x0000 [5]、I2S_AudioFreq:从定义的音频通道采样频率计算出I2SDIV[7:0]的值。 Table.03-5音频通道采样频率
I2S_AudioFreq I2S_AudioFreq_48k I2S_AudioFreq_44k I2S_AudioFreq_22k I2S_AudioFreq_16k I2S_AudioFreq_8k 意义:实际目标值[Fs] 通道数据频率48KHz 通道数据频率44.1KHz 通道数据频率16KHz 通道数据频率8KHz 目标频率值 (u16)48000 (u16)44100 (u16)16000 (u16)8000 (u16)2 获取I2SDIV值的方法 I2S的音频采样频率[Fs]: 通过RCC_GetClocksFreq()获取系统时间,然后根据I2SPR的ODD位及I2SDIV位,计算出填入I2SDIV[7:0]内的线性分频值。而不是直接把“目标频率值”直接填入I2SDIV[7:0]内。 同时I2SDIV的最终值,要受MCKOE控制。 通道数据频率22.05KHz (u16)22050 I2S_AudioFreq_Default 通道数据频率2Hz 下图是I2S时钟发生器的结构图
线性分频器需要按照以下的公式来设置,以获得需要的频率:
1、当需要生成主时钟时(寄存器SPI->I2SPR的MCKOE =‘1’) :
A、声道的帧长为16位时,Fs = I2SxCLK / [(16*2) * ((2*I2SDIV) + ODD)*8]
B、声道的帧长为32位时,Fs = I2SxCLK / [(32*2) * ((2*I2SDIV) + ODD)*4]
即:在MCKOE=1时,不管声道帧长为16位或32或,固定Fs= I2SxCLK / [256 * ((2*I2SDIV) + ODD)] 2、当关闭主时钟时(MCKOE =‘0’) :
A、声道的帧长为16位时,Fs = I2SxCLK / [(16*2) * ((2*I2SDIV) + ODD)] B、声道的帧长为32位时,Fs = I2SxCLK / [(32*2) * ((2*I2SDIV) + ODD)] 上述
1、I2SxCLK 的时钟源是系统时钟(即驱动AHB时钟的HSI、HSE或PLL )
2、第一个“2”表示左右声道; 3、“(2*I2SDIV) + ODD”表示I2SPR内bit8-0控制关系;
4、“16”或“32”表示帧长度,指的是I2SCFGR.CHLEN控制下的位宽;
5、“8”或“4”表示“I2S主时钟可以输出到外部音频设备,比率固定为256*Fs”模式下的256对齐系数。 6、Fs = 音频通道采样频率(参看I2S_AudioFreq取值); 7、I2SxCLK为I2Sx的外设时钟。 而:
I2S 的比特率即确定了在I2S 数据线上的数据流和I2S的时钟信号频率。 I2S比特率 = 每个声道的比特数 × 声道数目 × 音频采样频率 对于一个左右声道,16位音频,I2S比特率计算为:I2S 比特率 = 16 × 2 × Fs 如果包长为32位,则有:I2S 比特率 = 32 × 2 × Fs
[6]、I2S_CPOL:I2S静止态时钟极性:为高电平还是位低电平。 Table.03-6 空闲状态下,时钟的电平取值
I2S_CPOL I2S_CPOL_Low 描述/I2SCFGR.bit3 #define I2S时钟静止态为低电平 ((u16)0x0000) I2S_CPOL_High I2S时钟静止态为高电平 ((u16)0x0008) 在调用本函数之前,必须对上述结构体成员进行数据初始化设置。 函数原型如下:
void I2S_Init(SPI_TypeDef* SPIx, I2S_InitTypeDef* I2S_InitStruct) {
u16 tmpreg = 0, i2sdiv = 2, i2sodd = 0, packetlength = 1; u32 tmp = 0;
RCC_ClocksTypeDef RCC_Clocks;
/* Check the I2S parameters */
assert_param(IS_SPI_23_PERIPH(SPIx));
assert_param(IS_I2S_MODE(I2S_InitStruct->I2S_Mode));
assert_param(IS_I2S_STANDARD(I2S_InitStruct->I2S_Standard));
assert_param(IS_I2S_DATA_FORMAT(I2S_InitStruct->I2S_DataFormat)); assert_param(IS_I2S_MCLK_OUTPUT(I2S_InitStruct->I2S_MCLKOutput)); assert_param(IS_I2S_AUDIO_FREQ(I2S_InitStruct->I2S_AudioFreq)); assert_param(IS_I2S_CPOL(I2S_InitStruct->I2S_CPOL));
/*----------------------- SPIx I2SCFGR & I2SPR Configuration -----------------*/
/* Clear I2SMOD, I2SE, I2SCFG, PCMSYNC, I2SSTD, CKPOL, DATLEN and CHLEN bits *///全配置 SPIx->I2SCFGR &= I2SCFGR_CLEAR_Mask; //0xF040
//Bit6、Bit12-15为保留位,不改变,保持为0;
//备注:凡Mask直接清0寄存器位,保留位对应的Mask值一律保持为1,以保证不改变原0值状态。 SPIx->I2SPR = 0x0002;
/* Get the I2SCFGR register value */
tmpreg = SPIx->I2SCFGR;
/* If the default value has to be written, reinitialize i2sdiv and i2sodd*/ if(I2S_InitStruct->I2S_AudioFreq == I2S_AudioFreq_Default)//缺省频率为2Hz
{
i2sodd = (u16)0;//偶系数:Freq = i2sdiv*2。如果设置为1(奇系数),则Freq = i2sdiv*2+1 i2sdiv = (u16)2; //2分频值,结合上句,则实际时钟为2*2=4分频。
}
/* If the requested audio frequency is not the default, compute the prescaler */ else {
/* Check the frame length (For the Prescaler computing) */
if(I2S_InitStruct->I2S_DataFormat == I2S_DataFormat_16b)//通道位宽16位 {
/* Packet length is 16 bits */
packetlength = 1;//包长为1表示16位。此时,CHLEN = 0。 }
else//扩展16位?24位?32位? {
/* Packet length is 32 bits */
packetlength = 2; //包长为2表示32位。此时,CHLEN = 1。包长这里起到控制程序作用。 }
/* Get System Clock frequency */
RCC_GetClocksFreq(&RCC_Clocks);//来源于SYSCLK(AHB)—HSI? PLLCLK? HSE?
/* Compute the Real divider depending on the MCLK output state with a flaoting point */ if(I2S_InitStruct->I2S_MCLKOutput == I2S_MCLKOutput_Enable)//MCKOE = 1 {
/* MCLK output is enabled */
tmp = (u16)(((10 * RCC_Clocks.SYSCLK_Frequency) / (256 * I2S_InitStruct->I2S_AudioFreq)) + 5); }// RCC_Clocks.SYSCLK_Frequency = HSI或HSE或PLLCLK = 8M、16M、24M、48M、72M。 else//MCKOE = 0 {
/* MCLK output is disabled */
tmp = (u16)(((10 * RCC_Clocks.SYSCLK_Frequency) / (32 * packetlength * \\
I2S_InitStruct->I2S_AudioFreq)) + 5);// packetlength* AudioFreq = I2S 比特率。 }
/* Remove the flaoting point */
tmp = tmp/10;
//*10、 +5、/10,以保证tmp取值为四舍五入。
//仅在(MCKOE = 1)8M时钟 48K、44.1K、22.05K取值,
// 16M时钟 48K、44.1K取值下,tmp = 1,其他取值都能保证>=2。 /* Check the parity of the divider */
i2sodd = (u16)(tmp & (u16)0x0001);//获取分频系数的奇偶性(LSB)。
/* Compute the i2sdiv prescaler */
i2sdiv = (u16)((tmp - i2sodd) / 2);//去除奇偶性后的分频值,即去掉LSB。
/* Get the Mask for the Odd bit (SPI_I2SPR[8]) register */
i2sodd = (u16) (i2sodd << 8);//把决定奇偶性的LSB位左移8位,用于控制I2SPR.ODD位。 }
/* Test if the divider is 1 or 0 */ if ((i2sdiv < 2) || (i2sdiv > 0xFF)) {
/* Set the default values */ i2sdiv = 2;
i2sodd = 0; //如果分频系数小于2或大于0xFF,都把分频系数设置为:Default、偶分频。 }
/* Write to SPIx I2SPR register the computed value */
SPIx->I2SPR = (u16)(i2sdiv | i2sodd | I2S_InitStruct->I2S_MCLKOutput);
/* Configure the I2S with the SPI_InitStruct values */
tmpreg |= (u16)(I2S_Mode_Select | I2S_InitStruct->I2S_Mode | \\
I2S_InitStruct->I2S_Standard | I2S_InitStruct->I2S_DataFormat | \\ I2S_InitStruct->I2S_CPOL);
/* Write to SPIx I2SCFGR */
SPIx->I2SCFGR = tmpreg; }
被调用函数RCC_GetClocksFreq(&RCC_Clocks);如下
/*【04】函数SPI_StructInit
****************************************************************************** * Function Name : SPI_StructInit
* Description : Fills each SPI_InitStruct member with its default value. * Input : - SPI_InitStruct : pointer to a SPI_InitTypeDef structure * which will be initialized.
* Output : None * Return : None
*******************************************************************************/ Table 420. 给出了SPI_InitStruct各个成员的缺省值 Table.04-1 SPI_InitStruct缺省值
成员 SPI_Direction SPI_Mode SPI_DataSize SPI_CPOL SPI_CPHA SPI_NSS SPI_BaudRatePrescaler SPI_FirstBit 缺省值 SPI_Direction_2Lines_FullDuplex SPI_Mode_Slave SPI_DataSize_8b SPI_CPOL_Low SPI_CPHA_1Edge SPI_NSS_Hard SPI_BaudRatePrescaler_2 SPI_FirstBit_MSB SPI_CRCPolynomial 7 结构体I2S_InitTypeDef定义如下: typedef struct {
u16 I2S_Mode;
u16 I2S_Standard; u16 I2S_DataFormat; u16 I2S_MCLKOutput; u16 I2S_AudioFreq; u16 I2S_CPOL; }I2S_InitTypeDef;
例:
/* Initialize an SPI_InitTypeDef structure */ SPI_InitTypeDef SPI_InitStructure;
SPI_StructInit(&SPI_InitStructure); 函数原型如下:
void SPI_StructInit(SPI_InitTypeDef* SPI_InitStruct) {
/*--------------- Reset SPI init structure parameters values -----------------*/ /* Initialize the SPI_Direction member */
SPI_InitStruct->SPI_Direction = SPI_Direction_2Lines_FullDuplex;
/* initialize the SPI_Mode member */ SPI_InitStruct->SPI_Mode = SPI_Mode_Slave;
/* initialize the SPI_DataSize member */
SPI_InitStruct->SPI_DataSize = SPI_DataSize_8b;
/* Initialize the SPI_CPOL member */
SPI_InitStruct->SPI_CPOL = SPI_CPOL_Low;
/* Initialize the SPI_CPHA member */ SPI_InitStruct->SPI_CPHA = SPI_CPHA_1Edge;
/* Initialize the SPI_NSS member */
SPI_InitStruct->SPI_NSS = SPI_NSS_Hard;
/* Initialize the SPI_BaudRatePrescaler member */
SPI_InitStruct->SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
/* Initialize the SPI_FirstBit member */
SPI_InitStruct->SPI_FirstBit = SPI_FirstBit_MSB;
/* Initialize the SPI_CRCPolynomial member */ SPI_InitStruct->SPI_CRCPolynomial = 7; }
/*【05】函数I2S_StructInit
****************************************************************************** * Function Name : I2S_StructInit
* Description : Fills each I2S_InitStruct member with its default value. * Input : - I2S_InitStruct : pointer to a I2S_InitTypeDef structure