kopia lustrzana https://github.com/micropython/micropython
Merge 2923d545b9
into e60e8079a7
commit
7ce48d21ae
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
Ładowanie…
Reference in New Issue