@@ -9,6 +9,30 @@ const PFIC = peripherals.PFIC;
99const RCC = peripherals .RCC ;
1010const TIM2 = peripherals .TIM2 ;
1111
12+ /// Safely read the 64-bit SysTick counter (CNTH:CNTL).
13+ ///
14+ /// This implements the standard double-read pattern to avoid race conditions:
15+ /// 1. Read high register
16+ /// 2. Read low register
17+ /// 3. Read high register again
18+ /// 4. If both high reads match, the value is consistent
19+ /// 5. Otherwise, the low register rolled over between reads - retry
20+ ///
21+ /// This ensures we never get a value where low has rolled over but we read the old high value.
22+ inline fn read_stk_cnt () u64 {
23+ while (true ) {
24+ const high1 : u32 = PFIC .STK_CNTH .raw ;
25+ const low : u32 = PFIC .STK_CNTL .raw ;
26+ const high2 : u32 = PFIC .STK_CNTH .raw ;
27+
28+ // If high didn't change, we have a consistent reading
29+ if (high1 == high2 ) {
30+ return (@as (u64 , high1 ) << 32 ) | @as (u64 , low );
31+ }
32+ // Otherwise low rolled over between reads, try again
33+ }
34+ }
35+
1236/// Global tick counter in microseconds.
1337/// Incremented by the TIM2 interrupt handler.
1438var ticks_us : u64 = 0 ;
@@ -149,16 +173,12 @@ pub fn delay_us(us: u32) void {
149173 const ticks_per_us : u32 = freq / 1_000_000 ;
150174 const ticks : u64 = @as (u64 , us ) * @as (u64 , ticks_per_us );
151175
152- // Read 64-bit counter (CNTH:CNTL)
153- const start_low : u32 = PFIC .STK_CNTL .raw ;
154- const start_high : u32 = PFIC .STK_CNTH .raw ;
155- const start : u64 = (@as (u64 , start_high ) << 32 ) | @as (u64 , start_low );
176+ // Read 64-bit counter using safe double-read pattern
177+ const start = read_stk_cnt ();
156178
157179 // Wait until enough ticks have elapsed
158180 while (true ) {
159- const current_low : u32 = PFIC .STK_CNTL .raw ;
160- const current_high : u32 = PFIC .STK_CNTH .raw ;
161- const current : u64 = (@as (u64 , current_high ) << 32 ) | @as (u64 , current_low );
181+ const current = read_stk_cnt ();
162182
163183 if (current - start >= ticks ) break ;
164184 asm volatile ("" ::: .{ .memory = true });
0 commit comments