/** * @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)) { /* Multplier 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 {
/** * @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. * @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; /* 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 System Clock frequency */ RCC_GetClocksFreq(&RCC_Clocks); /* Compute the Real divider depending on the MCLK output state with a flaoting point */ if(I2S_InitStruct->I2S_MCLKOutput == I2S_MCLKOutput_Enable) { /* MCLK output is enabled */ tmp = (uint16_t)(((10 * RCC_Clocks.SYSCLK_Frequency) / (256 * I2S_InitStruct->I2S_AudioFreq)) + 5); } else { /* MCLK output is disabled */ tmp = (uint16_t)(((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 = (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 */ 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 | i2sodd | I2S_InitStruct->I2S_MCLKOutput); /* Configure the I2S with the SPI_InitStruct values */ tmpreg |= (uint16_t)(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; }