Handle FreeRTOS tick rollover with 64-bit ticks
In FreeRTOS, with a 32-bit systick running at 1000Hz (i.e. configTICK_RATE_HZ = 1000
), the maximum duration it can run before a rollover occurs is ~50 days:1
A rollover (or “overflow”) may require special handling, depending upon what your application does:
- If your application only need to calculate the difference between two ticks, so long as the difference is not more than ~50 days (assuming 32-bit), then you can rely upon unsigned integer comparison.
- However, if you need to count the absolute number of ticks beyond the rollover, two possible options are detailed below:
Option A: Increment a 64-bit counter on every tick §
The first option is to implement our own 64-bit tick counter. FreeRTOS provides the callback vApplicationTickHook
, which is enabled by setting #define configUSE_TICK_HOOK 1
, and allows us to define a callback function that is called on each tick. We can do something like:
Note that 64-bit data types are generally not atomic, so it will almost certainly be necessary to use a critical section or a mutex, e.g.:
Option B: Make use of the private variable xNumOfOverflows
. §
Though why reinvent the wheel? The FreeRTOS kernel actually already counts the number of overflows. This can be combined with the current 32-bit tick to get a 64-bit tick.
The number of overflows is defined by xNumOfOverflows
in tasks.c
:
It is static
, so we cannot access it from outside of tasks.c
. While vApplicationTickHook
is part of the FreeRTOS public API, xNumOfOverflows
is not.2 However, by enabling configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H
we can add user-defined code into tasks.c
.
To do so, first set #define configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H 1
in FreeRTOSConfig.h
. Then create two files:
- The first file must be named
freertos_tasks_c_additions.h
3, since that is the exact file that FreeRTOS will include in the bottom oftasks.c
.4 - For this example, the second file will be named
systick64.h
, though the choice is yours. This will be the header file for our new functions.
I created both these files in the same directory as FreeRTOSConfig.h
.
Put the declaration for the new function in systick64.h
:
Put the definition in freertos_tasks_c_additions.h
:
Your application can now do #include "systick64.h"
and call the function xTaskGetTickCount64()
to get 64-bit ticks!
Conclusion §
Both options are viable, though arguably Option A is better in most cases. While Option B makes use of existing variables, it is relying on undocumented, private features, and is more complex to implement. In comparison, Option A is much simpler, and the overhead of an additional uint64_t
counter is unlikely to be prohibitive.
Systicks are either 16-bit or 32-bit, depending upon whether
configUSE_16_BIT_TICKS
is1
or0
respectively. If using a 16-bit systick at 1000Hz, a rollover will occur about once per minute (every 65.535 seconds to be precise). This “feature” can be useful for testing your rollover behaviour. ↩︎xNumOfOverflows
is used internally by the functionsvTaskSetTimeoutState
andxTaskCheckForTimeOut
, so it actually serves a useful purpose, and as such will hopefully remain a part of FreeRTOS in future. ↩︎Unfortunately there is a mix of plurality, with the macro
configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H
beingTASK
singular and the filenamefreertos_tasks_c_additions.h
beingtasks
plural. Though perhaps this is intentional, since this pattern appears elsewhere, e.g.xTaskGetTickCountFromISR
is defined inFreeRTOS/Source/tasks.c
plural but is declared inFreeRTOS/Source/include/task.h
singular. However, the official FreeRTOS release notes make a mistake by writingfreertos_task_c_additions.h
singular instead of plural. ↩︎Although the file extension implies this is a header, personally I think it is better to think of it as a source file, in which case the name
freertos_task_c_additions.c
would make more sense. Others have made the same observation, but unfortunately that ship has sailed. ↩︎