From c9f1d3f6d2b129b01d124275448a5b17437cccfa Mon Sep 17 00:00:00 2001 From: Jason Bridges Date: Thu, 22 Oct 2026 21:50:17 +0000 Subject: [PATCH] [arch][arm-m][systick] fix elapsed cycle calculation in current_time Per the Armv7-M and Armv8-M specifications, SysTick->CTRL.COUNTFLAG is asserted when SysTick->VAL transitions from 1 to 0, and SysTick->VAL reloads to LOAD (reload) on the next clock edge (0 -> reload). Within a single current_ticks period of reload + 1 clock cycles, SysTick->VAL therefore progresses through the sequence: 0, reload, reload - 1, ..., 1 corresponding to 0, 1, 2, ..., reload elapsed cycles since the 1 -> 0 transition that incremented current_ticks. Computing (reload - val) in current_time() and current_time_hires() was off by 1 cycle for val in [1, reload] and evaluated to reload (an entire tick period) when val == 0, causing time to jump forward by a full tick interval whenever SysTick->VAL was read during the VAL == 0 cycle. Compute delta_ticks as val ? (reload + 1 - val) : 0 so all reload + 1 states map 1-to-1 to 0..reload elapsed cycles without polling. --- arch/arm/arm-m/systick/systick.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm/arm-m/systick/systick.c b/arch/arm/arm-m/systick/systick.c index a0c212374..adde90d1a 100644 --- a/arch/arm/arm-m/systick/systick.c +++ b/arch/arm/arm-m/systick/systick.c @@ -110,7 +110,8 @@ lk_time_t current_time(void) { systick_get_ticks_val(&ticks, &val); /* convert ticks to msec */ - uint32_t delta = (reload - val) / (tick_rate_mhz * 1000); + uint32_t delta_ticks = val ? (reload + 1 - val) : 0; + uint32_t delta = delta_ticks / (tick_rate_mhz * 1000); lk_time_t res = (ticks * tick_interval_ms) + delta; return res; @@ -125,7 +126,8 @@ lk_bigtime_t current_time_hires(void) { systick_get_ticks_val(&ticks, &val); /* convert ticks to usec */ - uint32_t delta = (reload - val) / tick_rate_mhz; + uint32_t delta_ticks = val ? (reload + 1 - val) : 0; + uint32_t delta = delta_ticks / tick_rate_mhz; lk_bigtime_t res = (ticks * tick_interval_us) + delta; return res;