jakbird wrote on Tuesday, July 20, 2010:
While working on some power saving routines I ran into a problem with FreeRTOS. The OS assumes the clock stays at a fixed frequency, set by configCPU_CLOCK_HZ. For the STM32 the system tick timer uses this value to calculate the timer reload. However the STM32 can vary the instruction clock (SYSCLK) anywhere from 4MHZ to 72MHZ with substantial power savings at lower frequencies, significant when running on batteries or off the USB Vbus power.
I’d like to suggest changing configCPU_CLOCK_HZ into a RAM location instead of a compile time option. And for the STM32 it would be nice if the SysTick timer load routine in port.c was exposed so that the clock frequency changes would affect the SysTick timer in one routine, instead of replacing the one in port.c.
The other question is where best to vary the frequency? My inclination is to post a change request, and then switch the CPU clock during the tick hook routine, so that (on the STM32) the Systick timer can be modified to keep to the expected tick rate with a minimal loss from resetting the timer.
richard_damon wrote on Tuesday, July 20, 2010:
One thing to note, is the as far as I know, the only thing that the FreeRTOS kernel does with the value of configCPU_CLOCK_HZ is us it with the tick rate parameter to set up the tick timer. If you want to change the cpu frequency on the fly, you are free to adjust the clock rate (as well as any other perpetual that also need timing adjusted). Another point to consider is that FreeRTOS itself doesn’t need the timer tick to be at any given or constant rate. It is the requirements of the user program that control how accurate you need to keep the tick rate.
rtel wrote on Wednesday, July 21, 2010:
When a task blocks on a temporal event (calls something like vTaskDelayUntil(), vTaskDelay(), or a queue or semaphore function with a time out) then the kernel will calculate the time at which the task should unblock. If you then change the tick frequency the calculated time will be wrong, and an error will occur (the consequence of which could be significant or insignificant, depending on your application).
You can remove this problem by only every blocking for 0 ticks (not blocking) or blocking indefinitely (using portMAX_DELAY if configINCLUDE_vTaskSuspend is also set to 1), but that severely restricts how you can write your code.
Another technique I believe is often used is to manually adjust how many times the tick value is incremented during each timer tick. For example, if you slow the timer down by a factor of ten, then you have to call vTaskIncrementTick() ten times during each timer tick (could potentially be lengthy!) until the timer is set back to its original frequency.
There are a few people doing interesting work on this issue at the moment and hopefully the results will be published soon. This often includes using special hardware though, with an external low frequency clock in addition to the main timer.
jakbird wrote on Wednesday, July 21, 2010:
Maintaining a constant rate for the system tick isn’t an issue per se, since the timer reload count can be adjusted at the same time the CPU frequency is changed (with the assumption that the SysTick timer is tied to the CPU frequency). There is an issue of exactly when to change the frequency in order to keep the SysTick constant. I’m guessing that the system tick hook in FreeRTOS occurs soon after the SysTick timer generates an interrupt, so this would be the best place to change CPU speed and the SysTick counter/reload register. The question is, how soon is the hook called after the tick interrupt? Does the task rundown and context switching take place first?
Unfortunately ARM did miss on the design decision to make the SysTick timer dependent on the CPU instruction clock rather than the base oscillator. Not a big deal but it makes it harder to dynamically control clock rate and power consumption.