drivers: systick: avoid starving clock announcements

When setting a timeout measure the number of accumulated unannounced
ticks.  If this value exceeds half the 32-bit cycle counter range
force an announcement so the unannounced cycles are incorporated into
the system tick counter.

Signed-off-by: Peter Bigot <peter.bigot@nordicsemi.no>
This commit is contained in:
Peter Bigot 2019-11-11 14:20:03 -06:00 committed by David Leach
commit 3594f136d7

View file

@ -188,14 +188,30 @@ void z_clock_set_timeout(s32_t ticks, bool idle)
k_spinlock_key_t key = k_spin_lock(&lock);
cycle_count += elapsed();
/* Round delay up to next tick boundary */
delay = delay + (cycle_count - announced_cycles);
delay = ((delay + CYC_PER_TICK - 1) / CYC_PER_TICK) * CYC_PER_TICK;
last_load = delay - (cycle_count - announced_cycles);
u32_t pending = elapsed();
cycle_count += pending;
overflow_cyc = 0U;
u32_t unannounced = cycle_count - announced_cycles;
if ((s32_t)unannounced < 0) {
/* We haven't announced for more than half the 32-bit
* wrap duration, because new timeouts keep being set
* before the existing one fires. Force an announce
* to avoid loss of a wrap event, making sure the
* delay is at least the minimum delay possible.
*/
last_load = MIN_DELAY;
} else {
/* Round delay up to next tick boundary */
delay += unannounced;
delay =
((delay + CYC_PER_TICK - 1) / CYC_PER_TICK) * CYC_PER_TICK;
delay -= unannounced;
last_load = delay;
}
SysTick->LOAD = last_load - 1;
SysTick->VAL = 0; /* resets timer to last_load */