Skip to content

Commit 6f76d1c

Browse files
committed
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 <[email protected]>
1 parent c2e9a6f commit 6f76d1c

File tree

4 files changed

+27
-2
lines changed

4 files changed

+27
-2
lines changed

ports/rp2/machine_rtc.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ STATIC mp_obj_t machine_rtc_make_new(const mp_obj_type_t *type, size_t n_args, s
5858
rtc_init();
5959
datetime_t t = { .month = 1, .day = 1 };
6060
rtc_set_datetime(&t);
61+
mp_hal_time_ns_set_from_rtc();
6162
}
6263
// return constant object
6364
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) {
104105
if (!rtc_set_datetime(&t)) {
105106
mp_raise_OSError(MP_EINVAL);
106107
}
108+
mp_hal_time_ns_set_from_rtc();
107109

108110
}
109111
return mp_const_none;

ports/rp2/main.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ int main(int argc, char **argv) {
106106
};
107107
rtc_init();
108108
rtc_set_datetime(&t);
109+
mp_hal_time_ns_set_from_rtc();
109110

110111
// Initialise stack extents and GC heap.
111112
mp_stack_set_top(&__StackTop);

ports/rp2/mphalport.c

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@
3939
#include "lib/cyw43-driver/src/cyw43.h"
4040
#endif
4141

42+
// This needs to be added to the result of time_us_64() to get the number of
43+
// microseconds since the Epoch.
44+
STATIC uint64_t time_us_64_offset_from_epoch;
45+
4246
#if MICROPY_HW_ENABLE_UART_REPL || MICROPY_HW_USB_CDC
4347

4448
#ifndef MICROPY_HW_STDIN_BUFFER_LEN
@@ -176,11 +180,28 @@ void mp_hal_delay_ms(mp_uint_t ms) {
176180
}
177181
}
178182

179-
uint64_t mp_hal_time_ns(void) {
183+
void mp_hal_time_ns_set_from_rtc(void) {
184+
// Delay at least one RTC clock cycle so it's registers have updated with the most
185+
// recent time settings.
186+
sleep_us(23);
187+
188+
// Sample RTC and time_us_64() as close together as possible, so the offset
189+
// calculated for the latter can be as accurate as possible.
180190
datetime_t t;
181191
rtc_get_datetime(&t);
192+
uint64_t us = time_us_64();
193+
194+
// Calculate the difference between the RTC Epoch seconds and time_us_64().
182195
uint64_t s = timeutils_seconds_since_epoch(t.year, t.month, t.day, t.hour, t.min, t.sec);
183-
return s * 1000000000ULL;
196+
time_us_64_offset_from_epoch = (uint64_t)s * 1000000ULL - us;
197+
}
198+
199+
uint64_t mp_hal_time_ns(void) {
200+
// The RTC only has seconds resolution, so instead use time_us_64() to get a more
201+
// precise measure of Epoch time. Both these "clocks" are clocked from the same
202+
// source so they remain synchronised, and only differ by a fixed offset (calculated
203+
// in mp_hal_time_ns_set_from_rtc).
204+
return (time_us_64_offset_from_epoch + time_us_64()) * 1000ULL;
184205
}
185206

186207
// Generate a random locally administered MAC address (LAA)

ports/rp2/mphalport.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ extern int mp_interrupt_char;
3939
extern ringbuf_t stdin_ringbuf;
4040

4141
void mp_hal_set_interrupt_char(int c);
42+
void mp_hal_time_ns_set_from_rtc(void);
4243

4344
static inline void mp_hal_delay_us(mp_uint_t us) {
4445
sleep_us(us);

0 commit comments

Comments
 (0)