diff options
author | Angus Gratton <angus@redyak.com.au> | 2024-01-02 12:19:33 +1100 |
---|---|---|
committer | Damien George <damien@micropython.org> | 2024-05-31 16:43:52 +1000 |
commit | 74fb42aa82d537b6fefb463907274bd660c6ce8d (patch) | |
tree | d7c3c358a75ab1c9d4916d939b25e3aa39f8d919 | |
parent | 2926001b60fb5060727f3d8034c84cfb014a5dca (diff) | |
download | micropython-74fb42aa82d537b6fefb463907274bd660c6ce8d.tar.gz micropython-74fb42aa82d537b6fefb463907274bd660c6ce8d.zip |
rp2: Refactor soft timer to use hardware timer alarm.
Progress towards removing pico-sdk alarm pool, due to a known issue.
This work was funded through GitHub Sponsors.
Signed-off-by: Angus Gratton <angus@redyak.com.au>
-rw-r--r-- | ports/rp2/main.c | 2 | ||||
-rw-r--r-- | ports/rp2/mpconfigport.h | 4 | ||||
-rw-r--r-- | ports/rp2/mphalport.c | 28 | ||||
-rw-r--r-- | ports/rp2/mpnetworkport.c | 2 | ||||
-rw-r--r-- | ports/rp2/pendsv.h | 3 | ||||
-rw-r--r-- | shared/runtime/softtimer.h | 3 |
6 files changed, 29 insertions, 13 deletions
diff --git a/ports/rp2/main.c b/ports/rp2/main.c index 40374faff9..668017668a 100644 --- a/ports/rp2/main.c +++ b/ports/rp2/main.c @@ -76,6 +76,8 @@ int main(int argc, char **argv) { // This is a tickless port, interrupts should always trigger SEV. SCB->SCR |= SCB_SCR_SEVONPEND_Msk; + soft_timer_init(); + #if MICROPY_HW_ENABLE_UART_REPL bi_decl(bi_program_feature("UART REPL")) setup_default_uart(); diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h index a29692d0be..6ef994bb83 100644 --- a/ports/rp2/mpconfigport.h +++ b/ports/rp2/mpconfigport.h @@ -154,6 +154,10 @@ #define MICROPY_SSL_MBEDTLS (1) #define MICROPY_PY_LWIP_SOCK_RAW (MICROPY_PY_LWIP) +// Hardware timer alarm index. Available range 0-3. +// Number 3 is currently used by pico-sdk (PICO_TIME_DEFAULT_ALARM_POOL_HARDWARE_ALARM_NUM) +#define MICROPY_HW_SOFT_TIMER_ALARM_NUM (2) + // fatfs configuration #define MICROPY_FATFS_ENABLE_LFN (1) #define MICROPY_FATFS_LFN_CODE_PAGE 437 /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */ diff --git a/ports/rp2/mphalport.c b/ports/rp2/mphalport.c index 1641eadb7b..ac3a70822a 100644 --- a/ports/rp2/mphalport.c +++ b/ports/rp2/mphalport.c @@ -35,6 +35,7 @@ #include "pendsv.h" #include "tusb.h" #include "uart.h" +#include "hardware/irq.h" #include "hardware/rtc.h" #include "pico/unique_id.h" @@ -46,8 +47,6 @@ // microseconds since the Epoch. static uint64_t time_us_64_offset_from_epoch; -static alarm_id_t soft_timer_alarm_id = 0; - #if MICROPY_HW_ENABLE_UART_REPL || MICROPY_HW_USB_CDC #ifndef MICROPY_HW_STDIN_BUFFER_LEN @@ -273,21 +272,26 @@ uint32_t storage_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blo panic_unsupported(); } -static int64_t soft_timer_callback(alarm_id_t id, void *user_data) { - soft_timer_alarm_id = 0; - pendsv_schedule_dispatch(PENDSV_DISPATCH_SOFT_TIMER, soft_timer_handler); - return 0; // don't reschedule this alarm -} - uint32_t soft_timer_get_ms(void) { return mp_hal_ticks_ms(); } void soft_timer_schedule_at_ms(uint32_t ticks_ms) { - if (soft_timer_alarm_id != 0) { - cancel_alarm(soft_timer_alarm_id); - } int32_t ms = soft_timer_ticks_diff(ticks_ms, mp_hal_ticks_ms()); ms = MAX(0, ms); - soft_timer_alarm_id = add_alarm_in_ms(ms, soft_timer_callback, NULL, true); + if (hardware_alarm_set_target(MICROPY_HW_SOFT_TIMER_ALARM_NUM, delayed_by_ms(get_absolute_time(), ms))) { + // "missed" hardware alarm target + hardware_alarm_force_irq(MICROPY_HW_SOFT_TIMER_ALARM_NUM); + } +} + +static void soft_timer_hardware_callback(unsigned int alarm_num) { + // The timer alarm ISR needs to call here and trigger PendSV dispatch via + // a second ISR, as PendSV may be currently suspended by the other CPU. + pendsv_schedule_dispatch(PENDSV_DISPATCH_SOFT_TIMER, soft_timer_handler); +} + +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); } diff --git a/ports/rp2/mpnetworkport.c b/ports/rp2/mpnetworkport.c index 09a543c2db..4690a4e511 100644 --- a/ports/rp2/mpnetworkport.c +++ b/ports/rp2/mpnetworkport.c @@ -66,7 +66,7 @@ static void gpio_irq_handler(void) { void cyw43_irq_init(void) { gpio_add_raw_irq_handler_with_order_priority(CYW43_PIN_WL_HOST_WAKE, gpio_irq_handler, CYW43_SHARED_IRQ_HANDLER_PRIORITY); irq_set_enabled(IO_IRQ_BANK0, true); - NVIC_SetPriority(PendSV_IRQn, PICO_LOWEST_IRQ_PRIORITY); + NVIC_SetPriority(PendSV_IRQn, IRQ_PRI_PENDSV); } void cyw43_post_poll_hook(void) { diff --git a/ports/rp2/pendsv.h b/ports/rp2/pendsv.h index bc8e8d61c8..c9bdb27637 100644 --- a/ports/rp2/pendsv.h +++ b/ports/rp2/pendsv.h @@ -42,6 +42,9 @@ enum { #define PENDSV_DISPATCH_NUM_SLOTS PENDSV_DISPATCH_MAX +// PendSV IRQ priority, to run system-level tasks that preempt the main thread. +#define IRQ_PRI_PENDSV PICO_LOWEST_IRQ_PRIORITY + typedef void (*pendsv_dispatch_t)(void); void pendsv_suspend(void); diff --git a/shared/runtime/softtimer.h b/shared/runtime/softtimer.h index fe5d02b907..6921c9f47d 100644 --- a/shared/runtime/softtimer.h +++ b/shared/runtime/softtimer.h @@ -81,6 +81,9 @@ static inline void soft_timer_reinsert(soft_timer_entry_t *entry, uint32_t initi // pend-SV IRQ level, or equivalent. uint32_t soft_timer_get_ms(void); void soft_timer_schedule_at_ms(uint32_t ticks_ms); + +// Optional port-specific initialisation function (provided and called by the port if needed). +void soft_timer_init(void); #endif #endif // MICROPY_INCLUDED_SHARED_RUNTIME_SOFTTIMER_H |