diff --git a/examples/timer_periodic_wakeup/main.c b/examples/timer_periodic_wakeup/main.c index b2925f330941..aeddd026fa79 100644 --- a/examples/timer_periodic_wakeup/main.c +++ b/examples/timer_periodic_wakeup/main.c @@ -27,7 +27,7 @@ int main(void) { - uint32_t last_wakeup = xtimer_now(); + uint64_t last_wakeup = xtimer_now(); while(1) { xtimer_periodic_wakeup(&last_wakeup, INTERVAL); diff --git a/sys/include/xtimer.h b/sys/include/xtimer.h index 6b3168d08ba5..29b46cefcc20 100644 --- a/sys/include/xtimer.h +++ b/sys/include/xtimer.h @@ -161,7 +161,7 @@ static inline void xtimer_spin(uint32_t microseconds); * @param[in] last_wakeup base time stamp for the wakeup * @param[in] period time in microseconds that will be added to last_wakeup */ -void xtimer_periodic_wakeup(uint32_t *last_wakeup, uint32_t period); +void xtimer_periodic_wakeup(uint64_t *last_wakeup, uint32_t period); /** * @brief Set a timer that sends a message @@ -407,7 +407,7 @@ int xtimer_msg_receive_timeout64(msg_t *msg, uint64_t us); #if XTIMER_WIDTH != 32 #define XTIMER_MASK ((0xffffffff >> XTIMER_WIDTH) << XTIMER_WIDTH) #else -#define XTIMER_MASK (0) +#define XTIMER_MASK (0U) #endif #define XTIMER_MASK_SHIFTED XTIMER_TICKS_TO_USEC(XTIMER_MASK) diff --git a/sys/include/xtimer/implementation.h b/sys/include/xtimer/implementation.h index cac6b8576e8b..3f4a5aa23adc 100644 --- a/sys/include/xtimer/implementation.h +++ b/sys/include/xtimer/implementation.h @@ -31,8 +31,11 @@ extern "C" { #if XTIMER_MASK extern volatile uint32_t _xtimer_high_cnt; +#define XTIMER_PERIOD_LENGTH XTIMER_TICKS_TO_USEC(~XTIMER_MASK + 1) #endif +#define XTIMER_MSBMASK (((uint32_t)1)<<(XTIMER_WIDTH - 1 + XTIMER_SHIFT)) + #if (XTIMER_SHIFT < 0) #define XTIMER_USEC_TO_TICKS(value) ( (value) << -XTIMER_SHIFT ) #define XTIMER_TICKS_TO_USEC(value) ( (value) >> -XTIMER_SHIFT ) @@ -71,7 +74,7 @@ static inline uint32_t _xtimer_lltimer_mask(uint32_t val) * @brief xtimer internal stuff * @internal */ -int _xtimer_set_absolute(xtimer_t *timer, uint32_t target); +void _xtimer_set_absolute(xtimer_t *timer); void _xtimer_set64(xtimer_t *timer, uint32_t offset, uint32_t long_offset); void _xtimer_sleep(uint32_t offset, uint32_t long_offset); /** @} */ @@ -89,18 +92,26 @@ void _xtimer_sleep(uint32_t offset, uint32_t long_offset); static inline uint32_t xtimer_now(void) { #if XTIMER_MASK - uint32_t latched_high_cnt, now; - - /* _high_cnt can change at any time, so check the value before - * and after reading the low-level timer. If it hasn't changed, - * then it can be safely applied to the timer count. */ - - do { - latched_high_cnt = _xtimer_high_cnt; - now = _xtimer_lltimer_now(); - } while (_xtimer_high_cnt != latched_high_cnt); - - return latched_high_cnt | now; + uint32_t high_cnt = _xtimer_high_cnt; + uint32_t now = _xtimer_lltimer_now(); + + /* _xtimer_high_cnt and the underlying hardware timer both count the most + * significant bit of the underlying hardware timer. + * + * Should the counter variable indicate we're in the first half of the + * hardware timer period, but the hardware timer indicates otherwise, the + * OR handles the missed interrupt. + * + * Should the counter variable indicate we're in the second half of the + * hardware timer period, but the actual timer value does not, we + * compensate by adding a half timer period. + * + * That way, timer overflow interrupts which are up to half a timer period + * late can be compensated for. + */ + + return (high_cnt | now) + + ((uint32_t)((high_cnt & (XTIMER_MSBMASK)) && (~now & XTIMER_MSBMASK))) * (XTIMER_PERIOD_LENGTH >> 1); #else return _xtimer_lltimer_now(); #endif diff --git a/sys/xtimer/xtimer.c b/sys/xtimer/xtimer.c index efe19d635eb6..d92a31e5ae70 100644 --- a/sys/xtimer/xtimer.c +++ b/sys/xtimer/xtimer.c @@ -58,70 +58,21 @@ void _xtimer_sleep(uint32_t offset, uint32_t long_offset) mutex_lock(&mutex); } -void xtimer_periodic_wakeup(uint32_t *last_wakeup, uint32_t period) { +void xtimer_periodic_wakeup(uint64_t *last_wakeup, uint32_t period) +{ xtimer_t timer; mutex_t mutex = MUTEX_INIT; + *last_wakeup += period; timer.callback = _callback_unlock_mutex; timer.arg = (void*) &mutex; - uint32_t target = (*last_wakeup) + period; - uint32_t now = xtimer_now(); - /* make sure we're not setting a value in the past */ - if (now < (*last_wakeup)) { - /* base timer overflowed between last_wakeup and now */ - if (!((now < target) && (target < (*last_wakeup)))) { - /* target time has already passed */ - goto out; - } - } - else { - /* base timer did not overflow */ - if ((((*last_wakeup) <= target) && (target <= now))) { - /* target time has already passed */ - goto out; - } - } + timer.long_target = (*last_wakeup)<<32; + timer.target = *last_wakeup; - /* - * For large offsets, set an absolute target time. - * As that might cause an underflow, for small offsets, set a relative - * target time. - * For very small offsets, spin. - */ - /* - * Note: last_wakeup _must never_ specify a time in the future after - * _xtimer_periodic_sleep returns. - * If this happens, last_wakeup may specify a time in the future when the - * next call to _xtimer_periodic_sleep is made, which in turn will trigger - * the overflow logic above and make the next timer fire too early, causing - * last_wakeup to point even further into the future, leading to a chain - * reaction. - * - * tl;dr Don't return too early! - */ - uint32_t offset = target - now; - DEBUG("xps, now: %9" PRIu32 ", tgt: %9" PRIu32 ", off: %9" PRIu32 "\n", now, target, offset); - if (offset < XTIMER_PERIODIC_SPIN) { - xtimer_spin(offset); - } - else { - if (offset < XTIMER_PERIODIC_RELATIVE) { - /* NB: This will overshoot the target by the amount of time it took - * to get here from the beginning of xtimer_periodic_wakeup() - * - * Since interrupts are normally enabled inside this function, this time may - * be undeterministic. */ - target = xtimer_now() + offset; - } - mutex_lock(&mutex); - DEBUG("xps, abs: %" PRIu32 "\n", target); - _xtimer_set_absolute(&timer, target); - mutex_lock(&mutex); - } - -out: - *last_wakeup = target; + mutex_lock(&mutex); + _xtimer_set_absolute(&timer); + mutex_lock(&mutex); } static void _callback_msg(void* arg) diff --git a/sys/xtimer/xtimer_core.c b/sys/xtimer/xtimer_core.c index 45140d7b1600..2d0a03a44ddc 100644 --- a/sys/xtimer/xtimer_core.c +++ b/sys/xtimer/xtimer_core.c @@ -25,34 +25,49 @@ #include "irq.h" /* WARNING! enabling this will have side effects and can lead to timer underflows. */ -#define ENABLE_DEBUG 0 +#define ENABLE_DEBUG (0) #include "debug.h" -static volatile int _in_handler = 0; +static int _in_handler = 0; static volatile uint32_t _long_cnt = 0; + +static uint32_t _safe_long_cnt(uint32_t now) +{ + uint32_t long_value = _long_cnt; + + /* _long_cnt counts half 32bit intervals. so to compensate for a possibly + * late overflow interrupt, compare if _long_cnt's LSB and the timer's MSB + * match. If (_long_cnt & 1) is set but the timer is already in the next + * period ((now >> 32) == 0), the overflow interrupt has been missed. + */ + + return (long_value >> 1) + ((long_value & 1) && (~now >> 31)); +} + #if XTIMER_MASK volatile uint32_t _xtimer_high_cnt = 0; +#define XTIMER_HALFTICK (_xtimer_high_cnt & XTIMER_MSBMASK) +#define XTIMER_LL_HALFTICK (_xtimer_lltimer_now() & XTIMER_MSBMASK) +#else +#define XTIMER_HALFTICK (_long_cnt & 1) +#define XTIMER_LL_HALFTICK (_xtimer_lltimer_now() >> 31) #endif -static inline void xtimer_spin_until(uint32_t value); +#define _NEXT_OVERFLOW_TICK (_xtimer_lltimer_mask(0xFFFFFFFF) >> (!XTIMER_HALFTICK)) static xtimer_t *timer_list_head = NULL; -static xtimer_t *overflow_list_head = NULL; -static xtimer_t *long_list_head = NULL; static void _add_timer_to_list(xtimer_t **list_head, xtimer_t *timer); -static void _add_timer_to_long_list(xtimer_t **list_head, xtimer_t *timer); static void _shoot(xtimer_t *timer); static void _remove(xtimer_t *timer); +static uint32_t _time_left(xtimer_t *timer); static inline void _lltimer_set(uint32_t target); -static uint32_t _time_left(uint32_t target, uint32_t reference); +static void _update_lltimer(void); static void _timer_callback(void); static void _periph_timer_callback(void *arg, int chan); -static inline int _this_high_period(uint32_t target); - static inline int _is_set(xtimer_t *timer) { return (timer->target || timer->long_target); @@ -72,23 +87,14 @@ void xtimer_init(void) timer_init(XTIMER_DEV, XTIMER_USEC_TO_TICKS(1000000ul), _periph_timer_callback, NULL); /* register initial overflow tick */ - _lltimer_set(0xFFFFFFFF); + _update_lltimer(); } static void _xtimer_now64(uint32_t *short_term, uint32_t *long_term) { - uint32_t before, after, long_value; - - /* loop to cope with possible overflow of xtimer_now() */ - do { - before = xtimer_now(); - long_value = _long_cnt; - after = xtimer_now(); - - } while(before > after); - - *short_term = after; - *long_term = long_value; + uint32_t short_value = xtimer_now(); + *short_term = short_value; + *long_term = _safe_long_cnt(short_value); } uint64_t xtimer_now64(void) @@ -99,93 +105,33 @@ uint64_t xtimer_now64(void) return ((uint64_t)long_term<<32) + short_term; } -void _xtimer_set64(xtimer_t *timer, uint32_t offset, uint32_t long_offset) -{ - DEBUG(" _xtimer_set64() offset=%" PRIu32 " long_offset=%" PRIu32 "\n", offset, long_offset); - if (!long_offset) { - /* timer fits into the short timer */ - xtimer_set(timer, (uint32_t) offset); - } - else { - int state = irq_disable(); - if (_is_set(timer)) { - _remove(timer); - } - - _xtimer_now64(&timer->target, &timer->long_target); - timer->target += offset; - timer->long_target += long_offset; - if (timer->target < offset) { - timer->long_target++; - } - - _add_timer_to_long_list(&long_list_head, timer); - irq_restore(state); - DEBUG("xtimer_set64(): added longterm timer (long_target=%" PRIu32 " target=%" PRIu32 ")\n", - timer->long_target, timer->target); - } -} - void xtimer_set(xtimer_t *timer, uint32_t offset) { - DEBUG("timer_set(): offset=%" PRIu32 " now=%" PRIu32 " (%" PRIu32 ")\n", offset, xtimer_now(), _xtimer_lltimer_now()); - if (!timer->callback) { - DEBUG("timer_set(): timer has no callback.\n"); - return; - } - - xtimer_remove(timer); - - if (offset < XTIMER_BACKOFF) { - xtimer_spin(offset); - _shoot(timer); - } - else { - uint32_t target = xtimer_now() + offset; - _xtimer_set_absolute(timer, target); - } -} - -static void _periph_timer_callback(void *arg, int chan) -{ - (void)arg; - (void)chan; - _timer_callback(); -} - -static void _shoot(xtimer_t *timer) -{ - timer->callback(timer->arg); + _xtimer_set64(timer, offset, 0); } -static inline void _lltimer_set(uint32_t target) +void _xtimer_set64(xtimer_t *timer, uint32_t offset, uint32_t long_offset) { - if (_in_handler) { - return; - } - DEBUG("_lltimer_set(): setting %" PRIu32 "\n", _xtimer_lltimer_mask(target)); -#ifdef XTIMER_SHIFT - target = XTIMER_USEC_TO_TICKS(target); - if (!target) { - target++; + DEBUG(" _xtimer_set64() offset=%" PRIu32 " long_offset=%" PRIu32 "\n", offset, long_offset); + _xtimer_now64(&timer->target, &timer->long_target); + timer->target += offset; + timer->long_target += long_offset; + if (timer->target < offset) { + timer->long_target++; } -#endif - timer_set_absolute(XTIMER_DEV, XTIMER_CHAN, _xtimer_lltimer_mask(target)); + + _xtimer_set_absolute(timer); } -int _xtimer_set_absolute(xtimer_t *timer, uint32_t target) +void _xtimer_set_absolute(xtimer_t *timer) { - uint32_t now = xtimer_now(); - int res = 0; - - DEBUG("timer_set_absolute(): now=%" PRIu32 " target=%" PRIu32 "\n", now, target); + DEBUG("timer_set_absolute(): now=%" PRIu32 " target=%" PRIu32 "\n",xtimer_now(), timer->target); timer->next = NULL; - if ((target >= now) && ((target - XTIMER_BACKOFF) < now)) { - /* backoff */ - xtimer_spin_until(target + XTIMER_BACKOFF); + if (_time_left(timer) < XTIMER_BACKOFF) { + while(_time_left(timer)); _shoot(timer); - return 0; + return; } unsigned state = irq_disable(); @@ -193,48 +139,30 @@ int _xtimer_set_absolute(xtimer_t *timer, uint32_t target) _remove(timer); } - timer->target = target; - timer->long_target = _long_cnt; - if (target < now) { - timer->long_target++; - } + _add_timer_to_list(&timer_list_head, timer); - if ( (timer->long_target > _long_cnt) || !_this_high_period(target) ) { - DEBUG("xtimer_set_absolute(): the timer doesn't fit into the low-level timer's mask.\n"); - _add_timer_to_long_list(&long_list_head, timer); - } - else { - if (_xtimer_lltimer_mask(now) >= target) { - DEBUG("xtimer_set_absolute(): the timer will expire in the next timer period\n"); - _add_timer_to_list(&overflow_list_head, timer); - } - else { - DEBUG("timer_set_absolute(): timer will expire in this timer period.\n"); - _add_timer_to_list(&timer_list_head, timer); - - if (timer_list_head == timer) { - DEBUG("timer_set_absolute(): timer is new list head. updating lltimer.\n"); - _lltimer_set(target - XTIMER_OVERHEAD); - } - } + if (timer_list_head == timer) { + DEBUG("timer_set_absolute(): timer is new list head. updating lltimer.\n"); + _update_lltimer(); } irq_restore(state); - - return res; } -static void _add_timer_to_list(xtimer_t **list_head, xtimer_t *timer) + +static void _periph_timer_callback(void *arg, int chan) { - while (*list_head && (*list_head)->target <= timer->target) { - list_head = &((*list_head)->next); - } + (void)arg; + (void)chan; + _timer_callback(); +} - timer->next = *list_head; - *list_head = timer; +static void _shoot(xtimer_t *timer) +{ + timer->callback(timer->arg); } -static void _add_timer_to_long_list(xtimer_t **list_head, xtimer_t *timer) +static void _add_timer_to_list(xtimer_t **list_head, xtimer_t *timer) { while (*list_head && (((*list_head)->long_target < timer->long_target) @@ -262,23 +190,11 @@ static int _remove_timer_from_list(xtimer_t **list_head, xtimer_t *timer) static void _remove(xtimer_t *timer) { if (timer_list_head == timer) { - uint32_t next; timer_list_head = timer->next; - if (timer_list_head) { - /* schedule callback on next timer target time */ - next = timer_list_head->target - XTIMER_OVERHEAD; - } - else { - next = _xtimer_lltimer_mask(0xFFFFFFFF); - } - _lltimer_set(next); + _update_lltimer(); } else { - if (!_remove_timer_from_list(&timer_list_head, timer)) { - if (!_remove_timer_from_list(&overflow_list_head, timer)) { - _remove_timer_from_list(&long_list_head, timer); - } - } + _remove_timer_from_list(&timer_list_head, timer); } } @@ -291,143 +207,83 @@ void xtimer_remove(xtimer_t *timer) irq_restore(state); } -static uint32_t _time_left(uint32_t target, uint32_t reference) +static uint32_t _time_left(xtimer_t *timer) { - uint32_t now = _xtimer_lltimer_now(); + uint32_t short_now, long_now, result; + _xtimer_now64(&short_now, &long_now); - if (now < reference) { + if (timer->long_target < long_now) { return 0; } - if (target > now) { - return target - now; - } - else { - return 0; + if (timer->long_target > long_now) { + return 0xffffffff; } -} - -static inline int _this_high_period(uint32_t target) { -#if XTIMER_MASK - return (target & XTIMER_MASK_SHIFTED) == _xtimer_high_cnt; -#else - (void)target; - return 1; -#endif -} -/** - * @brief compare two timers' target values, return the one with lower value. - * - * if either is NULL, return the other. - * if both are NULL, return NULL. - */ -static inline xtimer_t *_compare(xtimer_t *a, xtimer_t *b) -{ - if (a && b) { - return ((a->target <= b->target) ? a : b); + result = timer->target - short_now; + if (result > timer->target) { + return 0; } else { - return (a ? a : b); + return result; } } -/** - * @brief merge two timer lists, return head of new list - */ -static xtimer_t *_merge_lists(xtimer_t *head_a, xtimer_t *head_b) +static inline void _lltimer_set(uint32_t target) { - xtimer_t *result_head = _compare(head_a, head_b); - xtimer_t *pos = result_head; - - while(1) { - head_a = head_a->next; - head_b = head_b->next; - if (!head_a) { - pos->next = head_b; - break; - } - if (!head_b) { - pos->next = head_a; - break; - } - - pos->next = _compare(head_a, head_b); - pos = pos->next; + if (_in_handler) { + return; } - - return result_head; +#ifdef XTIMER_SHIFT + target = XTIMER_USEC_TO_TICKS(target); + if (!target) { + target++; + } +#endif + if (_xtimer_lltimer_mask(target - _xtimer_lltimer_now()) > (_xtimer_lltimer_mask(0xFFFFFFFF)>>1) ) { + target = _xtimer_lltimer_now() + XTIMER_ISR_BACKOFF; + } + timer_set_absolute(XTIMER_DEV, XTIMER_CHAN, _xtimer_lltimer_mask(target)); } -/** - * @brief parse long timers list and copy those that will expire in the current - * short timer period - */ -static void _select_long_timers(void) +static void _update_lltimer(void) { - xtimer_t *select_list_start = long_list_head; - xtimer_t *select_list_last = NULL; - - /* advance long_list head so it points to the first timer of the next (not - * just started) "long timer period" */ - while (long_list_head) { - if ((long_list_head->long_target <= _long_cnt) && _this_high_period(long_list_head->target)) { - select_list_last = long_list_head; - long_list_head = long_list_head->next; - } - else { - /* remaining long_list timers belong to later long periods */ - break; - } - } - - /* cut the "selected long timer list" at the end */ - if (select_list_last) { - select_list_last->next = NULL; - } + uint32_t next_target = _NEXT_OVERFLOW_TICK; - /* merge "current timer list" and "selected long timer list" */ if (timer_list_head) { - if (select_list_last) { - /* both lists are non-empty. merge. */ - timer_list_head = _merge_lists(timer_list_head, select_list_start); - } - else { - /* "selected long timer list" is empty, nothing to do */ - } - } - else { /* current timer list is empty */ - if (select_list_last) { - /* there's no current timer list, but a non-empty "selected long - * timer list". So just use that list as the new current timer - * list.*/ - timer_list_head = select_list_start; + uint32_t left = _time_left(timer_list_head); + if (left < (_NEXT_OVERFLOW_TICK - _xtimer_lltimer_now())) { + /* schedule callback on next timer target time */ + next_target = _xtimer_lltimer_mask(_xtimer_lltimer_now() + left - XTIMER_OVERHEAD); } } + + /* set low level timer */ + _lltimer_set(next_target); } /** - * @brief handle low-level timer overflow, advance to next short timer period + * @brief handle low-level timer half-period, advance to next half period */ -static void _next_period(void) +static void _next_half_period(void) { #if XTIMER_MASK - /* advance <32bit mask register */ - _xtimer_high_cnt += ~XTIMER_MASK_SHIFTED + 1; - if (_xtimer_high_cnt == 0) { - /* high_cnt overflowed, so advance >32bit counter */ + /* + * advance <32bit high count variable. + * (XTIMER_PERIOD_LENGTH >> 1) evaluates to 0x8000 for 16bit timers + * with XTIMER_MASK==0xFFFF. + */ + _xtimer_high_cnt += (XTIMER_PERIOD_LENGTH >> 1); + + if ((_xtimer_high_cnt == 0) || (_xtimer_high_cnt == (1LU << 31))) { + /* high_cnt overflowed or reached half 32bit period, + * so advance 32bit half-period counter */ _long_cnt++; } #else - /* advance >32bit counter */ + /* advance 32bit half-period counter */ _long_cnt++; #endif - - /* swap overflow list to current timer list */ - timer_list_head = overflow_list_head; - overflow_list_head = NULL; - - _select_long_timers(); } /** @@ -435,103 +291,37 @@ static void _next_period(void) */ static void _timer_callback(void) { - uint32_t next_target; - uint32_t reference; - + DEBUG("T: now=%" PRIu32 " (ll=%" PRIu32 ")\n", xtimer_now(), _xtimer_lltimer_now()); _in_handler = 1; - DEBUG("_timer_callback() now=%" PRIu32 " (%" PRIu32 ")pleft=%" PRIu32 "\n", xtimer_now(), - _xtimer_lltimer_mask(xtimer_now()), _xtimer_lltimer_mask(0xffffffff - xtimer_now())); - - if (!timer_list_head) { - DEBUG("_timer_callback(): tick\n"); - /* there's no timer for this timer period, - * so this was a timer overflow callback. - * - * In this case, we advance to the next timer period. - */ - _next_period(); - - reference = 0; - - /* make sure the timer counter also arrived - * in the next timer period */ - while (_xtimer_lltimer_now() == _xtimer_lltimer_mask(0xFFFFFFFF)); - } - else { - /* we ended up in _timer_callback and there is - * a timer waiting. - */ - /* set our period reference to the current time. */ - reference = _xtimer_lltimer_now(); - } - -overflow: - /* check if next timers are close to expiring */ - while (timer_list_head && (_time_left(_xtimer_lltimer_mask(timer_list_head->target), reference) < XTIMER_ISR_BACKOFF)) { - /* make sure we don't fire too early */ - while (_time_left(_xtimer_lltimer_mask(timer_list_head->target), reference)); - - /* pick first timer in list */ - xtimer_t *timer = timer_list_head; - - /* advance list */ - timer_list_head = timer->next; - - /* make sure timer is recognized as being already fired */ - timer->target = 0; - timer->long_target = 0; + do { + /* check if next timers are close to expiring */ + while (timer_list_head && (_time_left(timer_list_head) < XTIMER_ISR_BACKOFF)) { + /* make sure we don't fire too early */ + while (_time_left(timer_list_head)); - /* fire timer */ - _shoot(timer); - } + /* pick first timer in list */ + xtimer_t *timer = timer_list_head; - /* possibly executing all callbacks took enough - * time to overflow. In that case we advance to - * next timer period and check again for expired - * timers.*/ - if (reference > _xtimer_lltimer_now()) { - DEBUG("_timer_callback: overflowed while executing callbacks. %i\n", timer_list_head != 0); - _next_period(); - reference = 0; - goto overflow; - } + /* advance list */ + timer_list_head = timer->next; - if (timer_list_head) { - /* schedule callback on next timer target time */ - next_target = timer_list_head->target - XTIMER_OVERHEAD; + /* make sure timer is recognized as being already fired */ + timer->target = 0; + timer->long_target = 0; - /* make sure we're not setting a time in the past */ - if (next_target < (_xtimer_lltimer_now() + XTIMER_ISR_BACKOFF)) { - goto overflow; - } - } - else { - /* there's no timer planned for this timer period */ - /* schedule callback on next overflow */ - next_target = _xtimer_lltimer_mask(0xFFFFFFFF); - uint32_t now = _xtimer_lltimer_now(); - - /* check for overflow again */ - if (now < reference) { - _next_period(); - reference = 0; - goto overflow; + /* fire timer */ + _shoot(timer); } - else { - /* check if the end of this period is very soon */ - if (_xtimer_lltimer_mask(now + XTIMER_ISR_BACKOFF) < now) { - /* spin until next period, then advance */ - while (_xtimer_lltimer_now() >= now); - _next_period(); - reference = 0; - goto overflow; - } + + /* if the saved half-period tick doesn't match the timer value MSB, we + * have to advance into the next half-period */ + if (XTIMER_HALFTICK != XTIMER_LL_HALFTICK) { + _next_half_period(); + continue; } - } + } while(0); _in_handler = 0; - - /* set low level timer */ - _lltimer_set(next_target); + _update_lltimer(); } diff --git a/tests/driver_bh1750/main.c b/tests/driver_bh1750/main.c index 0c276aa6bc6d..70340df1468c 100644 --- a/tests/driver_bh1750/main.c +++ b/tests/driver_bh1750/main.c @@ -29,7 +29,7 @@ int main(void) { bh1750fvi_t dev; - uint32_t last = xtimer_now(); + uint64_t last = xtimer_now(); puts("BH1750FVI ambient light sensor test\n"); diff --git a/tests/driver_srf02/main.c b/tests/driver_srf02/main.c index 317f5a3950f0..2395d53543d8 100644 --- a/tests/driver_srf02/main.c +++ b/tests/driver_srf02/main.c @@ -75,7 +75,7 @@ static int cmd_sample(int argc, char **argv) { (void)argc; (void)argv; - uint32_t wakeup = xtimer_now(); + uint64_t wakeup = xtimer_now(); while(1) { sample(); diff --git a/tests/periph_adc/main.c b/tests/periph_adc/main.c index 79146a04f0dd..94cebc9801bc 100644 --- a/tests/periph_adc/main.c +++ b/tests/periph_adc/main.c @@ -31,7 +31,7 @@ int main(void) { - uint32_t last = xtimer_now(); + uint64_t last = xtimer_now(); int sample = 0; puts("\nRIOT ADC peripheral driver test\n"); diff --git a/tests/periph_dac/main.c b/tests/periph_dac/main.c index 59897a7a5fd7..a5d647b4d80f 100644 --- a/tests/periph_dac/main.c +++ b/tests/periph_dac/main.c @@ -30,7 +30,7 @@ int main(void) { - uint32_t last = xtimer_now(); + uint64_t last = xtimer_now(); uint16_t val = 0; uint16_t step = 0xffff / STEPS; diff --git a/tests/periph_pwm/main.c b/tests/periph_pwm/main.c index aee1a385c733..5d4e440dacf4 100644 --- a/tests/periph_pwm/main.c +++ b/tests/periph_pwm/main.c @@ -42,7 +42,7 @@ int main(void) { int state = 0; int step = STEP; - uint32_t last_wakeup = xtimer_now(); + uint64_t last_wakeup = xtimer_now(); puts("\nRIOT PWM test"); puts("Connect an LED or scope to PWM pins to see something\n"); diff --git a/tests/saul/main.c b/tests/saul/main.c index ff6d694c9dfb..46f18685f99a 100644 --- a/tests/saul/main.c +++ b/tests/saul/main.c @@ -32,7 +32,7 @@ int main(void) { phydat_t res; - uint32_t last = xtimer_now(); + uint64_t last = xtimer_now(); puts("SAUL test application"); diff --git a/tests/xtimer_drift/main.c b/tests/xtimer_drift/main.c index 7bb5828d9c1f..22937a91dd17 100644 --- a/tests/xtimer_drift/main.c +++ b/tests/xtimer_drift/main.c @@ -190,7 +190,7 @@ int main(void) NULL, "worker"); - uint32_t last_wakeup = xtimer_now(); + uint64_t last_wakeup = xtimer_now(); while (1) { xtimer_periodic_wakeup(&last_wakeup, TEST_INTERVAL); msg_try_send(&m, pid3); diff --git a/tests/xtimer_longterm/main.c b/tests/xtimer_longterm/main.c index e59fdd216fca..e4a0698906f6 100644 --- a/tests/xtimer_longterm/main.c +++ b/tests/xtimer_longterm/main.c @@ -96,7 +96,7 @@ void *mid_sleep(void *arg) void *ticker(void *arg) { (void)arg; - uint32_t base = xtimer_now(); + uint64_t base = xtimer_now(); while (1) { ++short_ticks; diff --git a/tests/xtimer_now64_continuity/Makefile b/tests/xtimer_now64_continuity/Makefile index 8d9f8cffe054..9f0ed7674506 100644 --- a/tests/xtimer_now64_continuity/Makefile +++ b/tests/xtimer_now64_continuity/Makefile @@ -1,6 +1,6 @@ export APPLICATION = xtimer_now64_continuity include ../Makefile.tests_common -USEMODULE += xtimer +USEMODULE += xtimer fmt include $(RIOTBASE)/Makefile.include diff --git a/tests/xtimer_now64_continuity/main.c b/tests/xtimer_now64_continuity/main.c index c6bf74145481..da433ef8fdf1 100644 --- a/tests/xtimer_now64_continuity/main.c +++ b/tests/xtimer_now64_continuity/main.c @@ -22,28 +22,30 @@ #include #include "xtimer.h" - -#define ITERATIONS (100000LU) -#define MAXDIFF 1000 +#include "fmt.h" +#include "irq.h" int main(void) { - uint32_t n = ITERATIONS; - uint64_t now; - uint64_t before = xtimer_now64(); - - while(--n) { - now = xtimer_now64(); - if ((now-before) > MAXDIFF) { + uint32_t before = xtimer_now(); + uint32_t now; + + print_u32_hex(XTIMER_MSBMASK); + print_u32_hex(XTIMER_MSBMASK); + puts(""); + + do { + now = xtimer_now(); + irq_disable(); + print_u32_hex(now); + puts(""); + if (now < before) { puts("TEST FAILED."); break; } before = now; - } - - if (!n) { - puts("TEST SUCCESSFUL."); - } + irq_enable(); + } while(1); return 0; } diff --git a/tests/xtimer_periodic_wakeup/main.c b/tests/xtimer_periodic_wakeup/main.c index 479c5d0b86ee..543b04d8185e 100644 --- a/tests/xtimer_periodic_wakeup/main.c +++ b/tests/xtimer_periodic_wakeup/main.c @@ -39,7 +39,7 @@ int main(void) for (int i = 0; i < NUMOF; i++) { uint32_t now = xtimer_now(); printf("Testing interval %" PRIu32 "... (now=%" PRIu32 ")\n", interval, now); - uint32_t last_wakeup = xtimer_now(); + uint64_t last_wakeup = xtimer_now(); uint32_t before = last_wakeup; xtimer_periodic_wakeup(&last_wakeup, interval); now = xtimer_now();