High level timer abstraction layer. More...
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().
Example:
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:
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.
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.
Currently, a sorted singly linked list is used for storing the timers. This choice has some implications:
By making the list doubly-linked, removal of timer objects could be easily made a constant operation, at the price of another pointer per timer object (for "previous" element).
If deemed necessary, the linked list can be exchanged our augmented with another data structure providing better algorithmic guarantees. It remains to be shown whether the increased complexity would lead to better performance for any reasonable amount of active timers.
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.
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:
ztimer_now(ZTIMER_USEC);
They also need to be added to USEMODULE using the names ztimer_usec
, ztimer_msec
and ztimer_sec
.
Modules | |
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 | |
Files | |
file | config.h |
ztimer default configuration | |
file | periodic.h |
Periodic ztimer API. | |
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... | |
Macros | |
#define | ZTIMER_CLOCK_NO_REQUIRED_PM_MODE (UINT8_MAX) |
Disables interaction with pm_layered for a clock. | |
#define | MSG_ZTIMER 0xc83e |
msg type used by ztimer_msg_receive_timeout | |
Typedefs | |
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 | |
Functions | |
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... | |
static void | ztimer_spin (ztimer_clock_t *clock, uint32_t duration) |
Busy-wait specified duration. 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. | |
static void | ztimer_init_extend (ztimer_clock_t *clock) |
Initialize possible ztimer extension intermediate timer. More... | |
Variables | |
ztimer_clock_t *const | ZTIMER_USEC |
Default ztimer microsecond clock. | |
ztimer_clock_t *const | ZTIMER_MSEC |
Default ztimer millisecond clock. | |
ztimer_clock_t *const | ZTIMER_USEC_BASE |
Base ztimer for the microsecond clock (ZTIMER_USEC) More... | |
ztimer_clock_t *const | ZTIMER_MSEC_BASE |
Base ztimer for the millisecond clock (ZTIMER_MSEC) More... | |
|
inlinestatic |
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.
[in] | clock | ztimer clock to operate on |
[out] | msg | pointer to buffer which will be filled if a message is received |
[in] | timeout | relative timeout, in clock time units |
|
inlinestatic |
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] | clock | ztimer clock to operate on |
[in] | last_wakeup | base time stamp for the wakeup |
[in] | period | time in ticks that will be added to last_wakeup |
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] | clock | ztimer clock to operate on |
[in] | timer | timer entry to remove |
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
.
timer
is not copied and must remain in scope until the callback is fired or the timer is removed via ztimer_remove[in] | clock | ztimer clock to operate on |
[in] | timer | timer entry to set |
[in] | val | timer target (relative ticks from now) |
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.
timer
and msg
will not be copied, i.e. *timer
and *msg
needs to remain valid until the timer has triggered.[in] | clock | ztimer clock to operate on |
[in] | timer | ztimer timer struct to use |
[in] | offset | ticks from now |
[in] | msg | pointer to msg that will be sent |
[in] | target_pid | pid the message will be sent to |
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] | clock | ztimer clock to operate on |
[in] | timer | timer struct to use |
[in] | timeout | timeout in ztimer_clock's ticks |
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] | clock | ztimer clock to operate on |
[in] | timer | timer struct to work with. |
[in] | offset | clock ticks from now |
[in] | pid | pid of the thread that will be woken up |
void ztimer_sleep | ( | ztimer_clock_t * | clock, |
uint32_t | duration | ||
) |
Put the calling thread to sleep for the specified number of ticks.
[in] | clock | ztimer clock to use |
[in] | duration | duration of sleep, in ztimer time units |
|
inlinestatic |
ztimer_clock_t* const ZTIMER_MSEC_BASE |
Base ztimer for the millisecond clock (ZTIMER_MSEC)
This ztimer will reference the counter device object at the end of the chain of ztimer_clock_t for ZTIMER_MSEC.
If ztimer_periph_rtt is not used then ZTIMER_MSEC_BASE will reference the same base as ZTIMER_USEC_BASE.
If the base counter device object's frequency (CONFIG_ZTIMER_MSEC_BASE_FREQ) is not 1KHz then ZTIMER_MSEC will be converted on top of this one. Otherwise they will reference the same ztimer_clock.
To avoid chained conversions its better to base new ztimer_clock on top of ZTIMER_MSEC_BASE running at CONFIG_ZTIMER_MSEC_BASE_FREQ.
ztimer_clock_t* const ZTIMER_USEC_BASE |
Base ztimer for the microsecond clock (ZTIMER_USEC)
This ztimer will reference the counter device object at the end of the chain of ztimer_clock_t for ZTIMER_USEC.
If the base counter device object's frequency (CONFIG_ZTIMER_USEC_BASE_FREQ) is not 1MHz then ZTIMER_USEC will be converted on top of this one. Otherwise they will reference the same ztimer_clock.
To avoid chained conversions its better to base new ztimer_clock on top of ZTIMER_USEC_BASE running at CONFIG_ZTIMER_USEC_BASE_FREQ.