Skip to content

Commit 76d5078

Browse files
committed
nrf: tick: update current_tick from samd port
Assuming the samd code is right, this fixes a rare problem where a timeout would be ~1ms too short; the problem could also be observed with the monotonic_ns code which could incorrectly jump forward 1ms.
1 parent 83ecb1b commit 76d5078

File tree

1 file changed

+22
-2
lines changed

1 file changed

+22
-2
lines changed

ports/nrf/tick.c

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "supervisor/filesystem.h"
3131
#include "shared-module/gamepad/__init__.h"
3232
#include "shared-bindings/microcontroller/Processor.h"
33+
#include "shared-bindings/microcontroller/__init__.h"
3334
#include "nrf.h"
3435

3536
// Global millisecond tick count
@@ -38,8 +39,13 @@ volatile uint64_t ticks_ms = 0;
3839
void SysTick_Handler(void) {
3940
// SysTick interrupt handler called when the SysTick timer reaches zero
4041
// (every millisecond).
42+
common_hal_mcu_disable_interrupts();
4143
ticks_ms += 1;
4244

45+
// Read the control register to reset the COUNTFLAG.
46+
(void) SysTick->CTRL;
47+
common_hal_mcu_enable_interrupts();
48+
4349
#if CIRCUITPY_FILESYSTEM_FLUSH_INTERVAL_MS > 0
4450
filesystem_tick();
4551
#endif
@@ -74,8 +80,22 @@ void tick_delay(uint32_t us) {
7480
// us counts down!
7581
void current_tick(uint64_t* ms, uint32_t* us_until_ms) {
7682
uint32_t ticks_per_us = common_hal_mcu_processor_get_frequency() / 1000 / 1000;
77-
*ms = ticks_ms;
78-
*us_until_ms = SysTick->VAL / ticks_per_us;
83+
84+
// We disable interrupts to prevent ticks_ms from changing while we grab it.
85+
common_hal_mcu_disable_interrupts();
86+
uint32_t tick_status = SysTick->CTRL;
87+
uint32_t current_us = SysTick->VAL;
88+
uint32_t tick_status2 = SysTick->CTRL;
89+
uint64_t current_ms = ticks_ms;
90+
// The second clause ensures our value actually rolled over. Its possible it hit zero between
91+
// the VAL read and CTRL read.
92+
if ((tick_status & SysTick_CTRL_COUNTFLAG_Msk) != 0 ||
93+
((tick_status2 & SysTick_CTRL_COUNTFLAG_Msk) != 0 && current_us > ticks_per_us)) {
94+
current_ms++;
95+
}
96+
common_hal_mcu_enable_interrupts();
97+
*ms = current_ms;
98+
*us_until_ms = current_us / ticks_per_us;
7999
}
80100

81101
void wait_until(uint64_t ms, uint32_t us_until_ms) {

0 commit comments

Comments
 (0)