Skip to content

Add sub-ms resolution for time.monotonic_ns, on samd and nrf ports #2342

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions ports/atmel-samd/tick.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "supervisor/filesystem.h"
#include "shared-bindings/microcontroller/__init__.h"
#include "shared-bindings/microcontroller/Processor.h"
#include "shared-bindings/time/__init__.h"

#if CIRCUITPY_GAMEPAD
#include "shared-module/gamepad/__init__.h"
Expand Down Expand Up @@ -131,3 +132,29 @@ void wait_until(uint64_t ms, uint32_t us_until_ms) {
uint32_t ticks_per_us = common_hal_mcu_processor_get_frequency() / 1000 / 1000;
while (ticks_ms <= ms && SysTick->VAL / ticks_per_us >= us_until_ms) {}
}

#if CIRCUITPY_FULL_BUILD
uint64_t common_hal_time_monotonic_ns(void) {
uint32_t ticks_per_us = common_hal_mcu_processor_get_frequency() / 1000 / 1000;

// We disable interrupts to prevent ticks_ms from changing while we grab it.
common_hal_mcu_disable_interrupts();
uint32_t tick_status = SysTick->CTRL;
uint32_t current_us = SysTick->VAL;
uint32_t tick_status2 = SysTick->CTRL;
uint64_t current_ms = ticks_ms;
// The second clause ensures our value actually rolled over. Its possible it hit zero between
// the VAL read and CTRL read.
if ((tick_status & SysTick_CTRL_COUNTFLAG_Msk) != 0 ||
((tick_status2 & SysTick_CTRL_COUNTFLAG_Msk) != 0 && current_us > ticks_per_us)) {
current_ms++;
}
common_hal_mcu_enable_interrupts();
return (current_ms + 1) * 1000000
- current_us * 1000 / ticks_per_us;
}
#else
uint64_t common_hal_time_monotonic_ns(void) {
return common_hal_time_monotonic() * 1000000;
}
#endif
4 changes: 4 additions & 0 deletions ports/cxd56/tick.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,7 @@ void board_timerhook(void)
autoreload_tick();
#endif
}

uint64_t common_hal_time_monotonic_ns(void) {
return ticks_ms * 1000000;
}
44 changes: 42 additions & 2 deletions ports/nrf/tick.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "supervisor/filesystem.h"
#include "shared-module/gamepad/__init__.h"
#include "shared-bindings/microcontroller/Processor.h"
#include "shared-bindings/microcontroller/__init__.h"
#include "nrf.h"

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

// Read the control register to reset the COUNTFLAG.
(void) SysTick->CTRL;
common_hal_mcu_enable_interrupts();

#if CIRCUITPY_FILESYSTEM_FLUSH_INTERVAL_MS > 0
filesystem_tick();
#endif
Expand Down Expand Up @@ -74,11 +80,45 @@ void tick_delay(uint32_t us) {
// us counts down!
void current_tick(uint64_t* ms, uint32_t* us_until_ms) {
uint32_t ticks_per_us = common_hal_mcu_processor_get_frequency() / 1000 / 1000;
*ms = ticks_ms;
*us_until_ms = SysTick->VAL / ticks_per_us;

// We disable interrupts to prevent ticks_ms from changing while we grab it.
common_hal_mcu_disable_interrupts();
uint32_t tick_status = SysTick->CTRL;
uint32_t current_us = SysTick->VAL;
uint32_t tick_status2 = SysTick->CTRL;
uint64_t current_ms = ticks_ms;
// The second clause ensures our value actually rolled over. Its possible it hit zero between
// the VAL read and CTRL read.
if ((tick_status & SysTick_CTRL_COUNTFLAG_Msk) != 0 ||
((tick_status2 & SysTick_CTRL_COUNTFLAG_Msk) != 0 && current_us > ticks_per_us)) {
current_ms++;
}
common_hal_mcu_enable_interrupts();
*ms = current_ms;
*us_until_ms = current_us / ticks_per_us;
}

void wait_until(uint64_t ms, uint32_t us_until_ms) {
uint32_t ticks_per_us = common_hal_mcu_processor_get_frequency() / 1000 / 1000;
while(ticks_ms <= ms && SysTick->VAL / ticks_per_us >= us_until_ms) {}
}

uint64_t common_hal_time_monotonic_ns(void) {
uint32_t ticks_per_us = common_hal_mcu_processor_get_frequency() / 1000 / 1000;

// We disable interrupts to prevent ticks_ms from changing while we grab it.
common_hal_mcu_disable_interrupts();
uint32_t tick_status = SysTick->CTRL;
uint32_t current_us = SysTick->VAL;
uint32_t tick_status2 = SysTick->CTRL;
uint64_t current_ms = ticks_ms;
// The second clause ensures our value actually rolled over. Its possible it hit zero between
// the VAL read and CTRL read.
if ((tick_status & SysTick_CTRL_COUNTFLAG_Msk) != 0 ||
((tick_status2 & SysTick_CTRL_COUNTFLAG_Msk) != 0 && current_us > ticks_per_us)) {
current_ms++;
}
common_hal_mcu_enable_interrupts();
return (current_ms + 1) * 1000000
- current_us * 1000 / ticks_per_us;
}
5 changes: 5 additions & 0 deletions ports/stm32f4/tick.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "supervisor/filesystem.h"
#include "shared-module/gamepad/__init__.h"
#include "shared-bindings/microcontroller/Processor.h"
#include "shared-bindings/time/__init__.h"

#include "stm32f4xx.h"

Expand Down Expand Up @@ -93,3 +94,7 @@ void wait_until(uint64_t ms, uint32_t us_until_ms) {
uint32_t ticks_per_us = SystemCoreClock / 1000 / 1000;
while(ticks_ms <= ms && SysTick->VAL / ticks_per_us >= us_until_ms) {}
}

uint64_t common_hal_time_monotonic_ns(void) {
return common_hal_time_monotonic() * 1000000;
}
2 changes: 1 addition & 1 deletion shared-bindings/time/__init__.c
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time);
//| :rtype: int
//|
STATIC mp_obj_t time_monotonic_ns(void) {
uint64_t time64 = common_hal_time_monotonic() * 1000000llu;
uint64_t time64 = common_hal_time_monotonic_ns();
return mp_obj_new_int_from_ll((long long) time64);
Comment on lines +219 to 220
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is STM32 different than the others? Maybe it should also share the same code?

}
MP_DEFINE_CONST_FUN_OBJ_0(time_monotonic_ns_obj, time_monotonic_ns);
Expand Down
1 change: 1 addition & 0 deletions shared-bindings/time/__init__.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ extern mp_obj_t struct_time_from_tm(timeutils_struct_time_t *tm);
extern void struct_time_to_tm(mp_obj_t t, timeutils_struct_time_t *tm);

extern uint64_t common_hal_time_monotonic(void);
extern uint64_t common_hal_time_monotonic_ns(void);
extern void common_hal_time_delay_ms(uint32_t);

#endif // MICROPY_INCLUDED_SHARED_BINDINGS_TIME___INIT___H