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 <damien.p.george@gmail.com>
This commit is contained in:
parent
c2e9a6f2a5
commit
6f76d1c7fa
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user