/** * @brief Initializes the SPIx peripheral according to the specified * parameters in the I2S_InitStruct. * @param SPIx: where x can be 2 or 3 to select the SPI peripheral * (configured in I2S mode). * @param I2S_InitStruct: pointer to an I2S_InitTypeDef structure that * contains the configuration information for the specified SPI peripheral * configured in I2S mode. * @note * The function calculates the optimal prescaler needed to obtain the most * accurate audio frequency (depending on the I2S clock source, the PLL values * and the product configuration). But in case the prescaler value is greater * than 511, the default value (0x02) will be configured instead. * * @retval None */ void I2S_Init(SPI_TypeDef* SPIx, I2S_InitTypeDef* I2S_InitStruct) { uint16_t tmpreg = 0, i2sdiv = 2, i2sodd = 0, packetlength = 1; uint32_t tmp = 0; RCC_ClocksTypeDef RCC_Clocks; uint32_t sourceclock = 0; /* 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; 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) { i2sodd = (uint16_t)0; i2sdiv = (uint16_t)2; } /* 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) { /* Packet length is 16 bits */ packetlength = 1; } else { /* Packet length is 32 bits */ packetlength = 2; } /* Get the I2S clock source mask depending on the peripheral number */ if(((uint32_t)SPIx) == SPI2_BASE) { /* The mask is relative to I2S2 */ tmp = I2S2_CLOCK_SRC; } else { /* The mask is relative to I2S3 */ tmp = I2S3_CLOCK_SRC; } /* Check the I2S clock source configuration depending on the Device: Only Connectivity line devices have the PLL3 VCO clock */ #ifdef STM32F10X_CL if((RCC->CFGR2 & tmp) != 0) { /* Get the configuration bits of RCC PLL3 multiplier */ tmp = (uint32_t)((RCC->CFGR2 & I2S_MUL_MASK) >> 12); /* Get the value of the PLL3 multiplier */ if((tmp > 5) && (tmp < 15)) { /* Multiplier is between 8 and 14 (value 15 is forbidden) */ tmp += 2; } else { if (tmp == 15) { /* Multiplier is 20 */ tmp = 20; } } /* Get the PREDIV2 value */ sourceclock = (uint32_t)(((RCC->CFGR2 & I2S_DIV_MASK) >> 4) + 1); /* Calculate the Source Clock frequency based on PLL3 and PREDIV2 values */ sourceclock = (uint32_t) ((HSE_Value / sourceclock) * tmp * 2); } else {
/******************************************************************************* * 函数名称: I2S_Init * 功能描述: 根据SPI_InitStruct.中的特定参数初始化SPIx外设. * 输入参数: (1)SPIx :x为1,2或3用于选定SPI外设(配置I2S 模式)。 * (2)I2S_InitStruct:指向一个在模式I2S包含特定SPI外设配置信息的SPI_InitTypeDef结构体的指针。 * 输出参数: 无 * 返回参数: 无 ******************************************************************************/ 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 [检查I2S参数]*/ 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 [清I2SMOD, I2SE, I2SCFG, PCMSYNC, I2SSTD, CKPOL, DATLEN 和CHLEN标志] */ SPIx->I2SCFGR &= I2SCFGR_CLEAR_Mask; SPIx->I2SPR = 0x0002; /* Get the I2SCFGR register value [取得I2SCFGR值]*/ tmpreg = SPIx->I2SCFGR; /* If the default value has to be written, reinitialize i2sdiv and i2sodd[如果默认值已经写了,重新初始化i2sdiv和i2sodd]*/ if(I2S_InitStruct->I2S_AudioFreq == I2S_AudioFreq_Default) { i2sodd = (u16)0; i2sdiv = (u16)2; } /* 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) { /* Packet length is 16 bits [包的长度16位]*/ packetlength = 1; } else { /* Packet length is 32 bits [包的长度32位]*/ packetlength = 2; } /* Get System Clock frequency [取得系统时钟频率]*/ RCC_GetClocksFreq(&RCC_Clocks); /* Compute the Real divider depending on the MCLK output state with a flaoting point 用浮点指针根据MCLK输出状态计算真实分割器*/ if(I2S_InitStruct->I2S_MCLKOutput == I2S_MCLKOutput_Enable) { /* MCLK output is enabled [MCLK输出使能]*/ tmp = (u16)(((10 * RCC_Clocks.SYSCLK_Frequency) / (256 * I2S_InitStruct->I2S_AudioFreq)) + 5); } else { /* MCLK output is disabled [MCLK输出禁止]*/ tmp = (u16)(((10 * RCC_Clocks.SYSCLK_Frequency) / (32 * packetlength * I2S_InitStruct->I2S_AudioFreq)) + 5); } /* Remove the flaoting point [删除浮点指针]*/ tmp = tmp/10; /* Check the parity of the divider [检查除数的奇偶]*/ i2sodd = (u16)(tmp & (u16)0x0001); /* Compute the i2sdiv prescaler [计算i2sdiv预分频器]*/ i2sdiv = (u16)((tmp - i2sodd) / 2); /* Get the Mask for the Odd bit (SPI_I2SPR[8]) register [取得(SPI_I2SPR[8])寄存器旧的标志位]*/ i2sodd = (u16) (i2sodd << 8); } /* Test if the divider is 1 or 0 [测试除数是1还是0]*/ if ((i2sdiv < 2) || (i2sdiv > 0xFF)) { /* Set the default values [设置默认值]*/ i2sdiv = 2; i2sodd = 0; } /* Write to SPIx I2SPR register the computed value [向SPIx I2SPR寄存器写入计算值]*/ SPIx->I2SPR = (u16)(i2sdiv | i2sodd | I2S_InitStruct->I2S_MCLKOutput); /* Configure the I2S with the SPI_InitStruct values [根据SPI_InitStruct值配置I2S]*/ 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]*/ SPIx->I2SCFGR = tmpreg; }
/** * @brief Initializes the SPIx peripheral according to the specified * parameters in the I2S_InitStruct. * @param SPIx: where x can be 1 to select the SPI peripheral (configured in I2S mode). * @param I2S_InitStruct: pointer to an I2S_InitTypeDef structure that * contains the configuration information for the specified SPI peripheral * configured in I2S mode. * @note This function calculates the optimal prescaler needed to obtain the most * accurate audio frequency (depending on the I2S clock source, the PLL values * and the product configuration). But in case the prescaler value is greater * than 511, the default value (0x02) will be configured instead. * @retval None */ void I2S_Init(SPI_TypeDef* SPIx, I2S_InitTypeDef* I2S_InitStruct) { uint16_t tmpreg = 0, i2sdiv = 2, i2sodd = 0, packetlength = 1; uint32_t tmp = 0; RCC_ClocksTypeDef RCC_Clocks; uint32_t sourceclock = 0; /* Check the I2S parameters */ assert_param(IS_SPI_1_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; 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) { i2sodd = (uint16_t)0; i2sdiv = (uint16_t)2; } /* 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) { /* Packet length is 16 bits */ packetlength = 1; } else { /* Packet length is 32 bits */ packetlength = 2; } /* I2S Clock source is System clock: Get System Clock frequency */ RCC_GetClocksFreq(&RCC_Clocks); /* Get the source clock value: based on System Clock value */ sourceclock = RCC_Clocks.SYSCLK_Frequency; /* Compute the Real divider depending on the MCLK output state with a floating point */ if(I2S_InitStruct->I2S_MCLKOutput == I2S_MCLKOutput_Enable) { /* MCLK output is enabled */ tmp = (uint16_t)(((((sourceclock / 256) * 10) / I2S_InitStruct->I2S_AudioFreq)) + 5); } else { /* MCLK output is disabled */ tmp = (uint16_t)(((((sourceclock / (32 * packetlength)) *10 ) / I2S_InitStruct->I2S_AudioFreq)) + 5); } /* Remove the floating point */ tmp = tmp / 10; /* Check the parity of the divider */ i2sodd = (uint16_t)(tmp & (uint16_t)0x0001); /* Compute the i2sdiv prescaler */ i2sdiv = (uint16_t)((tmp - i2sodd) / 2); /* Get the Mask for the Odd bit (SPI_I2SPR[8]) register */ i2sodd = (uint16_t) (i2sodd << 8); } /* Test if the divider is 1 or 0 or greater than 0xFF */ if ((i2sdiv < 2) || (i2sdiv > 0xFF)) { /* Set the default values */ i2sdiv = 2; i2sodd = 0; } /* Write to SPIx I2SPR register the computed value */ SPIx->I2SPR = (uint16_t)(i2sdiv | (uint16_t)(i2sodd | (uint16_t)I2S_InitStruct->I2S_MCLKOutput)); /* Configure the I2S with the SPI_InitStruct values */ tmpreg |= (uint16_t)(SPI_I2SCFGR_I2SMOD | (uint16_t)(I2S_InitStruct->I2S_Mode | \ (uint16_t)(I2S_InitStruct->I2S_Standard | (uint16_t)(I2S_InitStruct->I2S_DataFormat | \ (uint16_t)I2S_InitStruct->I2S_CPOL)))); /* Write to SPIx I2SCFGR */ SPIx->I2SCFGR = tmpreg; }
/** * @brief Initializes the I2S according to the specified parameters * in the I2S_InitTypeDef and create the associated handle. * @param hi2s: pointer to a I2S_HandleTypeDef structure that contains * the configuration information for I2S module * @retval HAL status */ __weak HAL_StatusTypeDef HAL_I2S_Init(I2S_HandleTypeDef *hi2s) { uint32_t tmpreg = 0, i2sdiv = 2, i2sodd = 0, packetlength = 1; uint32_t tmp = 0, i2sclk = 0; /* Check the I2S handle allocation */ if(hi2s == NULL) { return HAL_ERROR; } /* Check the I2S parameters */ assert_param(IS_I2S_ALL_INSTANCE(hi2s->Instance)); assert_param(IS_I2S_MODE(hi2s->Init.Mode)); assert_param(IS_I2S_STANDARD(hi2s->Init.Standard)); assert_param(IS_I2S_DATA_FORMAT(hi2s->Init.DataFormat)); assert_param(IS_I2S_MCLK_OUTPUT(hi2s->Init.MCLKOutput)); assert_param(IS_I2S_AUDIO_FREQ(hi2s->Init.AudioFreq)); assert_param(IS_I2S_CPOL(hi2s->Init.CPOL)); assert_param(IS_I2S_CLOCKSOURCE(hi2s->Init.ClockSource)); if(hi2s->State == HAL_I2S_STATE_RESET) { /* Allocate lock resource and initialize it */ hi2s->Lock = HAL_UNLOCKED; /* Init the low level hardware : GPIO, CLOCK, CORTEX...etc */ HAL_I2S_MspInit(hi2s); } hi2s->State = HAL_I2S_STATE_BUSY; /*----------------------- SPIx I2SCFGR & I2SPR Configuration ---------------*/ /* Clear I2SMOD, I2SE, I2SCFG, PCMSYNC, I2SSTD, CKPOL, DATLEN and CHLEN bits */ hi2s->Instance->I2SCFGR &= ~(SPI_I2SCFGR_CHLEN | SPI_I2SCFGR_DATLEN | SPI_I2SCFGR_CKPOL | \ SPI_I2SCFGR_I2SSTD | SPI_I2SCFGR_PCMSYNC | SPI_I2SCFGR_I2SCFG | \ SPI_I2SCFGR_I2SE | SPI_I2SCFGR_I2SMOD); hi2s->Instance->I2SPR = 0x0002; /* Get the I2SCFGR register value */ tmpreg = hi2s->Instance->I2SCFGR; /* If the default frequency value has to be written, reinitialize i2sdiv and i2sodd */ /* If the requested audio frequency is not the default, compute the prescaler */ if(hi2s->Init.AudioFreq != I2S_AUDIOFREQ_DEFAULT) { /* Check the frame length (For the Prescaler computing) *******************/ if(hi2s->Init.DataFormat != I2S_DATAFORMAT_16B) { /* Packet length is 32 bits */ packetlength = 2; } /* Get I2S source Clock frequency ****************************************/ /* If an external I2S clock has to be used, the specific define should be set in the project configuration or in the stm32f4xx_conf.h file */ i2sclk = I2S_GetInputClock(hi2s); /* Compute the Real divider depending on the MCLK output state, with a floating point */ if(hi2s->Init.MCLKOutput == I2S_MCLKOUTPUT_ENABLE) { /* MCLK output is enabled */ tmp = (uint32_t)(((((i2sclk / 256) * 10) / hi2s->Init.AudioFreq)) + 5); } else { /* MCLK output is disabled */ tmp = (uint32_t)(((((i2sclk / (32 * packetlength)) *10 ) / hi2s->Init.AudioFreq)) + 5); } /* Remove the flatting point */ tmp = tmp / 10; /* Check the parity of the divider */ i2sodd = (uint32_t)(tmp & (uint32_t)1); /* Compute the i2sdiv prescaler */ i2sdiv = (uint32_t)((tmp - i2sodd) / 2); /* Get the Mask for the Odd bit (SPI_I2SPR[8]) register */ i2sodd = (uint32_t) (i2sodd << 8); } /* Test if the divider is 1 or 0 or greater than 0xFF */ if((i2sdiv < 2) || (i2sdiv > 0xFF)) { /* Set the default values */ i2sdiv = 2; i2sodd = 0; } /* Write to SPIx I2SPR register the computed value */ hi2s->Instance->I2SPR = (uint32_t)((uint32_t)i2sdiv | (uint32_t)(i2sodd | (uint32_t)hi2s->Init.MCLKOutput)); /* Configure the I2S with the I2S_InitStruct values */ tmpreg |= (uint32_t)(SPI_I2SCFGR_I2SMOD | hi2s->Init.Mode | hi2s->Init.Standard | hi2s->Init.DataFormat | hi2s->Init.CPOL); #if defined(SPI_I2SCFGR_ASTRTEN) if (hi2s->Init.Standard == I2S_STANDARD_PCM_SHORT) { /* Write to SPIx I2SCFGR */ hi2s->Instance->I2SCFGR = tmpreg | SPI_I2SCFGR_ASTRTEN; } else { /* Write to SPIx I2SCFGR */ hi2s->Instance->I2SCFGR = tmpreg; } #else /* Write to SPIx I2SCFGR */ hi2s->Instance->I2SCFGR = tmpreg; #endif hi2s->ErrorCode = HAL_I2S_ERROR_NONE; hi2s->State= HAL_I2S_STATE_READY; return HAL_OK; }
/** * @brief Initializes the I2S according to the specified parameters * in the I2S_InitTypeDef and create the associated handle. * @param hi2s: pointer to a I2S_HandleTypeDef structure that contains * the configuration information for I2S module * @retval HAL status */ HAL_StatusTypeDef HAL_I2S_Init(I2S_HandleTypeDef *hi2s) { uint32_t i2sdiv = 2, i2sodd = 0, packetlength = 1; uint32_t tmp = 0, i2sclk = 0; /* Check the I2S handle allocation */ if(hi2s == NULL) { return HAL_ERROR; } /* Check the I2S parameters */ assert_param(IS_I2S_ALL_INSTANCE(hi2s->Instance)); assert_param(IS_I2S_MODE(hi2s->Init.Mode)); assert_param(IS_I2S_STANDARD(hi2s->Init.Standard)); assert_param(IS_I2S_DATA_FORMAT(hi2s->Init.DataFormat)); assert_param(IS_I2S_MCLK_OUTPUT(hi2s->Init.MCLKOutput)); assert_param(IS_I2S_AUDIO_FREQ(hi2s->Init.AudioFreq)); assert_param(IS_I2S_CPOL(hi2s->Init.CPOL)); if(hi2s->State == HAL_I2S_STATE_RESET) { /* Allocate lock resource and initialize it */ hi2s->Lock = HAL_UNLOCKED; /* Init the low level hardware : GPIO, CLOCK, CORTEX...etc */ HAL_I2S_MspInit(hi2s); } hi2s->State = HAL_I2S_STATE_BUSY; /* If the default value has to be written, reinitialize i2sdiv and i2sodd*/ if(hi2s->Init.AudioFreq == I2S_AUDIOFREQ_DEFAULT) { i2sodd = (uint32_t)0; i2sdiv = (uint32_t)2; } /* If the requested audio frequency is not the default, compute the prescaler */ else { /* Check the frame length (For the Prescaler computing) *******************/ if(hi2s->Init.DataFormat == I2S_DATAFORMAT_16B) { /* Packet length is 16 bits */ packetlength = 1; } else { /* Packet length is 32 bits */ packetlength = 2; } /* Get the source clock value: based on System Clock value */ i2sclk = HAL_RCC_GetSysClockFreq(); /* Compute the Real divider depending on the MCLK output state, with a floating point */ if(hi2s->Init.MCLKOutput == I2S_MCLKOUTPUT_ENABLE) { /* MCLK output is enabled */ tmp = (uint32_t)(((((i2sclk / 256) * 10) / hi2s->Init.AudioFreq)) + 5); } else { /* MCLK output is disabled */ tmp = (uint32_t)(((((i2sclk / (32 * packetlength)) *10 ) / hi2s->Init.AudioFreq)) + 5); } /* Remove the flatting point */ tmp = tmp / 10; /* Check the parity of the divider */ i2sodd = (uint32_t)(tmp & (uint32_t)1); /* Compute the i2sdiv prescaler */ i2sdiv = (uint32_t)((tmp - i2sodd) / 2); /* Get the Mask for the Odd bit (SPI_I2SPR[8]) register */ i2sodd = (uint32_t) (i2sodd << 8); } /* Test if the divider is 1 or 0 or greater than 0xFF */ if((i2sdiv < 2) || (i2sdiv > 0xFF)) { /* Set the default values */ i2sdiv = 2; i2sodd = 0; } /*----------------------- SPIx I2SCFGR & I2SPR Configuration ----------------*/ /* Clear I2SMOD, I2SE, I2SCFG, PCMSYNC, I2SSTD, CKPOL, DATLEN and CHLEN bits */ /* And configure the I2S with the I2S_InitStruct values */ MODIFY_REG( hi2s->Instance->I2SCFGR, (SPI_I2SCFGR_CHLEN | SPI_I2SCFGR_DATLEN |\ SPI_I2SCFGR_CKPOL | SPI_I2SCFGR_I2SSTD |\ SPI_I2SCFGR_PCMSYNC | SPI_I2SCFGR_I2SCFG |\ SPI_I2SCFGR_I2SE | SPI_I2SCFGR_I2SMOD),\ (SPI_I2SCFGR_I2SMOD | hi2s->Init.Mode |\ hi2s->Init.Standard | hi2s->Init.DataFormat |\ hi2s->Init.CPOL)); /* Write to SPIx I2SPR register the computed value */ hi2s->Instance->I2SPR = (uint32_t)((uint32_t)i2sdiv | (uint32_t)(i2sodd | (uint32_t)hi2s->Init.MCLKOutput)); hi2s->ErrorCode = HAL_I2S_ERROR_NONE; hi2s->State= HAL_I2S_STATE_READY; return HAL_OK; }