Skip to content

Commit efad242

Browse files
committed
shared-bindings: introduce, use common_hal_time_monotonic_ns
.. which, on some ports, can return sub-millisecond precision thanks to how SysTick works.
1 parent 76d5078 commit efad242

File tree

6 files changed

+58
-1
lines changed

6 files changed

+58
-1
lines changed

ports/atmel-samd/tick.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "supervisor/filesystem.h"
3333
#include "shared-bindings/microcontroller/__init__.h"
3434
#include "shared-bindings/microcontroller/Processor.h"
35+
#include "shared-bindings/time/__init__.h"
3536

3637
#if CIRCUITPY_GAMEPAD
3738
#include "shared-module/gamepad/__init__.h"
@@ -131,3 +132,29 @@ void wait_until(uint64_t ms, uint32_t us_until_ms) {
131132
uint32_t ticks_per_us = common_hal_mcu_processor_get_frequency() / 1000 / 1000;
132133
while (ticks_ms <= ms && SysTick->VAL / ticks_per_us >= us_until_ms) {}
133134
}
135+
136+
#if CIRCUITPY_FULL_BUILD
137+
uint64_t common_hal_time_monotonic_ns(void) {
138+
uint32_t ticks_per_us = common_hal_mcu_processor_get_frequency() / 1000 / 1000;
139+
140+
// We disable interrupts to prevent ticks_ms from changing while we grab it.
141+
common_hal_mcu_disable_interrupts();
142+
uint32_t tick_status = SysTick->CTRL;
143+
uint32_t current_us = SysTick->VAL;
144+
uint32_t tick_status2 = SysTick->CTRL;
145+
uint64_t current_ms = ticks_ms;
146+
// The second clause ensures our value actually rolled over. Its possible it hit zero between
147+
// the VAL read and CTRL read.
148+
if ((tick_status & SysTick_CTRL_COUNTFLAG_Msk) != 0 ||
149+
((tick_status2 & SysTick_CTRL_COUNTFLAG_Msk) != 0 && current_us > ticks_per_us)) {
150+
current_ms++;
151+
}
152+
common_hal_mcu_enable_interrupts();
153+
return (current_ms + 1) * 1000000
154+
- current_us * 1000 / ticks_per_us;
155+
}
156+
#else
157+
uint64_t common_hal_time_monotonic_ns(void) {
158+
return common_hal_time_monotonic() * 1000000;
159+
}
160+
#endif

ports/cxd56/tick.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,7 @@ void board_timerhook(void)
4343
autoreload_tick();
4444
#endif
4545
}
46+
47+
uint64_t common_hal_time_monotonic_ns(void) {
48+
return ticks_ms * 1000000;
49+
}

ports/nrf/tick.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,23 @@ void wait_until(uint64_t ms, uint32_t us_until_ms) {
102102
uint32_t ticks_per_us = common_hal_mcu_processor_get_frequency() / 1000 / 1000;
103103
while(ticks_ms <= ms && SysTick->VAL / ticks_per_us >= us_until_ms) {}
104104
}
105+
106+
uint64_t common_hal_time_monotonic_ns(void) {
107+
uint32_t ticks_per_us = common_hal_mcu_processor_get_frequency() / 1000 / 1000;
108+
109+
// We disable interrupts to prevent ticks_ms from changing while we grab it.
110+
common_hal_mcu_disable_interrupts();
111+
uint32_t tick_status = SysTick->CTRL;
112+
uint32_t current_us = SysTick->VAL;
113+
uint32_t tick_status2 = SysTick->CTRL;
114+
uint64_t current_ms = ticks_ms;
115+
// The second clause ensures our value actually rolled over. Its possible it hit zero between
116+
// the VAL read and CTRL read.
117+
if ((tick_status & SysTick_CTRL_COUNTFLAG_Msk) != 0 ||
118+
((tick_status2 & SysTick_CTRL_COUNTFLAG_Msk) != 0 && current_us > ticks_per_us)) {
119+
current_ms++;
120+
}
121+
common_hal_mcu_enable_interrupts();
122+
return (current_ms + 1) * 1000000
123+
- current_us * 1000 / ticks_per_us;
124+
}

ports/stm32f4/tick.c

Lines changed: 5 additions & 0 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/time/__init__.h"
3334

3435
#include "stm32f4xx.h"
3536

@@ -93,3 +94,7 @@ void wait_until(uint64_t ms, uint32_t us_until_ms) {
9394
uint32_t ticks_per_us = SystemCoreClock / 1000 / 1000;
9495
while(ticks_ms <= ms && SysTick->VAL / ticks_per_us >= us_until_ms) {}
9596
}
97+
98+
uint64_t common_hal_time_monotonic_ns(void) {
99+
return common_hal_time_monotonic() * 1000000;
100+
}

shared-bindings/time/__init__.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time);
216216
//| :rtype: int
217217
//|
218218
STATIC mp_obj_t time_monotonic_ns(void) {
219-
uint64_t time64 = common_hal_time_monotonic() * 1000000llu;
219+
uint64_t time64 = common_hal_time_monotonic_ns();
220220
return mp_obj_new_int_from_ll((long long) time64);
221221
}
222222
MP_DEFINE_CONST_FUN_OBJ_0(time_monotonic_ns_obj, time_monotonic_ns);

shared-bindings/time/__init__.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ extern mp_obj_t struct_time_from_tm(timeutils_struct_time_t *tm);
3636
extern void struct_time_to_tm(mp_obj_t t, timeutils_struct_time_t *tm);
3737

3838
extern uint64_t common_hal_time_monotonic(void);
39+
extern uint64_t common_hal_time_monotonic_ns(void);
3940
extern void common_hal_time_delay_ms(uint32_t);
4041

4142
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_TIME___INIT___H

0 commit comments

Comments
 (0)