From ffb143740e65d50e43f7b8dd173194bdf32d8022 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Fri, 27 Sep 2024 09:24:01 +0300 Subject: [PATCH] arch/arm64/src/common/arm64_arch_timer.c: Remove clock drift from tick timer This fixes two issues with the tick timer 1) Each tick was longer than the requested period. This is because setting the compare register was done by first reading the current time, and only after that setting the compare register. In addition, when handling the timer interrupts in arch_alarm.c / oneshot_callback, the current_tick is first read, all the tick handling is done and only after that the next tick is started. The whole tick processing time was added to the total tick time. 2) When the compare time is not aligned with tick period, and is drifting, eventually any call to ONESHOT_TICK_CURRENT would either return the current tick, or the next one, depending on the rounding of division by the cycle_per_tick. This again leads to oneshot_callback randomly handling two ticks at a time, which breaks all wdog based timers, causing them to randomly timeout too early. The issues are fixed as follows: Align the compare time register to be evenly divisible by cycle_per_tick. This will lead arm64_tick_current always to return the currently ongoing tick, fixing 2). Also calculating the next tick's start from the aligned current count will fix 1), as there is no time drift in the start cycle. Signed-off-by: Jukka Laitinen --- arch/arm64/src/common/arm64_arch_timer.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/arch/arm64/src/common/arm64_arch_timer.c b/arch/arm64/src/common/arm64_arch_timer.c index 21fc07c3adc2b..ce7e4dda0269e 100644 --- a/arch/arm64/src/common/arm64_arch_timer.c +++ b/arch/arm64/src/common/arm64_arch_timer.c @@ -244,6 +244,7 @@ static int arm64_tick_start(struct oneshot_lowerhalf_s *lower, { struct arm64_oneshot_lowerhalf_s *priv = (struct arm64_oneshot_lowerhalf_s *)lower; + uint64_t next_cycle; DEBUGASSERT(priv != NULL && callback != NULL); @@ -252,10 +253,11 @@ static int arm64_tick_start(struct oneshot_lowerhalf_s *lower, priv->callback = callback; priv->arg = arg; - /* Set the timeout */ + next_cycle = + arm64_arch_timer_count() / priv->cycle_per_tick * priv->cycle_per_tick + + ticks * priv->cycle_per_tick; - arm64_arch_timer_set_compare(arm64_arch_timer_count() + - priv->cycle_per_tick * ticks); + arm64_arch_timer_set_compare(next_cycle); arm64_arch_timer_set_irq_mask(false); return OK; @@ -418,4 +420,4 @@ void arm64_arch_timer_secondary_init() arm64_arch_timer_enable(true); #endif } -#endif \ No newline at end of file +#endif