sys: xtimer: some updates
- more robust underflow protection in xtimer_usleep_until() - use relative target in xtimer_spin() - honour reference in isr when spinning until timer target - add XTIMER_BACKOFF to xtimer_spin_until() target when backing off in _timer_set_absolute() - doxygen updates
This commit is contained in:
parent
ca540c9d07
commit
a719e7d61f
@ -333,6 +333,9 @@ int xtimer_msg_receive_timeout64(msg_t *msg, uint64_t us);
|
|||||||
* If the timer is slower by a power of two, XTIMER_SHIFT can be used to
|
* If the timer is slower by a power of two, XTIMER_SHIFT can be used to
|
||||||
* adjust the difference.
|
* adjust the difference.
|
||||||
*
|
*
|
||||||
|
* This will also initialize the underlying periph timer with
|
||||||
|
* us_per_tick == (1<<XTIMER_SHIFT).
|
||||||
|
*
|
||||||
* For example, if the timer is running with 250khz, set XTIMER_SHIFT to 2.
|
* For example, if the timer is running with 250khz, set XTIMER_SHIFT to 2.
|
||||||
*/
|
*/
|
||||||
#ifndef XTIMER_SHIFT
|
#ifndef XTIMER_SHIFT
|
||||||
@ -441,10 +444,17 @@ static inline void xtimer_spin_until(uint32_t value);
|
|||||||
*
|
*
|
||||||
* Use tests/xtimer_shift_on_compare to find the correct value for your MCU.
|
* Use tests/xtimer_shift_on_compare to find the correct value for your MCU.
|
||||||
*/
|
*/
|
||||||
#define XTIMER_SHIFT_ON_COMPARE 0
|
#define XTIMER_SHIFT_ON_COMPARE (0)
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef XTIMER_MIN_SPIN
|
||||||
|
/**
|
||||||
|
* @brief Minimal value xtimer_spin() can spin
|
||||||
|
*/
|
||||||
|
#define XTIMER_MIN_SPIN (1<<XTIMER_SHIFT)
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline uint32_t xtimer_now(void)
|
static inline uint32_t xtimer_now(void)
|
||||||
{
|
{
|
||||||
#if XTIMER_MASK
|
#if XTIMER_MASK
|
||||||
@ -460,13 +470,16 @@ static inline uint32_t xtimer_now(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void xtimer_spin_until(uint32_t value) {
|
static inline void xtimer_spin_until(uint32_t value) {
|
||||||
|
#if XTIMER_MASK
|
||||||
value = _mask(value);
|
value = _mask(value);
|
||||||
|
#endif
|
||||||
while (_xtimer_now() > value);
|
while (_xtimer_now() > value);
|
||||||
while (_xtimer_now() < value);
|
while (_xtimer_now() < value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void xtimer_spin(uint32_t offset) {
|
static inline void xtimer_spin(uint32_t offset) {
|
||||||
xtimer_spin_until(_xtimer_now() + offset + 1);
|
uint32_t start = _xtimer_now();
|
||||||
|
while ((_xtimer_now() - start) < offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void xtimer_usleep(uint32_t offset)
|
static inline void xtimer_usleep(uint32_t offset)
|
||||||
@ -489,16 +502,9 @@ static inline void xtimer_nanosleep(uint32_t nanoseconds)
|
|||||||
_xtimer_sleep(nanoseconds/1000, 0);
|
_xtimer_sleep(nanoseconds/1000, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @} */
|
|
||||||
|
|
||||||
#if XTIMER_OVERHEAD + XTIMER_USLEEP_UNTIL_OVERHEAD > XTIMER_BACKOFF
|
|
||||||
#warning (XTIMER_OVERHEAD + XTIMER_USLEEP_UNTIL_OVERHEAD > XTIMER_BACKOFF !!)
|
|
||||||
#warning This will lead to underruns. Check if tests/xtimer_usleep_until runs through.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** @} */
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** @} */
|
||||||
#endif /* XTIMER_H */
|
#endif /* XTIMER_H */
|
||||||
|
|||||||
@ -72,11 +72,25 @@ void xtimer_usleep_until(uint32_t *last_wakeup, uint32_t interval) {
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* For large offsets, set an absolute target time, as
|
||||||
|
* it is more exact.
|
||||||
|
*
|
||||||
|
* As that might cause an underflow, for small offsets,
|
||||||
|
* use a relative offset, as that can never underflow.
|
||||||
|
*
|
||||||
|
* For very small offsets, spin.
|
||||||
|
*/
|
||||||
uint32_t offset = target - now;
|
uint32_t offset = target - now;
|
||||||
|
|
||||||
if (offset > XTIMER_BACKOFF+XTIMER_USLEEP_UNTIL_OVERHEAD+1) {
|
if (offset > (XTIMER_BACKOFF * 2)) {
|
||||||
mutex_lock(&mutex);
|
mutex_lock(&mutex);
|
||||||
_xtimer_set_absolute(&timer, target - XTIMER_USLEEP_UNTIL_OVERHEAD);
|
if (offset >> 9) { /* >= 512 */
|
||||||
|
offset = target;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
offset += xtimer_now();
|
||||||
|
}
|
||||||
|
_xtimer_set_absolute(&timer, offset);
|
||||||
mutex_lock(&mutex);
|
mutex_lock(&mutex);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@ -167,7 +167,7 @@ int _xtimer_set_absolute(xtimer_t *timer, uint32_t target)
|
|||||||
timer->next = NULL;
|
timer->next = NULL;
|
||||||
if ((target >= now) && ((target - XTIMER_BACKOFF) < now)) {
|
if ((target >= now) && ((target - XTIMER_BACKOFF) < now)) {
|
||||||
/* backoff */
|
/* backoff */
|
||||||
xtimer_spin_until(target);
|
xtimer_spin_until(target+XTIMER_BACKOFF);
|
||||||
_shoot(timer);
|
_shoot(timer);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -410,7 +410,6 @@ static void _next_period(void)
|
|||||||
overflow_list_head = NULL;
|
overflow_list_head = NULL;
|
||||||
|
|
||||||
_select_long_timers();
|
_select_long_timers();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -453,7 +452,7 @@ overflow:
|
|||||||
/* check if next timers are close to expiring */
|
/* check if next timers are close to expiring */
|
||||||
while (timer_list_head && (_time_left(_mask(timer_list_head->target), reference) < XTIMER_ISR_BACKOFF)) {
|
while (timer_list_head && (_time_left(_mask(timer_list_head->target), reference) < XTIMER_ISR_BACKOFF)) {
|
||||||
/* make sure we don't fire too early */
|
/* make sure we don't fire too early */
|
||||||
while (_time_left(_mask(timer_list_head->target), 0));
|
while (_time_left(_mask(timer_list_head->target), reference));
|
||||||
|
|
||||||
/* pick first timer in list */
|
/* pick first timer in list */
|
||||||
xtimer_t *timer = timer_list_head;
|
xtimer_t *timer = timer_list_head;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user