summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorAngus Gratton <angus@redyak.com.au>2024-01-02 12:19:33 +1100
committerDamien George <damien@micropython.org>2024-05-31 16:43:52 +1000
commit74fb42aa82d537b6fefb463907274bd660c6ce8d (patch)
treed7c3c358a75ab1c9d4916d939b25e3aa39f8d919
parent2926001b60fb5060727f3d8034c84cfb014a5dca (diff)
downloadmicropython-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.c2
-rw-r--r--ports/rp2/mpconfigport.h4
-rw-r--r--ports/rp2/mphalport.c28
-rw-r--r--ports/rp2/mpnetworkport.c2
-rw-r--r--ports/rp2/pendsv.h3
-rw-r--r--shared/runtime/softtimer.h3
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