The magic behind Monotonics
Internally, all monotonics use a Timer Queue, which is a priority queue with entries describing the time at which their respective Future
s should complete.
Implementing a Monotonic
timer for scheduling
The rtic-time
framework is flexible because it can use any timer which has compare-match and optionally supporting overflow interrupts for scheduling. The single requirement to make a timer usable with RTIC is implementing the rtic-time::Monotonic
trait.
For RTIC 2.0, we assume that the user has a time library, e.g. fugit
, as the basis for all time-based operations when implementing Monotonic
. These libraries make it much easier to correctly implement the Monotonic
trait, allowing the use of almost any timer in the system for scheduling.
The trait documents the requirements for each method. There are reference implementations available in rtic-monotonics
that can be used for inspriation.
Systick based
, runs at a fixed interrupt (tick) rate - with some overhead but simple and provides support for large time spansRP2040 Timer
, a "proper" implementation with support for waiting for long periods without interrupts. Clearly demonstrates how to use theTimerQueue
to handle scheduling.nRF52 timers
implements monotonic & Timer Queue for the RTC and normal timers in nRF52's
Contributing
Contributing new implementations of Monotonic
can be done in multiple ways:
- Implement the trait behind a feature flag in
rtic-monotonics
, and create a PR for them to be included in the main RTIC repository. This way, the implementations of are in-tree, RTIC can guarantee their correctness, and can update them in the case of a new release. - Implement the changes in an external repository. Doing so will not have them included in
rtic-monotonics
, but may make it easier to do so in the future.
The timer queue
The timer queue is implemented as a list based priority queue, where list-nodes are statically allocated as part of the Future
created when await
-ing a Future created when waiting for the monotonic. Thus, the timer queue is infallible at run-time (its size and allocation are determined at compile time).
Similarly the channels implementation, the timer-queue implementation relies on a global Critical Section (CS) for race protection. For the examples a CS implementation is provided by adding --features test-critical-section
to the build options.