Electronic – Stm32f discovery internal clock

stm32

I have set up the STM32F4 discovery to generate audio with on-board codec using I2S and all is well when using the HSE external 8MHz crystal and ST clock configuration utility Excel tool.

The weirdness happens when switching to the internal HSI clock.

According to data sheet the internal clock is fixed at 16MHz suggesting that the only significant change to PLL and dividers is the PLL_M divider should be /16 for HSI instead of /8 when using crystal(HSE).

The rest of the clock settings should be the same.

After generating the system Init code with the tool the sample rate is now 83kHz not 48kHz as it is with external 8 MHz XTAL.

Is the stm32f4 internal clock 16MHz as it says in the data sheet or some other value? The only way I can get it down to the correct sample rate is use /25 for PLL_M.

I can't find any discussion on this because I imagine most users are sticking with the XTAL but I want to design my own board and wanted to reduce parts count by using internal clock. Anyone else tried to use internal clock?

Best Answer

OK I figured it out. There is a mistake in the STM32F4xx_spi.c Peripheral Driver file that doesn't allow the use of the HSI(internal clock) value needed for calculating the appropriate divider and odd values for the I2SPR register. (see the last line) I changed it to:

  i2sclk = (uint32_t)(((HSI_VALUE / pllm) * plln) / pllr);

and now it works. Hours wasted as usual!! The clock configuration tool is also wrong as it creates a message in the system_stm32F4xx.c file that states

*        To achieve the following I2S config:   |
*         - Master clock output (MCKO): ON      |
*         - Frame wide                : 16bit   |
*         - Audio sampling freq (KHz) : 48      |
*         - Error %                   : 0.0186  |
*         - Prescaler Odd factor (ODD): 0       |
*         - Linear prescaler (DIV)    : 2       |

which conflicts with the programmers reference that ODD=1 and DIV=3 for 48kHz sample rate, which is correct.

/* Get the PLLI2SN value */
plln = (uint32_t)(((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SN) >> 6) & \
                  (RCC_PLLI2SCFGR_PLLI2SN >> 6));

/* Get the PLLI2SR value */
pllr = (uint32_t)(((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SR) >> 28) & \
                  (RCC_PLLI2SCFGR_PLLI2SR >> 28));

/* Get the PLLM value */
pllm = (uint32_t)(RCC->PLLCFGR & RCC_PLLCFGR_PLLM);      

/* Get the I2S source clock value */
i2sclk = (uint32_t)(((HSE_VALUE / pllm) * plln) / pllr);