SysTick Timer
System timer for OS heartbeats.
Every real-time operating system and scheduling kernel needs a reliable heartbeat, a timer that fires at a fixed interval to manage task switching and time-keeping. The SysTick timer is a dedicated 24-bit countdown timer built into every Cortex-M processor core, designed specifically for this purpose. It operates independently of peripheral timers and is always available regardless of which STM32 variant is used.
Core Concept: SysTick Architecture
The SysTick timer contains four registers. The CTRL register (Control and Status) enables the counter, enables its interrupt, and selects the clock source. The LOAD register holds the reload value, which is copied into the current value register each time the counter reaches zero. The VAL register is the actual 24-bit down-counter. The CALIB register provides calibration data for a 10 ms tick reference.
Since SysTick counts down from LOAD to zero, the period is determined by the LOAD value and the clock frequency. When VAL reaches zero, the COUNTFLAG bit in CTRL is set, VAL is reloaded from LOAD, and if the TICKINT bit is enabled, the SysTick_Handler interrupt fires. This creates a very regular periodic interrupt with minimal jitter.
STM32 HAL uses SysTick to generate 1 ms ticks. HAL_Init() calls SystemCoreClockUpdate() and then configures SysTick for 1 ms. The global variable uwTick is incremented in SysTick_Handler, and HAL_Delay() simply waits until uwTick increments by the requested delay value. This is why HAL_Delay() is not suitable inside ISRs.
Mathematical Expression
To generate a tick interrupt every T milliseconds, the LOAD register value is calculated as follows. The SysTick clock frequency is either the processor AHB clock or AHB divided by 8, selected by the CLKSOURCE bit. With AHB as source:
LOAD = (SysTick_CLK x T_tick) - 1. The -1 accounts for the fact that LOAD=0 gives one clock cycle of execution before reload. For example, at 168 MHz system clock with 1 ms tick: LOAD = 168000 - 1 = 167999. The maximum LOAD value is 2^24 - 1 = 16,777,215, limiting the maximum tick period.
Practical Understanding
When using FreeRTOS with STM32, the RTOS configures SysTick itself during vTaskStartScheduler(). FreeRTOS sets SysTick to fire at configTICK_RATE_HZ (typically 1000 Hz for 1 ms ticks). The SysTick_Handler then calls xPortSysTickHandler() which handles task context switching.
A critical point for RTOS use: SysTick must have the lowest possible interrupt priority among all interrupts that call FreeRTOS API functions. This is because SysTick drives the scheduler, and calling scheduler functions from higher-priority ISRs can corrupt the kernel state. FreeRTOS sets SysTick priority to the lowest allowed level automatically.
Given:
System clock (AHB) = 72 MHz
Desired SysTick period = 1 ms
Clock source = AHB (CLKSOURCE = 1)
Why this formula applies:
SysTick counts down from LOAD to 0. Total count per tick = LOAD+1 cycles.
Formula:
LOAD = (CLK_Hz x T_seconds) - 1
Substitution:
LOAD = (72,000,000 x 0.001) - 1
LOAD = 72,000 - 1
Calculation:
LOAD = 71,999
Verification: 71,999 + 1 = 72,000 cycles
Time = 72,000 / 72,000,000 = 0.001 s
Final Answer:
SysTick LOAD = 71,999 for 1 ms tick at 72 MHzExam Tip: SysTick LOAD is 24-bit, so the maximum value is 16,777,215. If the required LOAD exceeds this, you must either reduce the clock source (use AHB/8) or use a general-purpose timer instead. This limit is frequently tested in embedded systems questions.
SysTick Register Map and Tick Flow
- SysTick is a 24-bit down-counter; it counts from LOAD down to 0 then reloads automatically.
- CLKSOURCE=1 uses AHB clock directly; CLKSOURCE=0 uses AHB/8, extending maximum tick period.
- Writing any value to VAL register clears it and also clears the COUNTFLAG bit.
- HAL_Delay() relies on SysTick and must not be called from ISRs with priority higher than SysTick.
- FreeRTOS reconfigures SysTick during startup; do not manually reconfigure SysTick when using RTOS.
Quick Revision
- SysTick is a 24-bit downcounter built into every Cortex-M core, not a peripheral timer.
- LOAD formula: LOAD = (CLK_Hz x T_seconds) - 1. Maximum LOAD = 16,777,215 (24-bit limit).
- Four registers: CTRL (enable/IRQ/clksrc), LOAD (reload value), VAL (current count), CALIB.
- CLKSOURCE bit: 1 = AHB, 0 = AHB/8. Use AHB/8 for longer tick periods.
- HAL uses SysTick for 1 ms tick via uwTick global incremented in SysTick_Handler.
- In FreeRTOS, SysTick must have the lowest interrupt priority to prevent kernel corruption.
- Exam trap: if LOAD exceeds 16,777,215, SysTick cannot achieve that period at the given clock.
SysTick Timer Practice
Test your knowledge on this topic!
Q1.What is the standard hardware architecture of the Cortex-M SysTick timer?
Related Articles
Watchdog Timer
Independent vs Windowed watchdog.
10 min read
PWM Generation
Pulse Width Modulation for motor control, LED dimming.
5 min read
Real Time Clock
RTC features and backup domain.
12 min read
Output Compare
Generating precise delays and signals.
6 min read
8253/54 Timer
Programmable Interval Timer, modes.
6 min read