ztimer high level timer abstraction layer

High level timer abstraction layer. More...

Detailed Description

High level timer abstraction layer.


ztimer provides a high level abstraction of hardware timers for application timing needs.

The basic functions of the ztimer module are ztimer_now(), ztimer_sleep(), ztimer_set() and ztimer_remove().

They all take a pointer to a clock device (or virtual timer device) as first parameter.

RIOT provides ZTIMER_USEC, ZTIMER_MSEC, ZTIMER_SEC by default, which can be used in an application by depending on the modules ztimer_usec, ztimer_msec or ztimer_sec. They will then automatically get configured.

Every ztimer clock allows multiple timeouts to be scheduled. They all provide unsigned 32bit range. In this documentation, a timeout or its corresponding struct will be called timer, and when the time out has passed, it has triggered.

As ztimer can use arbitrarily configurable backends, a ztimer clock instance can run at configurable frequencies. Throughout this documentation, one clock step is called tick. For the pre-defined clocks ZTIMER_USEC, ZTIMER_MSEC and ZTIMER_SEC, one clock tick corresponds to one microsecond, one millisecond or one second, respectively.

ztimer_now() returns the current clock tick count as uint32_t.

ztimer_sleep() pauses the current thread for the passed amount of clock ticks. E.g., ztimer_sleep(ZTIMER_SEC, 5); will suspend the currently running thread for five seconds.

ztimer_set() takes a ztimer_t object (containing a function pointer and void * argument) and an interval as arguments. After at least the interval (in number of ticks for the corresponding clock) has passed, the callback will be called in interrupt context. A timer can be cancelled using ztimer_remove().


#include "ztimer.h"
static void callback(void *arg)
int main()
ztimer_t timeout = { .callback=callback, .arg="Hello ztimer!" };
ztimer_set(ZTIMER_SEC, &timeout, 2);
ztimer_sleep(ZTIMER_SEC, 5);


clocks, virtual timers, chaining

The system is composed of clocks (virtual ztimer devices) which can be chained to create an abstract view of a hardware timer/counter device. Each ztimer clock acts as a operation on the next clock in the chain. At the end of each ztimer chain there is always some kind of counter device object.

Each clock device handles multiplexing (allowing multiple timers to be set) and extension to full 32bit.

Hardware interface submodules:

Filter submodules:

A common chain could be:

  1. ztimer_periph_timer (e.g., on top of an 1024Hz 16bit hardware timer)
  2. ztimer_convert_frac (to convert 1024 to 1000Hz)

This is how e.g., the clock ZTIMER_MSEC might be configured on a specific system.

Every clock in the chain can always be used on its own. E.g. in the example above, the ztimer_periph object can be used as ztimer clock with 1024Hz ticks in addition to the ztimer_convert_frac with 1000Hz.

Timer handling

Timers in ztimer are stored in a clock using a linked list for which each entry stores the difference to the previous entry in the timer (T[n]). The clock also stores the absolute time on which the relative offsets are based (B), effectively storing the absolute target time for each entry (as B + sum(T[0-n])). Storing the entries in this way allows all entries to use the full width of the used uint32_t, compared to storing the absolute time.

In order to prevent timer processing offset to add up, whenever a timer triggers, the list's absolute base time is set to the expected trigger time (B + T[0]). The underlying clock is then set to alarm at (now() + (now() - B) + T[1]). Thus even though the list is keeping relative offsets, the time keeping is done by keeping track of the absolute times.

Clock extension

The API always allows setting full 32bit relative offsets for every clock.

In some cases (e.g., a hardware timer only allowing getting/setting smaller values or a conversion which would overflow uint32_t for large intervals), ztimer takes care of extending timers. This is enabled automatically for every ztimer clock that has a "max_value" setting smaller than 2**32-1. If a ztimer_set() would overflow that value, intermediate intervals of length (max_value / 2) are set until the remaining interval fits into max_value. If extension is enabled for a clock, ztimer_now() uses interval checkpointing, storing the current time and corresponding clock tick value on each call and using that information to calculate the current time. This ensures correct ztimer_now() values if ztimer_now() is called at least once every "max_value" ticks. This is ensured by scheduling intermediate callbacks every (max_value / 2) ticks (even if no timeout is configured).


Care has been taken to avoid any unexpected behaviour of ztimer. In particular, ztimer tries hard to avoid underflows (setting a backend timer to a value at or behind the current time, causing the timer interrupt to trigger one whole timer period too late). This is done by always setting relative timeouts to backend timers, with interrupts disabled and ensuring that very small values don't cause underflows.

Configuration and convention

As timer hardware and capabilities is diverse and ztimer allows configuring and using arbitrary clock backends and conversions, it is envisioned to provide default configurations that application developers can assume to be available.

These are implemented by using pointers to ztimer clocks using default names.

For now, there are:

ZTIMER_USEC: clock providing microsecond ticks

ZTIMER_MSEC: clock providing millisecond ticks, using a low power timer if available on the platform

ZTIMER_SEC: clock providing second time, possibly using epoch semantics

These pointers are defined in ztimer.h and can be used like this:


They also need to be added to USEMODULE using the names ztimer_usec, ztimer_msec and ztimer_sec.

Some notes on ztimer's accuracy

  1. ztimer should wait "at least" the specified timeout
  2. due to its implementation details, expect +-1 clock tick systemic inaccuracy for all clocks.
  3. for the predefined clocks (ZTIMER_USEC, ZTIMER_MSEC, ZTIMER_SEC), tick conversion might be applied using ztimer_convert_*, causing errors due to integer conversion and rounding. In particular, most RTT's closest match for milliseconds are 1024Hz, which will be converted using convert_frac to provide the 1ms clock.
  4. Some platforms don't have any timer that can be configured to 1us. E.g., the fe310 (hifive1/b) only supports a 32kHz timer, and most atmegas only support 250kHz. In order to not completely break all applications using ZTIMER_USEC, that clock will only provide ~30.5ms respectively 4us maximum accuracy on those boards. With DEVELHELP=1, a warning will be printed at boot time.
  5. Due to +-1 systemic inaccuracies, it is advisable to use ZTIMER_MSEC for second timers up to 49 days (instead of ZTIMER_SEC).


 ztimer frequency conversion modules
 ztimer frequency conversion modules
 ztimer mock clock backend
 ztimer mock clock backend
 ztimer overhead utility
 ztimer overhead measurement functionality
 ztimer periph/rtc backend
 ztimer periph/rtc backend
 ztimer periph/rtt backend
 ztimer periph/rtt backend
 ztimer periph/timer backend
 ztimer periph/timer backend


file  ztimer.h
 ztimer API

Data Structures

struct  ztimer_base
 Minimum information for each timer. More...
struct  ztimer_t
 ztimer structure More...
struct  ztimer_ops_t
 ztimer backend method structure More...
struct  ztimer_clock
 ztimer device structure More...


#define MSG_ZTIMER   0xc83e
 msg type used by ztimer_msg_receive_timeout


typedef struct ztimer_base ztimer_base_t
 ztimer_base_t forward declaration
typedef struct ztimer_clock ztimer_clock_t
 ztimer_clock_t forward declaration
typedef uint32_t ztimer_now_t
 type for ztimer_now() result


void ztimer_handler (ztimer_clock_t *clock)
 main ztimer callback handler
void ztimer_set (ztimer_clock_t *clock, ztimer_t *timer, uint32_t val)
 Set a timer on a clock. More...
void ztimer_remove (ztimer_clock_t *clock, ztimer_t *timer)
 Remove a timer from a clock. More...
void ztimer_set_msg (ztimer_clock_t *clock, ztimer_t *timer, uint32_t offset, msg_t *msg, kernel_pid_t target_pid)
 Post a message after a delay. More...
int ztimer_msg_receive_timeout (ztimer_clock_t *clock, msg_t *msg, uint32_t timeout)
 receive a message (blocking, with timeout) More...
ztimer_now_t _ztimer_now_extend (ztimer_clock_t *clock)
 ztimer_now() for extending timers
static ztimer_now_t ztimer_now (ztimer_clock_t *clock)
 Get the current time from a clock. More...
void ztimer_periodic_wakeup (ztimer_clock_t *clock, uint32_t *last_wakeup, uint32_t period)
 Suspend the calling thread until the time (last_wakeup + period) More...
void ztimer_sleep (ztimer_clock_t *clock, uint32_t duration)
 Put the calling thread to sleep for the specified number of ticks. More...
void ztimer_set_wakeup (ztimer_clock_t *clock, ztimer_t *timer, uint32_t offset, kernel_pid_t pid)
 Set a timer that wakes up a thread. More...
void ztimer_set_timeout_flag (ztimer_clock_t *clock, ztimer_t *timer, uint32_t timeout)
 Set timeout thread flag after timeout. More...
void ztimer_update_head_offset (ztimer_clock_t *clock)
 Update ztimer clock head list offset.
void ztimer_init (void)
 Initialize the board-specific default ztimer configuration.


ztimer_clock_t *const ZTIMER_USEC
 Default ztimer microsecond clock.
ztimer_clock_t *const ZTIMER_MSEC
 Default ztimer millisecond clock.

Function Documentation

◆ ztimer_msg_receive_timeout()

int ztimer_msg_receive_timeout ( ztimer_clock_t clock,
msg_t msg,
uint32_t  timeout 

receive a message (blocking, with timeout)

Similar to msg_receive(), but with a timeout parameter. The function will return after waiting at most timeout ticks.

: This might function might leave a message with type MSG_ZTIMER in the thread's message queue, which must be handled (ignored).
[in]clockztimer clock to operate on
[out]msgpointer to buffer which will be filled if a message is received
[in]timeoutrelative timeout, in clock time units
>=0 if a message was received
-ETIME on timeout

◆ ztimer_now()

static ztimer_now_t ztimer_now ( ztimer_clock_t clock)

Get the current time from a clock.

[in]clockztimer clock to operate on
Current count on clock

Definition at line 404 of file ztimer.h.

◆ ztimer_periodic_wakeup()

void ztimer_periodic_wakeup ( ztimer_clock_t clock,
uint32_t *  last_wakeup,
uint32_t  period 

Suspend the calling thread until the time (last_wakeup + period)

This function can be used to create periodic wakeups.

When the function returns, last_wakeup is set to (last_wakeup + period).

last_wakeup should be set to ztimer_now(clock) before first call of the function.

If the time (last_wakeup + period) has already passed, the function sets last_wakeup to last_wakeup + period and returns immediately.

[in]clockztimer clock to operate on
[in]last_wakeupbase time stamp for the wakeup
[in]periodtime in ticks that will be added to last_wakeup

◆ ztimer_remove()

void ztimer_remove ( ztimer_clock_t clock,
ztimer_t timer 

Remove a timer from a clock.

This will place timer in the timer targets queue for clock.

This function does nothing if timer is not found in the timer queue of clock.

[in]clockztimer clock to operate on
[in]timertimer entry to remove

◆ ztimer_set()

void ztimer_set ( ztimer_clock_t clock,
ztimer_t timer,
uint32_t  val 

Set a timer on a clock.

This will place timer in the timer targets queue of clock.

The memory pointed to by timer is not copied and must remain in scope until the callback is fired or the timer is removed via ztimer_remove
[in]clockztimer clock to operate on
[in]timertimer entry to set
[in]valtimer target (relative ticks from now)

◆ ztimer_set_msg()

void ztimer_set_msg ( ztimer_clock_t clock,
ztimer_t timer,
uint32_t  offset,
msg_t msg,
kernel_pid_t  target_pid 

Post a message after a delay.

This function sets a timer that will send a message offset ticks from now.

The memory pointed to by timer and msg will not be copied, i.e. *timer and *msg needs to remain valid until the timer has triggered.
[in]clockztimer clock to operate on
[in]timerztimer timer struct to use
[in]offsetticks from now
[in]msgpointer to msg that will be sent
[in]target_pidpid the message will be sent to

◆ ztimer_set_timeout_flag()

void ztimer_set_timeout_flag ( ztimer_clock_t clock,
ztimer_t timer,
uint32_t  timeout 

Set timeout thread flag after timeout.

This function will set THREAD_FLAG_TIMEOUT on the current thread after timeout usec have passed.

[in]clockztimer clock to operate on
[in]timertimer struct to use
[in]timeouttimeout in ztimer_clock's ticks

◆ ztimer_set_wakeup()

void ztimer_set_wakeup ( ztimer_clock_t clock,
ztimer_t timer,
uint32_t  offset,
kernel_pid_t  pid 

Set a timer that wakes up a thread.

This function sets a timer that will wake up a thread when the timer has expired.

[in]clockztimer clock to operate on
[in]timertimer struct to work with.
[in]offsetclock ticks from now
[in]pidpid of the thread that will be woken up

◆ ztimer_sleep()

void ztimer_sleep ( ztimer_clock_t clock,
uint32_t  duration 

Put the calling thread to sleep for the specified number of ticks.

[in]clockztimer clock to use
[in]durationduration of sleep, in ztimer time units