diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h index fe67db676a..ed6ff71419 100644 --- a/ports/rp2/mpconfigport.h +++ b/ports/rp2/mpconfigport.h @@ -263,6 +263,7 @@ typedef intptr_t mp_off_t; #define BINARY_INFO_ID_MP_FROZEN 0x4a99d719 #define MICROPY_FROZEN_LIST_ITEM(name, file) bi_decl(bi_string(BINARY_INFO_TAG_MICROPYTHON, BINARY_INFO_ID_MP_FROZEN, name)) + extern uint32_t rosc_random_u32(void); extern void lwip_lock_acquire(void); extern void lwip_lock_release(void); diff --git a/ports/rp2/mphalport.c b/ports/rp2/mphalport.c index d2a12e67f2..cfb0af1abd 100644 --- a/ports/rp2/mphalport.c +++ b/ports/rp2/mphalport.c @@ -198,17 +198,31 @@ mp_uint_t mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) { return did_write ? ret : 0; } +void mp_hal_delay_us(mp_uint_t us) { + // Avoid calling sleep_us() and invoking the alarm pool by splitting long + // sleeps into an optional longer sleep and a shorter busy-wait + uint64_t end = time_us_64() + us; + if (us > 1000) { + mp_hal_delay_ms(us / 1000); + } + while (time_us_64() < end) { + // Tight loop busy-wait for accurate timing + } +} + void mp_hal_delay_ms(mp_uint_t ms) { - absolute_time_t t = make_timeout_time_ms(ms); + mp_uint_t start = mp_hal_ticks_ms(); + mp_uint_t elapsed = 0; do { - mp_event_handle_nowait(); - } while (!best_effort_wfe_or_timeout(t)); + mp_event_wait_ms(ms - elapsed); + elapsed = mp_hal_ticks_ms() - start; + } while (elapsed < ms); } 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); + // Outstanding RTC register writes need at least two RTC clock cycles to + // update. (See RP2040 datasheet section 4.8.4 "Reference clock"). + mp_hal_delay_us(44); // Sample RTC and time_us_64() as close together as possible, so the offset // calculated for the latter can be as accurate as possible. @@ -295,3 +309,17 @@ void soft_timer_init(void) { hardware_alarm_claim(MICROPY_HW_SOFT_TIMER_ALARM_NUM); hardware_alarm_set_callback(MICROPY_HW_SOFT_TIMER_ALARM_NUM, soft_timer_hardware_callback); } + +void mp_wfe_or_timeout(uint32_t timeout_ms) { + soft_timer_entry_t timer; + + // Note the timer doesn't have an associated callback, it just exists to create a + // hardware interrupt to wake the CPU + soft_timer_static_init(&timer, SOFT_TIMER_MODE_ONE_SHOT, 0, NULL); + soft_timer_insert(&timer, timeout_ms); + + __wfe(); + + // Clean up the timer node if it's not already + soft_timer_remove(&timer); +} diff --git a/ports/rp2/mphalport.h b/ports/rp2/mphalport.h index c8e2301a92..57b2fb3dc4 100644 --- a/ports/rp2/mphalport.h +++ b/ports/rp2/mphalport.h @@ -57,23 +57,22 @@ if ((TIMEOUT_MS) < 0) { \ __wfe(); \ } else { \ - best_effort_wfe_or_timeout(make_timeout_time_ms(TIMEOUT_MS)); \ + mp_wfe_or_timeout(TIMEOUT_MS); \ } \ } while (0) extern int mp_interrupt_char; extern ringbuf_t stdin_ringbuf; +// Port-specific function to create a wakeup interrupt after timeout_ms and enter WFE +void mp_wfe_or_timeout(uint32_t timeout_ms); + uint32_t mp_thread_begin_atomic_section(void); void mp_thread_end_atomic_section(uint32_t); 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); -} - static inline void mp_hal_delay_us_fast(mp_uint_t us) { busy_wait_us(us); } diff --git a/shared/runtime/softtimer.c b/shared/runtime/softtimer.c index 468fa95b72..0577cd00c4 100644 --- a/shared/runtime/softtimer.c +++ b/shared/runtime/softtimer.c @@ -89,7 +89,7 @@ void soft_timer_handler(void) { heap = (soft_timer_entry_t *)mp_pairheap_pop(soft_timer_lt, &heap->pairheap); if (entry->flags & SOFT_TIMER_FLAG_PY_CALLBACK) { mp_sched_schedule(entry->py_callback, MP_OBJ_FROM_PTR(entry)); - } else { + } else if (entry->c_callback) { entry->c_callback(entry); } if (entry->mode == SOFT_TIMER_MODE_PERIODIC) {