Skip to content

Commit 1a444b0

Browse files
authored
ch32v: Improve timekeeping (#761)
Fix reading two parts of sys tick counter to safely protect against rollover
1 parent 24fda04 commit 1a444b0

File tree

1 file changed

+27
-7
lines changed

1 file changed

+27
-7
lines changed

port/wch/ch32v/src/hals/time.zig

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,30 @@ const PFIC = peripherals.PFIC;
99
const RCC = peripherals.RCC;
1010
const 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.
1438
var 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

Comments
 (0)