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>
This commit is contained in:
Angus Gratton 2024-01-02 12:19:33 +11:00 committed by Damien George
parent 2926001b60
commit 74fb42aa82
6 changed files with 29 additions and 13 deletions

View File

@ -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();

View File

@ -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) */

View File

@ -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);
}

View File

@ -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) {

View File

@ -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);

View File

@ -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