Is there a reason M0 port doesn't respect configSYSTICK_CLK_HZ?

(I’m a new user so it won’t let me post links) freertos dot org /low-power-ARM-cortex-rtos.html describes how you can get longer tick intervals if systick is not the system clock, and it is implemented in all the Cortex M ports except M0. Is there a reason for this? For example, rp2040 can use the watchdog timer’s 1 MHz clock as the reference instead of the system clock (at least the documentation for the rp2040 says you can, and the registers on chip say it is possible, although I don’t know how many people do this in practice).

The exact lines in the port:
M0: (I’m a new user so it won’t let me put in links) github: /FreeRTOS/FreeRTOS-Kernel/blob/b5b1ff02ddb7f3de990283253a2d73b665af3ef4/portable/GCC/ARM_CM0/port.c#L385

ulTimerCountsForOneTick = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ );

compared to M4
github: /FreeRTOS/FreeRTOS-Kernel/blob/b5b1ff02ddb7f3de990283253a2d73b665af3ef4/portable/GCC/ARM_CM4F/port.c#L695

ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ );

Along with a bunch of other code including allow portNVIC_SYSTICK_CLK_BIT to be zero on the non-M0 (meaning that you don’t have to set it to system clock speed)
github: /FreeRTOS/FreeRTOS-Kernel/blob/b5b1ff02ddb7f3de990283253a2d73b665af3ef4/portable/GCC/ARM_CM4F/port.c#L49

/* The way the SysTick is clocked is not modified in case it is not the same
 * as the core. */
#define portNVIC_SYSTICK_CLK_BIT    ( 0 )

while the M0 requires that portNVIC_SYSTICK_CLK_BIT be set to system clock:
github: /FreeRTOS/FreeRTOS-Kernel/blob/b5b1ff02ddb7f3de990283253a2d73b665af3ef4/portable/GCC/ARM_CM0/port.c#L43

#define portNVIC_SYSTICK_CLK_BIT              ( 1UL << 2UL )


Let me check this with my team and get back to you. Meanwhile, to make sure that I understand your problem, you are trying to clock systick at a different rate than CPU? Or are you looking to use any other interrupt to drive FreeRTOS tick?


Yes, I’m trynig to use another reference clock for systick besides the CPU (which is what the configSYSTICK_CLK_HZ is intended for, I believe). I’m trying to see how far I can push the low power tickless idle period.

Most ARM Cortex-M microcontrollers clock the SysTick timer at the same frequency as the ARM Cortex-M core. When this is the case, the combination of high clock speed and 24-bit resolution result in a sever limitation in the maximum tickless period that can be achieved.

If the system is at 133 MHz, the 24 bit timer means the maximum period is ~125 ms. If I could use the 1 MHz reference instead, I can reach ticks greater than 125 ms up to ~16 seconds. All the other cortex M ports have this implemented for this use case, I believe.

You are right. Let me see if I can add this support. Aside, have you tried changing the clock source of systick to see if that works?

FYI this change is included in PR #59 along with some minor fixes/improvements to the default tickless idle implementation. Gaurav, you might still want to do a separate PR since #59 is more involved and will take longer to merge.

Meantime, Scott you might find the benefit is very small. For example, over 16 seconds, you would spend, say, 99.9% of the time in sleep mode if you have to wake up every 125 ms just to go back to sleep. However, with support for 1 MHz systick, you can spend 100% of that 16 seconds in sleep mode. The difference in energy consumption is probably fairly small but would be interesting to actually measure it as it also depends on time and energy used in the wake-up events, which can differ greatly between MCU models.

I have tried it yet - I’m planning a project now that fits the dual-core M0+ capabilities and power profile well, but could benefit from a longer systick interval.

I think there should be some device that would work. The M0 and M0+ (ARMv6-M) has an optional system timer, and devices that do come with it can have an alternative reference clock. If the alternative clock is implemented, SYST_CSR resets to 0x00000000. If an alternative reference is not implemented, it resets to 0x00000004. The rp2040 says it resets to 0x00000000 and that systick can run off of the 1 MHz WDT clock - but I haven’t seen any examples of anyone doing it yet. Here’s the text from their datasheet:

Each Cortex-M0+ core (Section 2.4) has a standard 24-bit SysTick timer, counting either the microsecond tick (Section 4.7.2) or the system clock.

Thanks! Yes, I believe it probably won’t get much improvement. I’m actually looking at this for a class a teach, and trying to see if there was a fundamental reason why it wouldn’t work. Getting it to work soon isn’t a high priority to me as much as explaining to students how it can work (e.g., if I show it on an M4 and a student tries it on an M0, I can explain that it can be implemented), so this is good to know that it’s in the work.

Perhaps as a counterpoint, I would like to point out that not only can you change the configuration of the systick counter to get longer periods, but you can totally replace it as the source of a system tick. The big advantage of the built in implementation is that it is available for ALL Cortex processors. In the same way the built in Tickless Idle mode has the advantage that it also uses just standard hardware, so works on all Cortex processors, but doesn’t save as much power as possible, because it really only ‘Idles’ not ‘Sleeps’.

Many processors have timers that allow you to go to MUCH lower power draw mode, being able to actually SLEEP the processor by turning off the clock to it, and running a timer on a separate lower frequency clock,

Many ‘Low Power’ processors have the ability to totally stop much of the system, and leave a 32kHz clock running, which you can put into a low power timer, and you can use that for your system tick. Yes, this sort of answer needs something developed for each ‘family’ of processors that does this somewhat differently, but a given company is apt to only use a few (maybe just 1) of these families so can do a fairly limited development to implement this sort of thing.

FreeRTOS itself, being targeted to the wide audience of as many families as possible, has less incentive to develop this wide range of options, and even if it tried, the largest level of power savings really require application level knowledge to implement.

I have added this support in this PR - Add configSYSTICK_CLOCK_HZ to Cortex-M0 ports by aggarg · Pull Request #484 · FreeRTOS/FreeRTOS-Kernel · GitHub


Update to answer your question, yes I was just able to get the rp2040 system tick to use the watchdog timer reference clock! I’ve seen others reference that it didn’t work, but maybe they fixed something in the SDK because it “just worked” for me now.

Using the code from:
forums DOT raspberrypi DOT com /viewtopic.php?t=304201#p1822690

Just changing systick_hw->csr = 0x5; to systick_hw->csr = 0x1; switches the system tick from 125 ticks per microsecond to 1 tick per microsecond. That’s the Cortex M0PLUS’s SYST_CSR register, changing the “CLKSOURCE” from system clock to reference clock (here the reference clock is a 1 MHz watchdog tick).

EDIT: In fact, the reset default is 1 MHz. If you just enable the systick timer (and don’t touch any other bits in SYST_CSR hw_set_bits(&systick_hw->csr, 0x1);), you get a 1 MHz system tick. Right now, FreeRTOS sets the clock to the system tick in the M0 port, which makes sense since not all M0s have this other clock. So the new patch allowing people to configure as they wish sounds great.

Glad that it worked for you.