
FreeRTOS software timers provide a powerful mechanism for executing periodic callback functions without blocking tasks or requiring complex hardware timer setup. They are particularly useful for periodic telemetry, LED blinking, watchdog feeding, and other background activities that need consistent timing but don’t require interrupt-level responsiveness.
FreeRTOS software timers are created and managed by the RTOS kernel. When a timer expires, its callback function executes in the context of the timer service task (also called the timer daemon task). This design keeps interrupt service routines (ISRs) short while still enabling periodic processing.
Expert Note (Deferred Interrupt Processing): The timer daemon task has a powerful dual-purpose. In addition to handling software timers, it executes functions deferred from ISRs using the xTimerPendFunctionCallFromISR() API. This allows developers to push heavy ISR processing down to the task level without creating a dedicated task for it.
Each software timer has:
The timer service task runs at a configurable priority and processes commands from the timer command queue. Instead of the tick interrupt checking timers every tick, the timer daemon task simply blocks on its command queue with a timeout equal to the time remaining until the next timer is due to expire. When this block time elapses, the scheduler wakes the daemon task, which then executes the appropriate callback functions and recalculates its next wakeup time.
+---------------------------+| Application |+---------------------------+| FreeRTOS Kernel / OS || (scheduler, IPC, mem) |+---------------------------+| Timer Service || (timer daemon task) || - Timer command queue || - Timer callback exec |+---------------------------+| Hardware || (tick timer, peripherals)|+---------------------------+
To use software timers, first enable them in FreeRTOSConfig.h:
#define configUSE_TIMERS 1#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1)#define configTIMER_QUEUE_LENGTH 10#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE
Then create a timer using xTimerCreate():
TimerHandle_t xTelemetryTimer;const TickType_t xTelemetryPeriod = pdMS_TO_TICKS(1000); // 1 secondvoid vTelemetryTimerCallback(TimerHandle_t xTimer) {send_telemetry_data();/* Optional: restart timer if one-shot */// xTimerStart(xTimer, 0);}void setup_timers(void) {xTelemetryTimer = xTimerCreate("TelemetryTimer", // Just a text name, not used by kernelxTelemetryPeriod, // Timer period in tickspdTRUE, // Auto-reload (pdTRUE) or one-shot (pdFALSE)NULL, // Timer ID (can be used to identify timer)vTelemetryTimerCallback // Callback function);if (xTelemetryTimer != NULL) {xTimerStart(xTelemetryTimer, 0); // Start the timer}}
Software timers can be in one of two states:
You control timers using these API functions:
xTimerStart() / xTimerStartFromISR(): Start or restart a timerxTimerStop() / xTimerStopFromISR(): Stop an active timerxTimerChangePeriod() / xTimerChangePeriodFromISR(): Modify the period of an active timerxTimerReset() / xTimerResetFromISR(): Re-starts a timer that is already running, or starts a timer that was dormantxTimerDelete(): Delete a timer and free its resourcesxTimerIsTimerActive(): Check if a timer is activepvTimerGetTimerID() / vTimerSetTimerID(): Get or set the timer’s ID, heavily used when multiple timers share a single callback functionxTimerPendFunctionCallFromISR(): Defers execution of a function from an ISR to the timer daemon taskConsider a system that needs to send telemetry at different rates:
Instead of creating multiple tasks or using complex delay logic, you can use three software timers:
TimerHandle_t xSensorTimer, xDiagTimer, xLedTimer;void vSensorTimerCallback(TimerHandle_t xTimer) {read_and_send_sensor_data();}void vDiagTimerCallback(TimerHandle_t xTimer) {collect_and_send_diagnostics();}void vLedTimerCallback(TimerHandle_t xTimer) {toggle_status_led();}void setup_telemetry_timers(void) {// 10ms period for sensor dataxSensorTimer = xTimerCreate("Sensor", pdMS_TO_TICKS(10), pdTRUE, NULL, vSensorTimerCallback);// 100ms period for diagnosticsxDiagTimer = xTimerCreate("Diag", pdMS_TO_TICKS(100), pdTRUE, NULL, vDiagTimerCallback);// 500ms period for LED blinkxLedTimer = xTimerCreate("LED", pdMS_TO_TICKS(500), pdTRUE, NULL, vLedTimerCallback);// Start all timersif (xSensorTimer != NULL) xTimerStart(xSensorTimer, 0);if (xDiagTimer != NULL) xTimerStart(xDiagTimer, 0);if (xLedTimer != NULL) xTimerStart(xLedTimer, 0);}
[!WARNING] Integer Truncation Hazard with
pdMS_TO_TICKS:pdMS_TO_TICKSperforms integer division. If the requested millisecond period is shorter than the RTOS tick duration (for example, requesting 5ms on a system with a 100Hz tick rate, where a single tick is 10ms),pdMS_TO_TICKSwill truncate to0. Passing a period of0toxTimerCreate()is invalid and will cause it to returnNULL. Always ensure high-frequency periods resolve to at least1tick.
| Mechanism | RAM Overhead | Timing Precision | Context | Use Case |
|---|---|---|---|---|
| Software Timer | ~Timer control block + queue | Subject to scheduling jitter + tick resolution | Timer service task | Periodic callbacks, telemetry, watchdogs |
| Hardware Timer | Peripheral registers | Hardware-dependent (µs or better) | ISR | PWM, input capture, precise timing |
| Task Delay | Task stack + TCB | Tick resolution | Task context | Simple periodic tasks, delays |
Best Practices:
pvTimerGetTimerID()) to associate timers with specific data or objects, especially when using a shared callback function.configSUPPORT_STATIC_ALLOCATION is enabled, setting configUSE_TIMERS to 1 will cause a linker error unless you also implement the vApplicationGetTimerTaskMemory() callback to provide memory for the daemon task.Limitations:
configTICK_RATE_HZ). For instance, if the tick rate is 100Hz, the timer resolution is 10ms.FreeRTOS software timers offer an excellent balance of ease-of-use and functionality for periodic embedded tasks. They eliminate the need for complex hardware timer configuration while providing reliable, periodic callback execution in a safe task context. By understanding their configuration, limitations, and best practices, you can effectively use software timers for telemetry, diagnostics, periodic maintenance, and other timing-dependent functions in your embedded systems.
Quick Links
Legal Stuff


