Skip to content

Commit 2d029e8

Browse files
stm32: fix systick get_time_since_boot() bad value due to non-atomic memory read (#925)
Fixes #924 --------- Co-authored-by: Mihai Nicolae <mihai@doublepoint.com>
1 parent 881aaa9 commit 2d029e8

1 file changed

Lines changed: 15 additions & 4 deletions

File tree

port/stmicro/stm32/src/hals/common/systick.zig

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,21 @@ pub fn is_initialized() bool {
7575
// Low level function to build clock device from it.
7676
pub fn get_time_since_boot() u64 {
7777
const reload = systick.LOAD.read().RELOAD;
78-
const ticks = @as(u64, @intCast(reload - systick.VAL.read().CURRENT));
79-
const all_ticks = @as(u64, @intCast(microzig.cpu.atomic.load(u32, &accumulated_ticks, .acquire))) << 24 | ticks;
80-
const ns = all_ticks * ns_per_ticks;
81-
return ns >> 10;
78+
var high_before = microzig.cpu.atomic.load(u32, &accumulated_ticks, .acquire);
79+
while (true) {
80+
const ticks = @as(u64, @intCast(reload - systick.VAL.read().CURRENT));
81+
const high_after = microzig.cpu.atomic.load(u32, &accumulated_ticks, .acquire);
82+
83+
// ensure that 'high' and 'ticks' belong to the same
84+
// RELOAD..0 count down cycle
85+
if (high_before == high_after) {
86+
const all_ticks = (@as(u64, high_after) << 24) | ticks;
87+
const ns = all_ticks * ns_per_ticks;
88+
return ns >> 10;
89+
} else {
90+
high_before = high_after;
91+
}
92+
}
8293
}
8394

8495
pub fn SysTick_handler() callconv(.c) void {

0 commit comments

Comments
 (0)