-
-
Notifications
You must be signed in to change notification settings - Fork 8.4k
Description
Port, board and/or hardware
stm32, STM32N6.
MicroPython version
MicroPython 1.26.0
Reproduction
diff --git a/ports/stm32/main.c b/ports/stm32/main.c
index af4d7f8bb..7583148ee 100644
--- a/ports/stm32/main.c
+++ b/ports/stm32/main.c
@@ -549,6 +549,17 @@ void stm32_main(uint32_t reset_mode) {
MICROPY_BOARD_BEFORE_SOFT_RESET_LOOP(&state);
+ while (true) {
+ mp_uint_t last_tick = mp_hal_ticks_us();
+ SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
+
+ if (mp_hal_ticks_us() < last_tick) {
+ MICROPY_BOARD_FATAL_ERROR("");
+ }
+
+ SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
+ }
+
soft_reset:
MICROPY_BOARD_TOP_SOFT_RESET_LOOP(&state);
Expected behaviour
Time is a river that never bends back.
Observed behaviour
mp_hal_ticks_us
values can go backward by up to ~1 ms.
Additional Information
mp_hal_ticks_us
values can go backward by up to ~1 ms, especially on faster MCUs (like the N6) and when IRQs occur around the calls. You’re probably aware of this possibility, judging by the comments in that function, so what I’m looking for is advice on whether this is something we should try to fix or just accept. Right now I'm using this workaround:
static inline mp_uint_t mp_hal_ticks_us_monotonic(void) {
static mp_uint_t last_timestamp = 0;
mp_uint_t current = mp_hal_ticks_us();
// Ensure monotonic behavior
if (current > last_timestamp) {
last_timestamp = current;
}
return last_timestamp;
}
However, I'm using mp_hal_ticks_us
as part of a code profiler, so accuracy is very important. The following function seems to fix the issue, and it might also be better because it doesn't disable IRQs. However, I might be missing something, or this loop may not be wanted, that's why I didn't send this as a fix:
mp_uint_t mp_hal_ticks_us(void) {
uint32_t ms1, ms2, counter, load, ctrl;
// Repeat until we get a consistent millisecond + VAL snapshot
do {
ms1 = HAL_GetTick();
counter = SysTick->VAL;
ctrl = SysTick->CTRL; // Read CTRL to check COUNTFLAG
ms2 = HAL_GetTick();
} while (ms1 != ms2);
load = SysTick->LOAD;
// Check if SysTick rolled over but HAL_GetTick() hasn't been updated yet
// This happens when IRQs are disabled or the interrupt is pending
if (ctrl & SysTick_CTRL_COUNTFLAG_Msk) {
// SysTick has rolled over since last interrupt
// The counter value is from the new cycle, so increment milliseconds
ms1++;
}
// Convert from decrementing to incrementing
counter = load - counter;
return ms1 * 1000 + (counter * 1000) / (load + 1);
}
Code of Conduct
Yes, I agree