[riot-devel] Timers

Kaspar Schleiser kaspar at schleiser.de
Wed Jan 24 23:37:56 CET 2018


Hi all,

I guess it is time to coordinate improving RIOT's timers - again.

IMO xtimer is a dead end. It was designed with good intentions, but
unfortunately with not much real-world experience. It has also
(d)evolved into a complex and inflexible #ifdef-mess...

Here's what I think is bad about it:

- it allows only one type of base timer. On most platforms it tries to
use one 1MHz periph/timer. there are PR's and hacks to make it use e.g.,
32KHz RTTs or low power timers, but they didn't make it to master. The
API basically enforces 1us ticks, and mapping unchanged code bases to
very different timers is just too error prone. Also, the API would
require choosing at compile time, which is just too inflexible.

- xtimer still doesn't support pm

- by forcing 1us time, xtimer also requires 64bit time functions in
order to support > 2**32us (~71min) timeouts

- xtimer is not ISR safe (xtimer_now() with <16bit base timers can break)

- xtimer_t is quite large (20b on 32bit platforms)

- xtimer's code has become very complex due to us/tick conversion and
the many #ifdefs that grew into it

Here's what I propose:

- re-write from scratch

- in the API, allow "instances", e.g.:

timer_now(instance);
timer_set(instance, timer_object);

where an "instance" provides state and function pointers.

- implement backends for periph/timer, rtt, rtc, lptim, systick, whatever

- provide global instance aliases that every board provides, e.g.,
"TIMER_USEC", "TIMER_MSEC", "TIMER_SEC". Map those to available timer
backends. Make it possible to enable / disable them as needed.

- allow application specific timers to use the same API (e.g., allow
setting up a very high speed timer, which can be used alongside
"default" timers)

- provide stackable "converters"
  e.g., if there's no MSEC resolution low power timer that can be mapped
to "TIMER_MSEC", use "TIMER_USEC", but transparently convert all values
  or if periph/timer doesn't support 32bit, create a "timer instance"
that transparently handles the extension.
  Maybe stack those (e.g., if the rtt backend only supports 1024hz and
16bit, stack a 1024 to 1000 converter on that, stack a 16bit to 32bit on
that and map the result to "TIMER_MSEC".
 this would lead to re-usable components that can also be individually
tested (think unittests using a software-controlled fake timer).

- provide either clear convention (e.g., TIMER_USEC stops when sleeping,
unless a timer using it is set, TIMER_MSEC keeps running in low power
mode) or controlling API (e.g., "timer_block_sleep(TIMER_USEC)" for
behaviour in sleep modes

- try to slim down the timer struct (if possible)

- drop the 64bit API (usec resolution over 64bit range is unrealistic on
real hardware. if, for larger ranges, TIMER_MSEC or TIMER_SEC can be
used, the range that 64bit provides is not needed anymore. thus all the
expensive 64bit arithmetic can be dropped)

- consider new insights like the clock domain issue fixed by [1]

- obviously, avoid long-standing xtimer bugs like the ISR unsafeness

The main point I would like to push is the introduction of "timer
instances", which would basically make the timer interface object
oriented. This would allow having multiple implementations with
different tradeoffs without changing actual application code.

What do you think?

Kaspar

[1] https://github.com/RIOT-OS/RIOT/pull/7053


More information about the devel mailing list