cancel
Showing results for 
Search instead for 
Did you mean: 

Changing Clock Frequency on STM32F4xx

martinmartin9
Associate II
Posted on January 10, 2015 at 00:05

Having trouble changing the STM32F4 clock (M4 clock) on the fly, dynamically. When I do, the target fails, sometimes not right away, but within a few dozen seconds. How do I know its failing? I have a task attached to a button, that toggles LEDs. When I change the clock frequency, I push the button, and eventually the LEDs no longer toggle. The UART debug interface dies right away - note that when I change frequencies, I keep the peripheral bus at the same frequency. GDB shows the target is stuck in a task that was sending chars out the UART...

Using: FreeRTOS ver 8.1.2. STM32F439 STM32Cube generates the following code for setting the clock on power up,

RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSE; 
RCC_OscInitStruct.HSEState = RCC_HSE_ON; 
RCC_OscInitStruct.HSIState = RCC_HSI_ON; 
RCC_OscInitStruct.HSICalibrationValue = 6; 
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; 
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; 
RCC_OscInitStruct.PLL.PLLM = 8; 
RCC_OscInitStruct.PLL.PLLN = 192; 
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV8; 
RCC_OscInitStruct.PLL.PLLQ = 4; 
HAL_RCC_OscConfig(&RCC_OscInitStruct); 
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK; 
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; 
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV2; 
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; 
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; 
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0);

This works fine. I can use Cube32 to select other clock frequencies and they also work, when run at power up.

The dynamic switching code looks like this,

case
POWMAN_LOW: 
// 12MHz 
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSE; 
RCC_OscInitStruct.HSEState = RCC_HSE_ON; 
RCC_OscInitStruct.HSIState = RCC_HSI_ON; 
RCC_OscInitStruct.HSICalibrationValue = 6; 
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; 
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; 
RCC_OscInitStruct.PLL.PLLM = 8; 
RCC_OscInitStruct.PLL.PLLN = 192; 
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV8; 
RCC_OscInitStruct.PLL.PLLQ = 4; 
HAL_RCC_OscConfig(&RCC_OscInitStruct); 
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK; 
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; 
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV2; 
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; 
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; 
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0); 
break
; 
case
POWMAN_MED: 
// 48MHz 
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSE; 
RCC_OscInitStruct.HSEState = RCC_HSE_ON; 
RCC_OscInitStruct.HSIState = RCC_HSI_ON; 
RCC_OscInitStruct.HSICalibrationValue = 6; 
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; 
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; 
RCC_OscInitStruct.PLL.PLLM = 8; 
RCC_OscInitStruct.PLL.PLLN = 192; 
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4; 
RCC_OscInitStruct.PLL.PLLQ = 4; 
HAL_RCC_OscConfig(&RCC_OscInitStruct); 
RCC_ClkInitStruct.ClockType = 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_DIV4; 
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1); 
break
;

I have reviewed the RCC examples for the STM32F4, read the Power Modes app note, read the HAL library documentation, etc... I am not sure if this is a FreeRTOS issue, or if I am using HAL the wrong way....? #stm32f4-rcc #pll
11 REPLIES 11
jpeacock
Associate II
Posted on January 12, 2015 at 19:31

Since you are using the PLL multiplier you need to switch back to the base HSE, no PLL, reset the PLL settings, and then enable PLL again.  I don't believe you can change the PLL frequency while it is the SYSCLK source.

  Jack Peacock

martinmartin9
Associate II
Posted on January 12, 2015 at 20:21

Opps, yes, indeed I had that in a previous iteration, here is updated, and the result is the same,

case
POWMAN_LOW: 
// 12MHz 
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK; 
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; 
result = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1); 
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSE; 
RCC_OscInitStruct.HSEState = RCC_HSE_ON; 
RCC_OscInitStruct.HSIState = RCC_HSI_ON; 
RCC_OscInitStruct.HSICalibrationValue = 6; 
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; 
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; 
RCC_OscInitStruct.PLL.PLLM = 8; 
RCC_OscInitStruct.PLL.PLLN = 192; 
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV8; 
RCC_OscInitStruct.PLL.PLLQ = 4; 
result = HAL_RCC_OscConfig(&RCC_OscInitStruct); 
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK; 
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; 
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV2; 
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; 
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; 
result = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0); 
break
; 
case
POWMAN_MED: 
// 48MHz 
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK; 
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; 
result = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1); 
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI | RCC_OSCILLATORTYPE_HSE; 
RCC_OscInitStruct.HSEState = RCC_HSE_ON; 
RCC_OscInitStruct.HSIState = RCC_HSI_ON; 
RCC_OscInitStruct.HSICalibrationValue = 6; 
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; 
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; 
RCC_OscInitStruct.PLL.PLLM = 8; 
RCC_OscInitStruct.PLL.PLLN = 192; 
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4; 
RCC_OscInitStruct.PLL.PLLQ = 4; 
result = HAL_RCC_OscConfig(&RCC_OscInitStruct); 
RCC_ClkInitStruct.ClockType = 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_DIV4; 
result = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1); 
break
;

My main test is to switch from 12MHz, to 12MHz, and that fails. I can't seem to touch the RCC registers (thru HAL).
Posted on January 15, 2015 at 10:22

Hi,

As said Jack, you have to switch to HSE as a SYSCLK source, in order to change PLL frequency. It's not possible to change the PLL settings/frequency on the fly, while it's the SYSCLK source.

For more details you can refer to the: Firmware\Projects\STM324x9I_EVAL\Examples\RCC\RCC_ClockConfig project, under STM32Cube_FW_F4_V1.3.0 available

http://http://www.st.com/web/catalog/tools/FM147/CL1794/SC961/SS1743/LN1897/PF259243

.

Regards,

Heisenberg.

martinmartin9
Associate II
Posted on January 15, 2015 at 19:06

In the example above, am I not switching to the HSI while the PLL is being configured?

As suggested in your comment, I also tried the HSE, as indicated here,

RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK; 
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE; 
result = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1); 
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSE; 
RCC_OscInitStruct.HSEState = RCC_HSE_ON; 
RCC_OscInitStruct.HSIState = RCC_HSI_ON; 
RCC_OscInitStruct.HSICalibrationValue = 6; 
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; 
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; 
RCC_OscInitStruct.PLL.PLLM = 8; 
RCC_OscInitStruct.PLL.PLLN = 192; 
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV8; 
RCC_OscInitStruct.PLL.PLLQ = 4; 
result = HAL_RCC_OscConfig(&RCC_OscInitStruct); 
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK; 
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; 
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV2; 
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; 
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; 
result = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1); 
break;

Posted on January 15, 2015 at 22:37

> STM32Cube_FW_F4_V1.3.0 available

http://http://www.st.com/web/catalog/tools/FM147/CL1794/SC961/SS1743/LN1897/PF259243

.

The link does not work on a click, probably by courtesy of the idiotic forum software. Please vote for firing the webmaster.

http://www.st.com/web/catalog/tools/FM147/CL1794/SC961/SS1743/LN1897/PF259243

or direct link

http://www.st.com/st-web-ui/static/active/en/st_prod_software_internet/resource/technical/software/firmware/stm32cubef4.zip

> When I do, the target fails, sometimes not right away, but within a few dozen seconds. 

To me, this sounds like some deeper-rooted problem - what happens if all the code remains in place except the actual call to Cube RCC-switching routines is commented out? And what if you strip off the RTOS, attempting the frequency switch in an old-fashioned single-loop program?

One more question: I am not going to dive into Cube's guts, but does it actually switch off PLL before changing its parameters (probably yes, but aren't you bound to check it, once in troubles?)

JW

Posted on January 16, 2015 at 00:15

More questions: do you have

RCC_ClkInitStruct

filled completely or initialized properly before calling HAL_RCC_ClockConfig()? Is it a static/global variable, or local? Also, do you have CSS enabled? ---- [Cube bashing follows] > One more question: I am not going to dive into Cube's guts, OK I took a deep breath... HAL_RCC_ClockConfig() [...] /* Increasing the CPU frequency */ if(FLatency > (FLASH->ACR & FLASH_ACR_LATENCY)) Oh, c'mon. What if I switch between clocks of substantially differing frequency, but wish to leave latency for any weird reason unchanged or changed in the unexpected opposite way (while still obeying the hardware limitations)? The two legs of this if-then-else are substantially the same software repeated twice (c'mon again), with different ordering of things: if [increasing CPU frequency] { change (increase) FLASH latency change AHB divider *** change clock source } else [decreasing CPU frequency] { change AHB divider *** change clock source change (decrease) FLASH latency } OK so let's start with running on PLL at say 168MHz but for any reason with divider 2, i.e. HCLK=84MHz, latency set to whatever minimum value conforming to this frequency. Want to switch to HSI at 16MHz with divider 1, latency again set accordingly, so it goes through the ''decrease'' leg, hitting first the change of divider to 1, BANG! HCLK is suddenly 168MHz with FLASH latency unchanged from the value for 84MHz. Similarly, if I run a 25MHz external oscillator as HSE source and have the divider set to 2 to run at low clock sparing electrons and flash latency set to 0 as appropriate, but want to switch to full throttle PLL 168MHz divider 1, with accordingly set high flash latency, it goes to the ''increase frequency'' leg, hitting first the AHB divider change, BANG! we run at 25MHz, with inappropriate flash latency again. C'mon. Regardless of whether switching system frequency up or down, APB prescalers are updated only after all this happened. Oh c'mon... [end of Cube bashing] JW
martinmartin9
Associate II
Posted on January 19, 2015 at 21:22

I created a non-FreeRTOS build and I believe the clock switching is working, this is the code I used,

case
POWMAN_SPEED_LOW: 
// 12MHz 
// turn on HSE 
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; 
RCC_OscInitStruct.HSEState = RCC_HSE_ON; 
result = HAL_RCC_OscConfig(&RCC_OscInitStruct); 
// switch to HSE 
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK; 
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE; 
result = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1); 
// tune PLL 
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSE; 
RCC_OscInitStruct.HSEState = RCC_HSE_ON; 
RCC_OscInitStruct.HSIState = RCC_HSI_ON; 
RCC_OscInitStruct.HSICalibrationValue = 6; 
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; 
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; 
RCC_OscInitStruct.PLL.PLLM = 8; 
RCC_OscInitStruct.PLL.PLLN = 192; 
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV8; 
RCC_OscInitStruct.PLL.PLLQ = 4; 
result = HAL_RCC_OscConfig(&RCC_OscInitStruct); 
// switch to pll 
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; 
result = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1); 
break
; 
case
POWMAN_SPEED_MED: 
// 48MHz 
// turn on HSE 
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; 
RCC_OscInitStruct.HSEState = RCC_HSE_ON; 
result = HAL_RCC_OscConfig(&RCC_OscInitStruct); 
// switch to HSE 
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK; 
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE; 
result = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1); 
// tune PLL 
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSE; 
RCC_OscInitStruct.HSEState = RCC_HSE_ON; 
RCC_OscInitStruct.HSIState = RCC_HSI_ON; 
RCC_OscInitStruct.HSICalibrationValue = 6; 
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; 
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; 
RCC_OscInitStruct.PLL.PLLM = 8; 
RCC_OscInitStruct.PLL.PLLN = 192; 
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4; 
RCC_OscInitStruct.PLL.PLLQ = 4; 
result = HAL_RCC_OscConfig(&RCC_OscInitStruct); 
// switch to pll 
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_DIV4; 
result = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1); 
break
;

However using this code on the FreeRTOS build does not work... the target just seems to stop running a random amount of time (always sub 1s)after the switch occurs. GDB seems to indicate the system is stopped on a task switch...
martinmartin9
Associate II
Posted on January 19, 2015 at 22:26

I should add that the frequency switching code runs between,

taskENTER_CRITICAL(); 
// run the switch frequency code (as shown above) here 
taskEXIT_CRITICAL();

It seems that the frequencyswitch does occur, and the target is idle, all tasks are blocked, and when I create an event (push a button, or send a command over uart) the event partially processes, before the target seems to halt. With GDB I can pause the target and I find the target is always at the same line of FreeRTOS code, even if I un-pause and pause again, always at the same line. I can't step GDB.
martinmartin9
Associate II
Posted on January 19, 2015 at 23:36

GDB showed the line at which the system was crashing and I didn't notice the comments above the line, which read,

/* *** NOTE *********************************************************** 
If you find your application is crashing here then likely causes are: 
1) Stack overflow 
2) Incorrect interrupt priority assignment, especially on Cortex-M3 
parts where numerically high priority values denote low actual 
interrupt priorities, which can seem counter intuitive. See 
configMAX_SYSCALL_INTERRUPT_PRIORITY 
3) Calling an API function from within a critical section or when 
the scheduler is suspended, or calling an API function that does 
not end in ''FromISR'' from an interrupt. 
4) Using a queue or semaphore before it has been initialised or 
before the scheduler has been started (are interrupts firing 
before vTaskStartScheduler() has been called?). 
**********************************************************************/

So I have an investigation path...