pull/13329/merge
Angus Gratton 2024-04-26 19:15:07 +02:00 zatwierdzone przez GitHub
commit 7ce48d21ae
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
9 zmienionych plików z 97 dodań i 32 usunięć

Wyświetl plik

@ -76,6 +76,9 @@ int main(int argc, char **argv) {
// This is a tickless port, interrupts should always trigger SEV.
SCB->SCR |= SCB_SCR_SEVONPEND_Msk;
pendsv_init();
soft_timer_init();
#if MICROPY_HW_ENABLE_UART_REPL
bi_decl(bi_program_feature("UART REPL"))
setup_default_uart();

Wyświetl plik

@ -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) */
@ -266,6 +270,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);

Wyświetl plik

@ -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
@ -199,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.
@ -273,21 +286,40 @@ 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);
}
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);
}

Wyświetl plik

@ -62,23 +62,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);
}

Wyświetl plik

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

Wyświetl plik

@ -25,6 +25,7 @@
*/
#include <assert.h>
#include "pico/mutex.h"
#include "py/mpconfig.h"
#include "pendsv.h"
#include "RP2040.h"
@ -34,15 +35,21 @@
#endif
static pendsv_dispatch_t pendsv_dispatch_table[PENDSV_DISPATCH_NUM_SLOTS];
static int pendsv_lock;
static recursive_mutex_t pendsv_mutex;
void pendsv_init(void) {
recursive_mutex_init(&pendsv_mutex);
}
void pendsv_suspend(void) {
pendsv_lock++;
// Recursive Mutex here as either core may call pendsv_suspend() and expect
// both mutual exclusion (other core can't enter pendsv_suspend() at the
// same time), and that no PendSV handler will run.
recursive_mutex_enter_blocking(&pendsv_mutex);
}
void pendsv_resume(void) {
pendsv_lock--;
assert(pendsv_lock >= 0);
recursive_mutex_exit(&pendsv_mutex);
// Run pendsv if needed. Find an entry with a dispatch and call pendsv dispatch
// with it. If pendsv runs it will service all slots.
int count = PENDSV_DISPATCH_NUM_SLOTS;
@ -55,9 +62,11 @@ void pendsv_resume(void) {
}
void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f) {
assert(pendsv_lock >= 0);
pendsv_dispatch_table[slot] = f;
if (pendsv_lock == 0) {
if (pendsv_mutex.enter_count == 0) {
// There is a race here where other core calls pendsv_suspend() before
// ISR can execute, but dispatch will happen later when other core
// calls pendsv_resume().
SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
} else {
#if MICROPY_PY_NETWORK_CYW43
@ -68,7 +77,14 @@ void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f) {
// PendSV interrupt handler to perform background processing.
void PendSV_Handler(void) {
assert(pendsv_lock == 0);
if (!recursive_mutex_try_enter(&pendsv_mutex, NULL)) {
// Failure here means core 1 holds pendsv_mutex. ISR will
// run again after core 1 calls pendsv_resume().
return;
}
// Core 0 should not already have locked pendsv_mutex
assert(pensv_mutex.enter_count == 1);
#if MICROPY_PY_NETWORK_CYW43
CYW43_STAT_INC(PENDSV_RUN_COUNT);
@ -81,4 +97,6 @@ void PendSV_Handler(void) {
f();
}
}
recursive_mutex_exit(&pendsv_mutex);
}

Wyświetl plik

@ -42,8 +42,12 @@ 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_init(void);
void pendsv_suspend(void);
void pendsv_resume(void);
void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f);

Wyświetl plik

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

Wyświetl plik

@ -81,6 +81,10 @@ 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 by the port and called
// by the port if needed.)
void soft_timer_init(void);
#endif
#endif // MICROPY_INCLUDED_SHARED_RUNTIME_SOFTTIMER_H