Skip to content
Snippets Groups Projects
Unverified Commit 1d95da01 authored by Kevin "Bear Puncher" Weiss's avatar Kevin "Bear Puncher" Weiss Committed by GitHub
Browse files

Merge pull request #9211 from Josar/pr/xtimer_target_overflow

xtimer: timer & target overflow, hang resolved.
parents ce5cd059 67236895
No related branches found
No related tags found
No related merge requests found
...@@ -65,7 +65,21 @@ static inline uint32_t _xtimer_lltimer_mask(uint32_t val) ...@@ -65,7 +65,21 @@ static inline uint32_t _xtimer_lltimer_mask(uint32_t val)
* @brief xtimer internal stuff * @brief xtimer internal stuff
* @internal * @internal
*/ */
uint64_t _xtimer_now64(void); 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); int _xtimer_set_absolute(xtimer_t *timer, uint32_t target);
void _xtimer_set(xtimer_t *timer, uint32_t offset); void _xtimer_set(xtimer_t *timer, uint32_t offset);
void _xtimer_set64(xtimer_t *timer, uint32_t offset, uint32_t long_offset); void _xtimer_set64(xtimer_t *timer, uint32_t offset, uint32_t long_offset);
......
/** /**
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de> * 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 * 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 * General Public License v2.1. See the file LICENSE in the top level
...@@ -15,6 +16,7 @@ ...@@ -15,6 +16,7 @@
* @brief xtimer core functionality * @brief xtimer core functionality
* @author Kaspar Schleiser <kaspar@schleiser.de> * @author Kaspar Schleiser <kaspar@schleiser.de>
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se> * @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) ...@@ -178,12 +180,27 @@ int _xtimer_set_absolute(xtimer_t *timer, uint32_t target)
uint32_t now = _xtimer_now(); uint32_t now = _xtimer_now();
int res = 0; int res = 0;
DEBUG("timer_set_absolute(): now=%" PRIu32 " target=%" PRIu32 "\n", now, target);
timer->next = NULL; 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 */ /* backoff */
xtimer_spin_until(target + XTIMER_BACKOFF); xtimer_spin_until(target);
_shoot(timer); _shoot(timer);
return 0; return 0;
} }
...@@ -195,6 +212,17 @@ int _xtimer_set_absolute(xtimer_t *timer, uint32_t target) ...@@ -195,6 +212,17 @@ int _xtimer_set_absolute(xtimer_t *timer, uint32_t target)
timer->target = target; timer->target = target;
timer->long_target = _long_cnt; 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) { if (target < now) {
timer->long_target++; timer->long_target++;
} }
...@@ -214,7 +242,7 @@ int _xtimer_set_absolute(xtimer_t *timer, uint32_t target) ...@@ -214,7 +242,7 @@ int _xtimer_set_absolute(xtimer_t *timer, uint32_t target)
if (timer_list_head == timer) { if (timer_list_head == timer) {
DEBUG("timer_set_absolute(): timer is new list head. updating lltimer.\n"); 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: ...@@ -493,10 +521,14 @@ overflow:
* time to overflow. In that case we advance to * time to overflow. In that case we advance to
* next timer period and check again for expired * next timer period and check again for expired
* timers.*/ * 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", DEBUG("_timer_callback: overflowed while executing callbacks. %i\n",
timer_list_head != NULL); timer_list_head != NULL);
_next_period(); _next_period();
/* wait till overflow */
while( reference < _xtimer_lltimer_now()){}
reference = 0; reference = 0;
goto overflow; goto overflow;
} }
...@@ -506,7 +538,7 @@ overflow: ...@@ -506,7 +538,7 @@ overflow:
next_target = timer_list_head->target - XTIMER_OVERHEAD; next_target = timer_list_head->target - XTIMER_OVERHEAD;
/* make sure we're not setting a time in the past */ /* 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; goto overflow;
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment