2015-01-09 03:05 PM
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
2015-01-12 10:31 AM
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 Peacock2015-01-12 11:21 AM
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).
2015-01-15 01:22 AM
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 availablehttp://http://www.st.com/web/catalog/tools/FM147/CL1794/SC961/SS1743/LN1897/PF259243
.Regards,Heisenberg.2015-01-15 10:06 AM
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;
2015-01-15 01:37 PM
> 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?) JW2015-01-15 03:15 PM
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
2015-01-19 12:22 PM
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...
2015-01-19 01:26 PM
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.
2015-01-19 02:36 PM
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...