mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-01-18 12:52:44 +01:00
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
|
||||
* 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.
|
||||
*/
|
||||
#ifndef XTIMER_SHIFT
|
||||
@ -372,7 +375,7 @@ int xtimer_msg_receive_timeout64(msg_t *msg, uint64_t us);
|
||||
*/
|
||||
#define XTIMER_MASK (0)
|
||||
#endif
|
||||
#define XTIMER_MASK_SHIFTED (XTIMER_MASK<<XTIMER_SHIFT)
|
||||
#define XTIMER_MASK_SHIFTED (XTIMER_MASK << XTIMER_SHIFT)
|
||||
|
||||
#ifndef XTIMER_USLEEP_UNTIL_OVERHEAD
|
||||
/**
|
||||
@ -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.
|
||||
*/
|
||||
#define XTIMER_SHIFT_ON_COMPARE 0
|
||||
#define XTIMER_SHIFT_ON_COMPARE (0)
|
||||
#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)
|
||||
{
|
||||
#if XTIMER_MASK
|
||||
@ -460,13 +470,16 @@ static inline uint32_t xtimer_now(void)
|
||||
}
|
||||
|
||||
static inline void xtimer_spin_until(uint32_t value) {
|
||||
#if XTIMER_MASK
|
||||
value = _mask(value);
|
||||
#endif
|
||||
while (_xtimer_now() > value);
|
||||
while (_xtimer_now() < value);
|
||||
}
|
||||
|
||||
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)
|
||||
@ -489,16 +502,9 @@ static inline void xtimer_nanosleep(uint32_t nanoseconds)
|
||||
_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
|
||||
}
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
#endif /* XTIMER_H */
|
||||
|
@ -72,11 +72,25 @@ void xtimer_usleep_until(uint32_t *last_wakeup, uint32_t interval) {
|
||||
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;
|
||||
|
||||
if (offset > XTIMER_BACKOFF+XTIMER_USLEEP_UNTIL_OVERHEAD+1) {
|
||||
if (offset > (XTIMER_BACKOFF * 2)) {
|
||||
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);
|
||||
}
|
||||
else {
|
||||
|
@ -167,7 +167,7 @@ int _xtimer_set_absolute(xtimer_t *timer, uint32_t target)
|
||||
timer->next = NULL;
|
||||
if ((target >= now) && ((target - XTIMER_BACKOFF) < now)) {
|
||||
/* backoff */
|
||||
xtimer_spin_until(target);
|
||||
xtimer_spin_until(target+XTIMER_BACKOFF);
|
||||
_shoot(timer);
|
||||
return 0;
|
||||
}
|
||||
@ -410,7 +410,6 @@ static void _next_period(void)
|
||||
overflow_list_head = NULL;
|
||||
|
||||
_select_long_timers();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -453,7 +452,7 @@ overflow:
|
||||
/* check if next timers are close to expiring */
|
||||
while (timer_list_head && (_time_left(_mask(timer_list_head->target), reference) < XTIMER_ISR_BACKOFF)) {
|
||||
/* 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 */
|
||||
xtimer_t *timer = timer_list_head;
|
||||
|
Loading…
Reference in New Issue
Block a user