drivers: timer: SysTick: enforce proper min & max SysTick LOAD values

Similar to what we do in other timer drivers, the maximum ticks
supplied in z_clock_set_timeout(..) needs to be MAX_TICKS at
maximum, when K_FOREVER is supplied as argument to the function.

In addition to that, the value we load onto the SysTick LOAD
register shall be truncated to MAX_CYCLES. This is required
to prevent loading a trash value to LOAD register, as only
the lowest 24 bits may be safely written.

Finally, we move the enforcement of the minimum delay to be
programmed on LOAD (i.e. MIN_DELAY) at the end step of the
calculation of the cycles-to-be-programmed. This prevents
from misscalculating the delay, as any required adjustment
is applied at the end, after the delay is rounded up to
the next tick boundary.

Signed-off-by: Ioannis Glaropoulos <Ioannis.Glaropoulos@nordicsemi.no>
This commit is contained in:
Ioannis Glaropoulos 2019-11-25 11:26:26 +01:00 committed by David Leach
commit ea2324dd2a

View file

@ -181,10 +181,8 @@ void z_clock_set_timeout(s32_t ticks, bool idle)
#if defined(CONFIG_TICKLESS_KERNEL)
u32_t delay;
ticks = MIN(MAX_TICKS, MAX(ticks - 1, 0));
/* Desired delay in the future */
delay = (ticks == 0) ? MIN_DELAY : ticks * CYC_PER_TICK;
ticks = (ticks == K_FOREVER) ? MAX_TICKS : ticks;
ticks = MAX(MIN(ticks - 1, (s32_t)MAX_TICKS), 0);
k_spinlock_key_t key = k_spin_lock(&lock);
@ -204,13 +202,20 @@ void z_clock_set_timeout(s32_t ticks, bool idle)
*/
last_load = MIN_DELAY;
} else {
/* Desired delay in the future */
delay = ticks * CYC_PER_TICK;
/* 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;
delay = MAX(delay, MIN_DELAY);
if (delay > MAX_CYCLES) {
last_load = MAX_CYCLES;
} else {
last_load = delay;
}
}
SysTick->LOAD = last_load - 1;
SysTick->VAL = 0; /* resets timer to last_load */