Skip to content

Commit c1b4527

Browse files
committed
stm32: fix systick get_time_since_boot() jump due to non-atomic memory read
1 parent ef1eaba commit c1b4527

1 file changed

Lines changed: 17 additions & 4 deletions

File tree

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

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,23 @@ 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+
}
90+
else
91+
{
92+
high_before = high_after;
93+
}
94+
}
8295
}
8396

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

0 commit comments

Comments
 (0)