Merge pull request #9211 from Josar/pr/xtimer_target_overflow
xtimer: timer & target overflow, hang resolved.
This commit is contained in:
commit
1d95da01fa
@ -65,7 +65,21 @@ static inline uint32_t _xtimer_lltimer_mask(uint32_t val)
|
||||
* @brief xtimer internal stuff
|
||||
* @internal
|
||||
*/
|
||||
|
||||
uint64_t _xtimer_now64(void);
|
||||
|
||||
/**
|
||||
* @brief Sets the timer to the appropriate timer_list or list_head.
|
||||
*
|
||||
* @note The target to set the timer to has to be at least bigger then the
|
||||
* ticks needed to jump into the function and calculate '_xtimer_now()'.
|
||||
* So that 'now' did not pass the target.
|
||||
* This is crucial when using low CPU frequencies and/or when the
|
||||
* '_xtimer_now()' call needs multiple xtimer ticks to evaluate.
|
||||
*
|
||||
* @param[in] timer pointer to xtimer_t which is added to the list.
|
||||
* @param[in] target Absolute target value in ticks.
|
||||
*/
|
||||
int _xtimer_set_absolute(xtimer_t *timer, uint32_t target);
|
||||
void _xtimer_set(xtimer_t *timer, uint32_t offset);
|
||||
void _xtimer_set64(xtimer_t *timer, uint32_t offset, uint32_t long_offset);
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
/**
|
||||
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
|
||||
* Copyright (C) 2016 Eistec AB
|
||||
* 2016 Eistec AB
|
||||
* 2018 Josua Arndt
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
@ -15,6 +16,7 @@
|
||||
* @brief xtimer core functionality
|
||||
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
|
||||
* @author Josua Arndt <jarndt@ias.rwth-aachen.de>
|
||||
* @}
|
||||
*/
|
||||
|
||||
@ -178,12 +180,27 @@ int _xtimer_set_absolute(xtimer_t *timer, uint32_t target)
|
||||
uint32_t now = _xtimer_now();
|
||||
int res = 0;
|
||||
|
||||
DEBUG("timer_set_absolute(): now=%" PRIu32 " target=%" PRIu32 "\n", now, target);
|
||||
|
||||
timer->next = NULL;
|
||||
if ((target >= now) && ((target - XTIMER_BACKOFF) < now)) {
|
||||
|
||||
/* Ensure that offset is bigger than 'XTIMER_BACKOFF',
|
||||
* 'target - now' will allways be the offset no matter if target < or > now.
|
||||
*
|
||||
* This expects that target was not set too close to now and overrun now, so
|
||||
* from setting target up until the call of '_xtimer_now()' above now has not
|
||||
* become equal or bigger than target.
|
||||
* This is crucial when using low CPU frequencies so reaching the '_xtimer_now()'
|
||||
* call needs multiple xtimer ticks.
|
||||
*
|
||||
* '_xtimer_set()' and `_xtimer_periodic_wakeup()` ensure this by already
|
||||
* backing off for small values. */
|
||||
uint32_t offset = (target - now);
|
||||
|
||||
DEBUG("timer_set_absolute(): now=%" PRIu32 " target=%" PRIu32 " offset=%" PRIu32 "\n",
|
||||
now, target, offset);
|
||||
|
||||
if (offset <= XTIMER_BACKOFF) {
|
||||
/* backoff */
|
||||
xtimer_spin_until(target + XTIMER_BACKOFF);
|
||||
xtimer_spin_until(target);
|
||||
_shoot(timer);
|
||||
return 0;
|
||||
}
|
||||
@ -195,6 +212,17 @@ int _xtimer_set_absolute(xtimer_t *timer, uint32_t target)
|
||||
|
||||
timer->target = target;
|
||||
timer->long_target = _long_cnt;
|
||||
|
||||
/* Ensure timer is fired in right timer period.
|
||||
* Backoff condition above ensures that 'target - XTIMER_OVERHEAD` is later
|
||||
* than 'now', also for values when now will overflow and the value of target
|
||||
* is smaller then now.
|
||||
* If `target < XTIMER_OVERHEAD` the new target will be at the end of this
|
||||
* 32bit period, as `target - XTIMER_OVERHEAD` is a big number instead of a
|
||||
* small at the beginning of the next period. */
|
||||
target = target - XTIMER_OVERHEAD;
|
||||
|
||||
/* 32 bit target overflow, target is in next 32bit period */
|
||||
if (target < now) {
|
||||
timer->long_target++;
|
||||
}
|
||||
@ -214,7 +242,7 @@ int _xtimer_set_absolute(xtimer_t *timer, uint32_t target)
|
||||
|
||||
if (timer_list_head == timer) {
|
||||
DEBUG("timer_set_absolute(): timer is new list head. updating lltimer.\n");
|
||||
_lltimer_set(target - XTIMER_OVERHEAD);
|
||||
_lltimer_set(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -493,10 +521,14 @@ overflow:
|
||||
* time to overflow. In that case we advance to
|
||||
* next timer period and check again for expired
|
||||
* timers.*/
|
||||
if (reference > _xtimer_lltimer_now()) {
|
||||
/* check if the end of this period is very soon */
|
||||
uint32_t now = _xtimer_lltimer_now() + XTIMER_ISR_BACKOFF;
|
||||
if (now < reference) {
|
||||
DEBUG("_timer_callback: overflowed while executing callbacks. %i\n",
|
||||
timer_list_head != NULL);
|
||||
_next_period();
|
||||
/* wait till overflow */
|
||||
while( reference < _xtimer_lltimer_now()){}
|
||||
reference = 0;
|
||||
goto overflow;
|
||||
}
|
||||
@ -506,7 +538,7 @@ overflow:
|
||||
next_target = timer_list_head->target - XTIMER_OVERHEAD;
|
||||
|
||||
/* make sure we're not setting a time in the past */
|
||||
if (next_target < (_xtimer_lltimer_now() + XTIMER_ISR_BACKOFF)) {
|
||||
if (next_target < (_xtimer_now() + XTIMER_ISR_BACKOFF)) {
|
||||
goto overflow;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user