Changing clock speed seems to cause strange behaviour

Hi

I’m using FreeRTOS V10.0.1 on a NXP K22 MCU.

I’ve just started to implement some power saving features and need to reduce the clock speed when the application is receiving data, and then increase the speed when the application is sending data (because the data needs to be compressed and it takes longer to compress it)

I’m not sure how to notify FreeRTOS that the clock rate has been changed, so I have been setting the SystemCoreClock global variable, which I know FreeRTOS uses, and then calling vPortSetupTimerInterrupt() to reconfigure the timer.

SystemCoreClock = CLOCK_GetFreq(kCLOCK_CoreSysClk);
vPortSetupTimerInterrupt();

However this only seems to work correctly when changing from specific slower clock speeds, to a faster clock speed

50Mhz → 100Mhz works OK.
40Mhz → 100Mhz works OK

but 45Mhz → 100Mhz seems to cause FreeRTOS to stop scheduling tasks correctly and the task code only seems to be executed at random times, often with large delays.

I am not using TickLess idle, because I’m not fully sleeping the application, as USB needs to be maintained at all times.

So I’m simply changing the clock rate.

I’ve tried ending and the starting the scheduler when I change clock rates, but that just seems to cause my watchdog timer to activate, as if the application has hung.

If possible can someone tell me what I need to do, in order to notify FreeRTOS that I am about to change, or have just changed the clock speed, so that I can change clock speeds

I think the API for vPortSetupTimerInterrupt() requires that it be called with interrupts masked.

Also, double check in FreeRTOSConfig.h that configCPU_CLOCK_HZ is defined as SystemCoreClock.

Yes. I have

#define configCPU_CLOCK_HZ (SystemCoreClock)

In my FreeRTOSConfig.h

Re: Interrupts

Do you mean call

portDISABLE_INTERRUPTS();
vPortSetupTimerInterrupt();
portENABLE_INTERRUPTS();

Or do I need to do this at a lower level in the hardware ?

Or perhaps should call those interrupt functions before and after switching the clock rate ?

I guess I could give it a try.

Is there any specific documentation about changing clock rates when using FreeRTOS?

Yes, something like that. That specific code works as long as you know your task code isn’t already in a critical section. I believe a best practice is taskENTER_CRITICAL() and taskEXIT_CRITICAL() so you don’t have to worry about such things.

I can’t think of a reason you would need to have interrupts masked during the clock change.

This is a really great question. I don’t know of any.

Umm.

I’ve tried just wrapping the vPortSetup() but it didnt seem to make any difference.
I also tried wrapping my clock speed switching code completely with taskENTER_CRITICAL() taskEXIT_CRITICAL()

But that didn’t seem to help either.

Its hard to see whats going on in real time, but as far as I can tell from my debug trace statements via Segger RTT, none of the task code seems to be executing correctly.

Hmm. I can only guess that the problem is not related to FreeRTOS.

I can’t see any reason why it should work going from 40MHz and from 50MHz but not from 45MHz. For what it’s worth, here are some things to think about, even though I suspect you have already considered all of them, and some may not apply to K22:

  • Core voltage regulator settings must support 100MHz
  • Flash wait states must support 100MHz
  • Peripherals configured before the clock change often must be reconfigured after

Maybe a good next step would be to use the tick hook to toggle a pin or something just to see what the tick rate looks like before and after the clock change.

Yes.
That’s entirely possible.

Just to add to the strangeness of the problem, it seems to only occur on some hardware revisions and not others.

I had put this down to the MCU being very slightly different, but all boards use the NXP MK22FN512 (just the letters at the end of the part code change between hardware revision)

There is a Flash memory chip on the board, which is larger on the newer boards, and is a slightly different Windbond chip, but I think everything else is supposed to be the same.

I’ll need to write some more complex test code which is hopefully independent of external influences.

Thanks for your help.

I’ll probably leave the code in which wraps the CPU frequency change in the Task Critical wrapper functions, as it seems logical to top FreeRTOS task switching during the CPU clock rate change

I have had code that changes the CPU frequency and not had similar problems. One key is that if possible you want to (if possible) change you tick counter to be based on a counter that doesn’t depend on the CPU clock for its tic rate.

I wouldn’t;t just call the setup routine again, but look at what the code is doing and figure out what needs to change as the frequency changes. For timers that are actually keeping time, you likely need to read their value, scale it, and write it out, and perhaps trigger the ‘overflow’ interrupt. (Which is why it is best to be using timers that don’t depend on the CPU frequency).

1 Like

Sorry if I’m pointing out something that is obvious, but vPortSetupTimerInterrupt() does not change the CPU frequency. It uses whatever you tell it the CPU frequency is already set to in order to configure a timer/counter to generate a tick interrupt at the rate specified by configTICK_RATE_HZ.

Thanks.

I know changing vPortSetupTimerInterrupt() does not change the CPU frequency.

I’m using the NXP SDK example code “power_manager” which changes both the CPU clock speed and also the “power mode” of the MCU.

I had a look at whether any of the peripheral interface code could possibly be blocking the task switching, because it uses Enter and Exit Critical blocks, but so far I’ve not found anything which could be interfering with the task switching.

Did you do anything specific in your code?

Eg. Do you use Enter / Exit critical to wrap the function which changes the CPU frequency.
Or stop and restart the scheduling before and after the change?

Did you need change anything else in FreeRTOS after the change.

I’ve currently only wrapping with Enter/Edit and calling vPortSetupTimerInterrupt()

The problem is probably not in FreeRTOS but somewhere else in my code which is blocking the task scheduling, as the problem is definitely clock speed ( hence timing) related.

As some clock speeds work, but some don’t, but its not that faster or slower clock speeds work… Only bands of speeds work :frowning:

BTW.
I’m getting close to tracking down the problem and it looks like its something to do with peripheral contention.

Unfortunately, as the peripherals are accessed via ISR’s this is outside the scope of something the RTOS can deal with.

However, I’m still keen to know the best practice for changing clock speeds when using FreeRTOS.

Thanks

FreeRTOS itself doesn’t care, you just need to make sure the tick interrupt continues to meet your requirements (FreeRTOS itself doesn’t really care what rate the tick interrupt is, as it just keeps time in units of the interrupt).

My first guess is that you will want the entire clock change operation to be under a critical section, if not a complete interrupt disable interval. You also will need to make sure that all the peripherals whose clocks are going to get changed by this action are ‘idle’ at the time.