cancel
Showing results for 
Search instead for 
Did you mean: 

What it the recommended way to obtain lots of clock switch functions?

arnold_w
Senior
Posted on May 31, 2016 at 16:28

I am working with the Discovery Development Board and a custom-made PCB with an STM32F405 microcontroller operating at 1.85 Volts. I would like to be able to easily switch clock frequency, that is, I would like to have functions called switchFreq_500_kHz, switchFreq_1_MHz, switchFreq_2_MHz, switchFreq_4_MHz, etc. I thought I had found a good way to do this, I used the makro in the STM32F4xx_Clock_Configuration_V1.1.0.xls Excel-sheet provided by ST Microelectronics and generated code and then I renamed, for example, SystemInit to SystemInit_500_kHz and SystemCoreClockUpdate to SystemCoreClockUpdate_500_kHz and to switch frequency I would call both of these functions. This works fine on the development board but after having updated the system-folder to the latest release my STM32F405 microcontroller is acting erratically and I've traced the problem to these functions. What is the proper way to create the functions I want?

12 REPLIES 12
arnold_w
Senior
Posted on June 03, 2016 at 22:55

The code above is no good. Yes, it works if you call it once after a regular power up, but I found a use case where it doesn't work. When I power up my microcontroller the bootloader will first be executed and then it will jump to my application. So far so good, but if I then go back to the bootloader (for example, for a firmware upgrade), even though I do this transition using a software reset, when the microcontroller boots up again the clock frequency is wrong. Not only that, the value of the variable SystemCoreClock doesn't match the true frequency, resulting in my peripherals running at wrong data rates. It also seems the clock frequency isn't stable after the call to ClockSwitch returns, the first 10 bytes or so I write over a UART after power-up are erroneous. So, it seems I'm back on square one again...

Posted on June 03, 2016 at 23:03

Should probably check if the functions are returning error codes

I'd transition to the 16 MHz HSI, then program the PLL, and then switch to it.

RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0);
break
;

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
arnold_w
Senior
Posted on June 13, 2016 at 13:10

Thanks for your replies and advice. The code below seems to work fine. When I concluded that things didn't work I was basing that on my software UART using wrong Baud rate, but the real problem was that my timer was using the wrong clock frequency value in its calculations.

static
uint32_t getNumWaitStates(ClockFreqType clockFreq)
{
#if VDD_VALUE < 2100
if
(((uint8_t)clockFreq) < 20) { 
return
FLASH_LATENCY_0; }
else
if
(((uint8_t)clockFreq) < 40) { 
return
FLASH_LATENCY_1; }
else
if
(((uint8_t)clockFreq) < 60) { 
return
FLASH_LATENCY_2; }
else
if
(((uint8_t)clockFreq) < 80) { 
return
FLASH_LATENCY_3; }
else
if
(((uint8_t)clockFreq) < 100) { 
return
FLASH_LATENCY_4; }
else
if
(((uint8_t)clockFreq) < 120) { 
return
FLASH_LATENCY_5; }
else
if
(((uint8_t)clockFreq) < 140) { 
return
FLASH_LATENCY_6; }
else
return
FLASH_LATENCY_7;
#elif VDD_VALUE < 2400
if
(((uint8_t)clockFreq) < 22) { 
return
FLASH_LATENCY_0; }
else
if
(((uint8_t)clockFreq) < 44) { 
return
FLASH_LATENCY_1; }
else
if
(((uint8_t)clockFreq) < 66) { 
return
FLASH_LATENCY_2; }
else
if
(((uint8_t)clockFreq) < 88) { 
return
FLASH_LATENCY_3; }
else
if
(((uint8_t)clockFreq) < 110) { 
return
FLASH_LATENCY_4; }
else
if
(((uint8_t)clockFreq) < 132) { 
return
FLASH_LATENCY_5; }
else
if
(((uint8_t)clockFreq) < 154) { 
return
FLASH_LATENCY_6; }
else
return
FLASH_LATENCY_7;
#elif VDD_VALUE < 2700
if
(((uint8_t)clockFreq) < 24) { 
return
FLASH_LATENCY_0; }
else
if
(((uint8_t)clockFreq) < 48) { 
return
FLASH_LATENCY_1; }
else
if
(((uint8_t)clockFreq) < 72) { 
return
FLASH_LATENCY_2; }
else
if
(((uint8_t)clockFreq) < 96) { 
return
FLASH_LATENCY_3; }
else
if
(((uint8_t)clockFreq) < 120) { 
return
FLASH_LATENCY_4; }
else
if
(((uint8_t)clockFreq) < 144) { 
return
FLASH_LATENCY_5; }
else
return
FLASH_LATENCY_6;
#else
if
(((uint8_t)clockFreq) < 30) { 
return
FLASH_LATENCY_0; }
else
if
(((uint8_t)clockFreq) < 60) { 
return
FLASH_LATENCY_1; }
else
if
(((uint8_t)clockFreq) < 90) { 
return
FLASH_LATENCY_2; }
else
if
(((uint8_t)clockFreq) < 120) { 
return
FLASH_LATENCY_3; }
else
if
(((uint8_t)clockFreq) < 150) { 
return
FLASH_LATENCY_4; }
else
return
FLASH_LATENCY_5;
#endif
}
typedef
enum
{
CLOCK_FREQ_1_MHz = 1,
CLOCK_FREQ_2_MHz = 2,
CLOCK_FREQ_4_MHz = 4,
CLOCK_FREQ_8_MHz = 8,
CLOCK_FREQ_16_MHz = 16,
CLOCK_FREQ_32_MHz = 32,
CLOCK_FREQ_64_MHz = 64,
CLOCK_FREQ_128_MHz = 128,
} ClockFreqType;
void
ClockSwitch(ClockFreqType clockFreq)
{
// The code below was taken from HAL_RCC_DeInit() in file stm32f4xx_hal_rcc_ex.c
/* Set HSION bit */
SET_BIT(RCC->CR, RCC_CR_HSION | RCC_CR_HSITRIM_4);
/* Reset CFGR register */
CLEAR_REG(RCC->CFGR);
/* Reset HSEON, CSSON, PLLON, PLLI2S */
CLEAR_BIT(RCC->CR, RCC_CR_HSEON | RCC_CR_CSSON | RCC_CR_PLLON| RCC_CR_PLLI2SON);
/* Reset PLLCFGR register */
CLEAR_REG(RCC->PLLCFGR);
SET_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM_4 | RCC_PLLCFGR_PLLN_6 | RCC_PLLCFGR_PLLN_7 | RCC_PLLCFGR_PLLQ_2);
/* Reset PLLI2SCFGR register */
CLEAR_REG(RCC->PLLI2SCFGR);
SET_BIT(RCC->PLLI2SCFGR, RCC_PLLI2SCFGR_PLLI2SN_6 | RCC_PLLI2SCFGR_PLLI2SN_7 | RCC_PLLI2SCFGR_PLLI2SR_1);
/* Reset HSEBYP bit */
CLEAR_BIT(RCC->CR, RCC_CR_HSEBYP);
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
// First, switch to HSI to bypass the PLL
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_7);
// The code below was generated with STM32CubeMX
switch
(clockFreq)
{
case
CLOCK_FREQ_1_MHz:
{
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = 16;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV16;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
break
;
}
case
CLOCK_FREQ_2_MHz:
{
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = 16;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV8;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
break
;
}
case
CLOCK_FREQ_4_MHz:
{
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = 16;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV4;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
break
;
}
case
CLOCK_FREQ_8_MHz:
{
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = 16;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV2;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
break
;
}
case
CLOCK_FREQ_16_MHz:
{
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = 16;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
break
;
}
case
CLOCK_FREQ_32_MHz:
{
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = 16;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 64;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV2;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
break
;
}
case
CLOCK_FREQ_64_MHz:
{
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = 16;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 64;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
break
;
}
case
CLOCK_FREQ_128_MHz:
{
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = 16;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 128;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
break
;
}
default
:
{
break
;
}
}
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, getNumWaitStates(clockFreq));
SystemCoreClockUpdate();
}