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