From 6f76d1c7fa28c4bcb94a1fa33e3cca1ba8c8cdfd Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 5 Oct 2023 16:32:19 +1100 Subject: [PATCH] rp2: Implement time.time_ns with time_us_64 so it has us resolution. Currently on rp2 the time.time_ns() function has only seconds resolution. This commit makes it have microsecond resolution, by using the output of time_us_64() instead of the RTC. Tested that it does not drift from the RTC over long periods of time. Signed-off-by: Damien George --- ports/rp2/machine_rtc.c | 2 ++ ports/rp2/main.c | 1 + ports/rp2/mphalport.c | 25 +++++++++++++++++++++++-- ports/rp2/mphalport.h | 1 + 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/ports/rp2/machine_rtc.c b/ports/rp2/machine_rtc.c index a9d3426cf8..25d65eda69 100644 --- a/ports/rp2/machine_rtc.c +++ b/ports/rp2/machine_rtc.c @@ -58,6 +58,7 @@ STATIC mp_obj_t machine_rtc_make_new(const mp_obj_type_t *type, size_t n_args, s rtc_init(); datetime_t t = { .month = 1, .day = 1 }; rtc_set_datetime(&t); + mp_hal_time_ns_set_from_rtc(); } // return constant object return (mp_obj_t)&machine_rtc_obj; @@ -104,6 +105,7 @@ STATIC mp_obj_t machine_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) { if (!rtc_set_datetime(&t)) { mp_raise_OSError(MP_EINVAL); } + mp_hal_time_ns_set_from_rtc(); } return mp_const_none; diff --git a/ports/rp2/main.c b/ports/rp2/main.c index ff0384b952..72b243a598 100644 --- a/ports/rp2/main.c +++ b/ports/rp2/main.c @@ -106,6 +106,7 @@ int main(int argc, char **argv) { }; rtc_init(); rtc_set_datetime(&t); + mp_hal_time_ns_set_from_rtc(); // Initialise stack extents and GC heap. mp_stack_set_top(&__StackTop); diff --git a/ports/rp2/mphalport.c b/ports/rp2/mphalport.c index 52d55198b7..d1bba43642 100644 --- a/ports/rp2/mphalport.c +++ b/ports/rp2/mphalport.c @@ -39,6 +39,10 @@ #include "lib/cyw43-driver/src/cyw43.h" #endif +// This needs to be added to the result of time_us_64() to get the number of +// microseconds since the Epoch. +STATIC uint64_t time_us_64_offset_from_epoch; + #if MICROPY_HW_ENABLE_UART_REPL || MICROPY_HW_USB_CDC #ifndef MICROPY_HW_STDIN_BUFFER_LEN @@ -176,11 +180,28 @@ void mp_hal_delay_ms(mp_uint_t ms) { } } -uint64_t mp_hal_time_ns(void) { +void mp_hal_time_ns_set_from_rtc(void) { + // Delay at least one RTC clock cycle so it's registers have updated with the most + // recent time settings. + sleep_us(23); + + // Sample RTC and time_us_64() as close together as possible, so the offset + // calculated for the latter can be as accurate as possible. datetime_t t; rtc_get_datetime(&t); + uint64_t us = time_us_64(); + + // Calculate the difference between the RTC Epoch seconds and time_us_64(). uint64_t s = timeutils_seconds_since_epoch(t.year, t.month, t.day, t.hour, t.min, t.sec); - return s * 1000000000ULL; + time_us_64_offset_from_epoch = (uint64_t)s * 1000000ULL - us; +} + +uint64_t mp_hal_time_ns(void) { + // The RTC only has seconds resolution, so instead use time_us_64() to get a more + // precise measure of Epoch time. Both these "clocks" are clocked from the same + // source so they remain synchronised, and only differ by a fixed offset (calculated + // in mp_hal_time_ns_set_from_rtc). + return (time_us_64_offset_from_epoch + time_us_64()) * 1000ULL; } // Generate a random locally administered MAC address (LAA) diff --git a/ports/rp2/mphalport.h b/ports/rp2/mphalport.h index 8b4a5b6093..95e7cba2c5 100644 --- a/ports/rp2/mphalport.h +++ b/ports/rp2/mphalport.h @@ -39,6 +39,7 @@ extern int mp_interrupt_char; extern ringbuf_t stdin_ringbuf; void mp_hal_set_interrupt_char(int c); +void mp_hal_time_ns_set_from_rtc(void); static inline void mp_hal_delay_us(mp_uint_t us) { sleep_us(us);