diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt index 9f71f6584079..50afa55a9766 100644 --- a/ports/rp2/CMakeLists.txt +++ b/ports/rp2/CMakeLists.txt @@ -111,6 +111,7 @@ set(MICROPY_SOURCE_PORT mphalport.c mpnetworkport.c mpthreadport.c + pendsv.c rp2_flash.c rp2_pio.c tusb_port.c @@ -141,6 +142,7 @@ set(MICROPY_SOURCE_QSTR ) set(PICO_SDK_COMPONENTS + cmsis_core hardware_adc hardware_base hardware_clocks diff --git a/ports/rp2/mpnetworkport.c b/ports/rp2/mpnetworkport.c index 124907f53870..2b01b62192d0 100644 --- a/ports/rp2/mpnetworkport.c +++ b/ports/rp2/mpnetworkport.c @@ -26,6 +26,7 @@ #include "py/runtime.h" #include "py/mphal.h" +#include "pendsv.h" #if MICROPY_PY_LWIP @@ -36,14 +37,14 @@ #define LWIP_TICK_RATE_MS 64 static alarm_id_t lwip_alarm_id = -1; -static bool lwip_can_poll = true; -static bool lwip_poll_pending = false; #if MICROPY_PY_NETWORK_WIZNET5K -static bool wiznet_poll_pending = false; - void wiznet5k_poll(void); void wiznet5k_deinit(void); + +void wiznet5k_try_poll(void) { + pendsv_schedule_dispatch(PENDSV_DISPATCH_WIZNET, wiznet5k_poll); +} #endif u32_t sys_now(void) { @@ -51,62 +52,27 @@ u32_t sys_now(void) { return mp_hal_ticks_ms(); } -STATIC uint32_t lwip_poll(void) { +STATIC void lwip_poll(void) { // Run the lwIP internal updates sys_check_timeouts(); - - return MAX(5, MIN(sys_timeouts_sleeptime(), LWIP_TICK_RATE_MS)); } void lwip_lock_acquire(void) { - lwip_can_poll = false; + // Prevent PendSV from running. + pendsv_suspend(); } void lwip_lock_release(void) { - lwip_can_poll = false; - #if MICROPY_PY_NETWORK_WIZNET5K - if (wiznet_poll_pending) { - wiznet5k_poll(); - wiznet_poll_pending = false; - } - #endif - - if (lwip_poll_pending) { - lwip_poll(); - lwip_poll_pending = false; - } - lwip_can_poll = true; + // Allow PendSV to run again. + pendsv_resume(); } -uint32_t lwip_try_poll(void) { - uint32_t ret = LWIP_TICK_RATE_MS; - if (lwip_can_poll) { - lwip_can_poll = false; - ret = lwip_poll(); - lwip_can_poll = true; - } else { - lwip_poll_pending = true; - } - return ret; -} - -#if MICROPY_PY_NETWORK_WIZNET5K -void wiznet5k_try_poll(void) { - if (lwip_can_poll) { - lwip_can_poll = false; - wiznet5k_poll(); - lwip_can_poll = true; - } else { - wiznet_poll_pending = true; - } -} -#endif - STATIC int64_t alarm_callback(alarm_id_t id, void *user_data) { + pendsv_schedule_dispatch(PENDSV_DISPATCH_LWIP, lwip_poll); #if MICROPY_PY_NETWORK_WIZNET5K - wiznet5k_try_poll(); + pendsv_schedule_dispatch(PENDSV_DISPATCH_WIZNET, wiznet5k_poll); #endif - return (int64_t)lwip_try_poll() * 1000; + return LWIP_TICK_RATE_MS * 1000; } void mod_network_lwip_init(void) { diff --git a/ports/rp2/pendsv.c b/ports/rp2/pendsv.c new file mode 100644 index 000000000000..006303d46fbf --- /dev/null +++ b/ports/rp2/pendsv.c @@ -0,0 +1,70 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2022 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include "pendsv.h" +#include "RP2040.h" + +static pendsv_dispatch_t pendsv_dispatch_table[PENDSV_DISPATCH_NUM_SLOTS]; +static int pendsv_lock; + +void pendsv_suspend(void) { + pendsv_lock++; +} + +void pendsv_resume(void) { + pendsv_lock--; + assert(pendsv_lock >= 0); + // 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; + while (count--) { + if (pendsv_dispatch_table[count]) { + pendsv_schedule_dispatch(count, pendsv_dispatch_table[count]); + break; + } + } +} + +void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f) { + assert(pendsv_lock >= 0); + pendsv_dispatch_table[slot] = f; + if (pendsv_lock == 0) { + SCB->ICSR = SCB_ICSR_PENDSVSET_Msk; + } +} + +// PendSV interrupt handler to perform background processing. +void PendSV_Handler(void) { + assert(pendsv_lock == 0); + for (size_t i = 0; i < PENDSV_DISPATCH_NUM_SLOTS; ++i) { + if (pendsv_dispatch_table[i] != NULL) { + pendsv_dispatch_t f = pendsv_dispatch_table[i]; + pendsv_dispatch_table[i] = NULL; + f(); + } + } +} diff --git a/ports/rp2/pendsv.h b/ports/rp2/pendsv.h new file mode 100644 index 000000000000..7bb43208ab8a --- /dev/null +++ b/ports/rp2/pendsv.h @@ -0,0 +1,49 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2022 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_RP2_PENDSV_H +#define MICROPY_INCLUDED_RP2_PENDSV_H + +#include + +enum { + #if MICROPY_PY_LWIP + PENDSV_DISPATCH_LWIP, + #endif + #if MICROPY_PY_NETWORK_WIZNET5K + PENDSV_DISPATCH_WIZNET, + #endif + PENDSV_DISPATCH_MAX +}; + +#define PENDSV_DISPATCH_NUM_SLOTS PENDSV_DISPATCH_MAX + +typedef void (*pendsv_dispatch_t)(void); + +void pendsv_suspend(void); +void pendsv_resume(void); +void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f); + +#endif // MICROPY_INCLUDED_RP2_PENDSV_H