diff --git a/drivers/cyw43/cywbt.c b/drivers/cyw43/cywbt.c index d1b19382c599a..3f454485ab2bc 100644 --- a/drivers/cyw43/cywbt.c +++ b/drivers/cyw43/cywbt.c @@ -68,7 +68,7 @@ STATIC int cywbt_hci_cmd_raw(size_t len, uint8_t *buf) { mp_bluetooth_hci_uart_write((void *)buf, len); for (int c, i = 0; i < 6; ++i) { while ((c = mp_bluetooth_hci_uart_readchar()) == -1) { - MICROPY_EVENT_POLL_HOOK + mp_event_wait_indefinite(); } buf[i] = c; } @@ -88,7 +88,7 @@ STATIC int cywbt_hci_cmd_raw(size_t len, uint8_t *buf) { int sz = buf[2] - 3; for (int c, i = 0; i < sz; ++i) { while ((c = mp_bluetooth_hci_uart_readchar()) == -1) { - MICROPY_EVENT_POLL_HOOK + mp_event_wait_indefinite(); } buf[i] = c; } diff --git a/drivers/ninaw10/nina_bt_hci.c b/drivers/ninaw10/nina_bt_hci.c index 754e99ed76b45..f0d1b9bc8986b 100644 --- a/drivers/ninaw10/nina_bt_hci.c +++ b/drivers/ninaw10/nina_bt_hci.c @@ -75,12 +75,13 @@ static int nina_hci_cmd(int ogf, int ocf, size_t param_len, const uint8_t *param // Receive HCI event packet, initially reading 3 bytes (HCI Event, Event code, Plen). for (mp_uint_t start = mp_hal_ticks_ms(), size = 3, i = 0; i < size;) { while (!mp_bluetooth_hci_uart_any()) { - MICROPY_EVENT_POLL_HOOK + mp_uint_t elapsed = mp_hal_ticks_ms() - start; // Timeout. - if ((mp_hal_ticks_ms() - start) > HCI_COMMAND_TIMEOUT) { + if (elapsed > HCI_COMMAND_TIMEOUT) { error_printf("timeout waiting for HCI packet\n"); return -1; } + mp_event_wait_ms(HCI_COMMAND_TIMEOUT - elapsed); } buf[i] = mp_bluetooth_hci_uart_readchar(); diff --git a/extmod/btstack/modbluetooth_btstack.c b/extmod/btstack/modbluetooth_btstack.c index 0c15e9343159d..211214768f7eb 100644 --- a/extmod/btstack/modbluetooth_btstack.c +++ b/extmod/btstack/modbluetooth_btstack.c @@ -552,7 +552,7 @@ STATIC void set_random_address(void) { volatile bool ready = false; btstack_crypto_random_generate(&sm_crypto_random_request, static_addr, 6, &btstack_static_address_ready, (void *)&ready); while (!ready) { - MICROPY_EVENT_POLL_HOOK + mp_event_wait_indefinite(); } #endif // MICROPY_BLUETOOTH_USE_MP_HAL_GET_MAC_STATIC_ADDRESS @@ -574,7 +574,7 @@ STATIC void set_random_address(void) { break; } - MICROPY_EVENT_POLL_HOOK + mp_event_wait_indefinite(); } DEBUG_printf("set_random_address: Address loaded by controller\n"); } @@ -654,7 +654,7 @@ int mp_bluetooth_init(void) { // Either the HCI event will set state to ACTIVE, or the timeout will set it to TIMEOUT. mp_bluetooth_btstack_port_start(); while (mp_bluetooth_btstack_state == MP_BLUETOOTH_BTSTACK_STATE_STARTING) { - MICROPY_EVENT_POLL_HOOK + mp_event_wait_indefinite(); } btstack_run_loop_remove_timer(&btstack_init_deinit_timeout); @@ -727,7 +727,7 @@ void mp_bluetooth_deinit(void) { // either timeout or clean shutdown. mp_bluetooth_btstack_port_deinit(); while (mp_bluetooth_btstack_state == MP_BLUETOOTH_BTSTACK_STATE_ACTIVE) { - MICROPY_EVENT_POLL_HOOK + mp_event_wait_indefinite(); } btstack_run_loop_remove_timer(&btstack_init_deinit_timeout); diff --git a/extmod/machine_i2c.c b/extmod/machine_i2c.c index 6cc2aa5bbf0e9..1964284ec837d 100644 --- a/extmod/machine_i2c.c +++ b/extmod/machine_i2c.c @@ -331,11 +331,7 @@ STATIC mp_obj_t machine_i2c_scan(mp_obj_t self_in) { // This scan loop may run for some time, so process any pending events/exceptions, // or allow the port to run any necessary background tasks. But do it as fast as // possible, in particular we are not waiting on any events. - #if defined(MICROPY_EVENT_POLL_HOOK_FAST) - MICROPY_EVENT_POLL_HOOK_FAST; - #elif defined(MICROPY_EVENT_POLL_HOOK) - MICROPY_EVENT_POLL_HOOK - #endif + mp_event_handle_nowait(); } return list; } diff --git a/extmod/modlwip.c b/extmod/modlwip.c index 432b97e8fe3be..6f8703d5a71a9 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -318,11 +318,7 @@ typedef struct _lwip_socket_obj_t { } lwip_socket_obj_t; static inline void poll_sockets(void) { - #ifdef MICROPY_EVENT_POLL_HOOK - MICROPY_EVENT_POLL_HOOK; - #else - mp_hal_delay_ms(1); - #endif + mp_event_wait_ms(1); } STATIC struct tcp_pcb *volatile *lwip_socket_incoming_array(lwip_socket_obj_t *socket) { diff --git a/extmod/modselect.c b/extmod/modselect.c index d665a1082794a..07ef3d79c8403 100644 --- a/extmod/modselect.c +++ b/extmod/modselect.c @@ -306,6 +306,7 @@ STATIC mp_uint_t poll_set_poll_once(poll_set_t *poll_set, size_t *rwx_num) { STATIC mp_uint_t poll_set_poll_until_ready_or_timeout(poll_set_t *poll_set, size_t *rwx_num, mp_uint_t timeout) { mp_uint_t start_ticks = mp_hal_ticks_ms(); + bool has_timeout = timeout != (mp_uint_t)-1; #if MICROPY_PY_SELECT_POSIX_OPTIMISATIONS @@ -350,12 +351,12 @@ STATIC mp_uint_t poll_set_poll_until_ready_or_timeout(poll_set_t *poll_set, size } // Return if an object is ready, or if the timeout expired. - if (n_ready > 0 || (timeout != (mp_uint_t)-1 && mp_hal_ticks_ms() - start_ticks >= timeout)) { + if (n_ready > 0 || (has_timeout && mp_hal_ticks_ms() - start_ticks >= timeout)) { return n_ready; } - // This would be MICROPY_EVENT_POLL_HOOK but the call to poll() above already includes a delay. - mp_handle_pending(true); + // This would be mp_event_wait_ms() but the call to poll() above already includes a delay. + mp_event_handle_nowait(); } #else @@ -363,10 +364,15 @@ STATIC mp_uint_t poll_set_poll_until_ready_or_timeout(poll_set_t *poll_set, size for (;;) { // poll the objects mp_uint_t n_ready = poll_set_poll_once(poll_set, rwx_num); - if (n_ready > 0 || (timeout != (mp_uint_t)-1 && mp_hal_ticks_ms() - start_ticks >= timeout)) { + uint32_t elapsed = mp_hal_ticks_ms() - start_ticks; + if (n_ready > 0 || (has_timeout && elapsed >= timeout)) { return n_ready; } - MICROPY_EVENT_POLL_HOOK + if (has_timeout) { + mp_event_wait_ms(timeout - elapsed); + } else { + mp_event_wait_indefinite(); + } } #endif diff --git a/extmod/modssl_mbedtls.c b/extmod/modssl_mbedtls.c index 449952594c2db..1d7705c17fea4 100644 --- a/extmod/modssl_mbedtls.c +++ b/extmod/modssl_mbedtls.c @@ -391,9 +391,7 @@ STATIC mp_obj_t ssl_socket_make_new(mp_obj_ssl_context_t *ssl_context, mp_obj_t if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { goto cleanup; } - #ifdef MICROPY_EVENT_POLL_HOOK - MICROPY_EVENT_POLL_HOOK - #endif + mp_event_wait_ms(1); } } diff --git a/extmod/network_cyw43.c b/extmod/network_cyw43.c index 834f09eae956b..f8490d6b9a9cd 100644 --- a/extmod/network_cyw43.c +++ b/extmod/network_cyw43.c @@ -222,8 +222,13 @@ STATIC mp_obj_t network_cyw43_scan(size_t n_args, const mp_obj_t *pos_args, mp_m // Wait for scan to finish, with a 10s timeout uint32_t start = mp_hal_ticks_ms(); - while (cyw43_wifi_scan_active(self->cyw) && mp_hal_ticks_ms() - start < 10000) { - MICROPY_EVENT_POLL_HOOK + const uint32_t TIMEOUT = 10000; + while (cyw43_wifi_scan_active(self->cyw)) { + uint32_t elapsed = mp_hal_ticks_ms() - start; + if (elapsed >= TIMEOUT) { + break; + } + mp_event_wait_ms(TIMEOUT - elapsed); } return res; diff --git a/extmod/nimble/modbluetooth_nimble.c b/extmod/nimble/modbluetooth_nimble.c index 3cdf4d1a7811f..2e1faa9b100ef 100644 --- a/extmod/nimble/modbluetooth_nimble.c +++ b/extmod/nimble/modbluetooth_nimble.c @@ -570,7 +570,7 @@ void mp_bluetooth_nimble_port_shutdown(void) { ble_hs_stop(&ble_hs_shutdown_stop_listener, ble_hs_shutdown_stop_cb, NULL); while (mp_bluetooth_nimble_ble_state != MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF) { - MICROPY_EVENT_POLL_HOOK + mp_event_wait_indefinite(); } } @@ -636,10 +636,11 @@ int mp_bluetooth_init(void) { // On non-ringbuffer builds (NimBLE on STM32/Unix) this will also poll the UART and run the event queue. mp_uint_t timeout_start_ticks_ms = mp_hal_ticks_ms(); while (mp_bluetooth_nimble_ble_state != MP_BLUETOOTH_NIMBLE_BLE_STATE_ACTIVE) { - if (mp_hal_ticks_ms() - timeout_start_ticks_ms > NIMBLE_STARTUP_TIMEOUT) { + uint32_t elapsed = mp_hal_ticks_ms() - timeout_start_ticks_ms; + if (elapsed > NIMBLE_STARTUP_TIMEOUT) { break; } - MICROPY_EVENT_POLL_HOOK + mp_event_wait_ms(NIMBLE_STARTUP_TIMEOUT - elapsed); } if (mp_bluetooth_nimble_ble_state != MP_BLUETOOTH_NIMBLE_BLE_STATE_ACTIVE) { diff --git a/ports/esp8266/esp_mphal.c b/ports/esp8266/esp_mphal.c index afa934e00c9c2..956cb2e6490ac 100644 --- a/ports/esp8266/esp_mphal.c +++ b/ports/esp8266/esp_mphal.c @@ -53,7 +53,7 @@ void mp_hal_init(void) { void MP_FASTCODE(mp_hal_delay_us)(uint32_t us) { uint32_t start = system_get_time(); while (system_get_time() - start < us) { - ets_event_poll(); + mp_event_handle_nowait(); } } @@ -122,11 +122,6 @@ uint64_t mp_hal_time_ns(void) { return pyb_rtc_get_us_since_epoch() * 1000ULL; } -void ets_event_poll(void) { - ets_loop_iter(); - mp_handle_pending(true); -} - void __assert_func(const char *file, int line, const char *func, const char *expr) { printf("assert:%s:%d:%s: %s\n", file, line, func, expr); mp_raise_msg(&mp_type_AssertionError, MP_ERROR_TEXT("C-level assert")); diff --git a/ports/esp8266/esp_mphal.h b/ports/esp8266/esp_mphal.h index 73a36a4b65fce..6fea6554b06fc 100644 --- a/ports/esp8266/esp_mphal.h +++ b/ports/esp8266/esp_mphal.h @@ -72,9 +72,6 @@ void dupterm_task_init(); uint32_t esp_disable_irq(void); void esp_enable_irq(uint32_t state); -void ets_event_poll(void); -#define ETS_POLL_WHILE(cond) { while (cond) ets_event_poll(); } - // needed for machine.I2C #include "osapi.h" #define mp_hal_delay_us_fast(us) os_delay_us(us) diff --git a/ports/esp8266/machine_uart.c b/ports/esp8266/machine_uart.c index f38858b0c2312..eaaa8ac865991 100644 --- a/ports/esp8266/machine_uart.c +++ b/ports/esp8266/machine_uart.c @@ -300,7 +300,7 @@ STATIC mp_uint_t mp_machine_uart_ioctl(mp_obj_t self_in, mp_uint_t request, uint if (mp_machine_uart_txdone(self)) { return 0; } - MICROPY_EVENT_POLL_HOOK + mp_event_wait_ms(1); } while (system_get_time() < timeout); *errcode = MP_ETIMEDOUT; diff --git a/ports/esp8266/modespnow.c b/ports/esp8266/modespnow.c index 9aa5fdf9d8b9f..170e488c10a04 100644 --- a/ports/esp8266/modespnow.c +++ b/ports/esp8266/modespnow.c @@ -285,7 +285,7 @@ static int ringbuf_get_bytes_wait(ringbuf_t *r, uint8_t *data, size_t len, mp_in int status = 0; while (((status = ringbuf_get_bytes(r, data, len)) == -1) && (timeout_ms < 0 || (mp_uint_t)(mp_hal_ticks_ms() - start) < (mp_uint_t)timeout_ms)) { - MICROPY_EVENT_POLL_HOOK; + mp_event_wait_ms(1); } return status; } diff --git a/ports/esp8266/modmachine.c b/ports/esp8266/modmachine.c index f41c84e14d58f..3cf5e3dd3bc54 100644 --- a/ports/esp8266/modmachine.c +++ b/ports/esp8266/modmachine.c @@ -91,7 +91,7 @@ STATIC mp_obj_t mp_machine_unique_id(void) { STATIC void mp_machine_idle(void) { asm ("waiti 0"); - ets_event_poll(); // handle any events after possibly a long wait (eg feed WDT) + mp_event_handle_nowait(); // handle any events after possibly a long wait (eg feed WDT) } STATIC void mp_machine_lightsleep(size_t n_args, const mp_obj_t *args) { @@ -106,7 +106,7 @@ STATIC void mp_machine_lightsleep(size_t n_args, const mp_obj_t *args) { uint32_t wifi_mode = wifi_get_opmode(); uint32_t start = system_get_time(); while (system_get_time() - start <= max_us) { - ets_event_poll(); + mp_event_handle_nowait(); if (wifi_mode == NULL_MODE) { // Can only idle if the wifi is off asm ("waiti 0"); diff --git a/ports/esp8266/mpconfigport.h b/ports/esp8266/mpconfigport.h index 07586a0ea5a95..bbfab64fba8c9 100644 --- a/ports/esp8266/mpconfigport.h +++ b/ports/esp8266/mpconfigport.h @@ -7,6 +7,7 @@ // Board-specific definitions #include "mpconfigboard.h" +#include #include // Set the rom feature level. @@ -116,13 +117,26 @@ #define MICROPY_FATFS_LFN_CODE_PAGE 437 /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */ #define MICROPY_ESP8266_APA102 (1) -#define MICROPY_EVENT_POLL_HOOK {ets_event_poll();} +// No blocking wait-for-event on ESP8266, only non-blocking pump of the "OS" event +// loop +// +// TODO: When TIMEOUT_MS==-1, it may be possible to have MICROPY_INTERNAL_WFE() call the "waiti" instruction. +// See mp_machine_idle() and mp_machine_lightsleep() in esp8266/modmachine.c +// +// Note: We have to scope the declaration of ets_loop_iter() here as there are multiple incompatible +// definitions at compile time between the SDK and axTLS! +#define MICROPY_INTERNAL_WFE(TIMEOUT_MS) +#define MICROPY_INTERNAL_EVENT_HOOK \ + do { \ + extern bool ets_loop_iter(void); \ + ets_loop_iter(); \ + } while (0) + #define MICROPY_VM_HOOK_COUNT (10) #define MICROPY_VM_HOOK_INIT static uint vm_hook_divisor = MICROPY_VM_HOOK_COUNT; #define MICROPY_VM_HOOK_POLL if (--vm_hook_divisor == 0) { \ vm_hook_divisor = MICROPY_VM_HOOK_COUNT; \ - extern void ets_loop_iter(void); \ - ets_loop_iter(); \ + MICROPY_INTERNAL_EVENT_HOOK; \ } #define MICROPY_VM_HOOK_LOOP MICROPY_VM_HOOK_POLL #define MICROPY_VM_HOOK_RETURN MICROPY_VM_HOOK_POLL diff --git a/ports/esp8266/uart.c b/ports/esp8266/uart.c index c0a33acb5732a..80ae5e6171bb6 100644 --- a/ports/esp8266/uart.c +++ b/ports/esp8266/uart.c @@ -18,6 +18,7 @@ #include "c_types.h" #include "user_interface.h" #include "py/mphal.h" +#include "py/runtime.h" // seems that this is missing in the Espressif SDK #define FUNC_U0RXD 0 @@ -218,7 +219,7 @@ bool ICACHE_FLASH_ATTR uart_rx_wait(uint32_t timeout_us) { if (system_get_time() - start >= timeout_us) { return false; // timeout } - ets_event_poll(); + mp_event_handle_nowait(); } } diff --git a/ports/rp2/cyw43_configport.h b/ports/rp2/cyw43_configport.h index 96324ee5ec966..b69cfbc263a28 100644 --- a/ports/rp2/cyw43_configport.h +++ b/ports/rp2/cyw43_configport.h @@ -30,6 +30,7 @@ #include "py/mpconfig.h" #include "py/mperrno.h" #include "py/mphal.h" +#include "py/runtime.h" #include "extmod/modnetwork.h" #include "pendsv.h" @@ -119,6 +120,6 @@ static inline void cyw43_delay_ms(uint32_t ms) { mp_hal_delay_ms(ms); } -#define CYW43_EVENT_POLL_HOOK MICROPY_EVENT_POLL_HOOK_FAST +#define CYW43_EVENT_POLL_HOOK mp_event_handle_nowait() #endif // MICROPY_INCLUDED_RP2_CYW43_CONFIGPORT_H diff --git a/ports/rp2/machine_uart.c b/ports/rp2/machine_uart.c index dae57012a8d3d..e48924f09ae84 100644 --- a/ports/rp2/machine_uart.c +++ b/ports/rp2/machine_uart.c @@ -454,8 +454,8 @@ STATIC void mp_machine_uart_sendbreak(machine_uart_obj_t *self) { STATIC mp_uint_t mp_machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) { machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); - uint64_t t = time_us_64() + (uint64_t)self->timeout * 1000; - uint64_t timeout_char_us = (uint64_t)self->timeout_char * 1000; + mp_uint_t start = mp_hal_ticks_ms(); + mp_uint_t timeout = self->timeout; uint8_t *dest = buf_in; for (size_t i = 0; i < size; i++) { @@ -466,7 +466,8 @@ STATIC mp_uint_t mp_machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t uart_drain_rx_fifo(self); break; } - if (time_us_64() > t) { // timed out + mp_uint_t elapsed = mp_hal_ticks_ms() - start; + if (elapsed > timeout) { // timed out if (i <= 0) { *errcode = MP_EAGAIN; return MP_STREAM_ERROR; @@ -474,18 +475,19 @@ STATIC mp_uint_t mp_machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t return i; } } - MICROPY_EVENT_POLL_HOOK + mp_event_wait_ms(timeout - elapsed); } *dest++ = ringbuf_get(&(self->read_buffer)); - t = time_us_64() + timeout_char_us; + start = mp_hal_ticks_ms(); // Inter-character timeout + timeout = self->timeout_char; } return size; } STATIC mp_uint_t mp_machine_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) { machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); - uint64_t t = time_us_64() + (uint64_t)self->timeout * 1000; - uint64_t timeout_char_us = (uint64_t)self->timeout_char * 1000; + mp_uint_t start = mp_hal_ticks_ms(); + mp_uint_t timeout = self->timeout; const uint8_t *src = buf_in; size_t i = 0; @@ -502,7 +504,8 @@ STATIC mp_uint_t mp_machine_uart_write(mp_obj_t self_in, const void *buf_in, mp_ while (i < size) { // Wait for the first/next character to be sent. while (ringbuf_free(&(self->write_buffer)) == 0) { - if (time_us_64() > t) { // timed out + mp_uint_t elapsed = mp_hal_ticks_ms() - start; + if (elapsed > timeout) { // timed out if (i <= 0) { *errcode = MP_EAGAIN; return MP_STREAM_ERROR; @@ -510,11 +513,12 @@ STATIC mp_uint_t mp_machine_uart_write(mp_obj_t self_in, const void *buf_in, mp_ return i; } } - MICROPY_EVENT_POLL_HOOK + mp_event_wait_ms(timeout - elapsed); } ringbuf_put(&(self->write_buffer), *src++); ++i; - t = time_us_64() + timeout_char_us; + start = mp_hal_ticks_ms(); // Inter-character timeout + timeout = self->timeout_char; uart_fill_tx_fifo(self); } @@ -539,12 +543,16 @@ STATIC mp_uint_t mp_machine_uart_ioctl(mp_obj_t self_in, mp_uint_t request, uint // Take the worst case assumptions at 13 bit symbol size times 2. uint64_t timeout = time_us_64() + (uint64_t)(33 + self->write_buffer.size) * 13000000ll * 2 / self->baudrate; - do { + while (1) { if (mp_machine_uart_txdone(self)) { return 0; } - MICROPY_EVENT_POLL_HOOK - } while (time_us_64() < timeout); + uint64_t now = time_us_64(); + if (now >= timeout) { + break; + } + mp_event_wait_ms((timeout - now) / 1000); + } *errcode = MP_ETIMEDOUT; ret = MP_STREAM_ERROR; } else { diff --git a/ports/rp2/main.c b/ports/rp2/main.c index 43680a46cd68f..8b41fac4ba856 100644 --- a/ports/rp2/main.c +++ b/ports/rp2/main.c @@ -73,6 +73,9 @@ bi_decl(bi_program_feature_group_with_flags(BINARY_INFO_TAG_MICROPYTHON, BI_NAMED_GROUP_SEPARATE_COMMAS | BI_NAMED_GROUP_SORT_ALPHA)); int main(int argc, char **argv) { + // This is a tickless port, interrupts should always trigger SEV. + SCB->SCR |= SCB_SCR_SEVONPEND_Msk; + #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 5ff384c923b47..b349e0d67ba5e 100644 --- a/ports/rp2/mpconfigport.h +++ b/ports/rp2/mpconfigport.h @@ -249,18 +249,19 @@ extern const struct _mp_obj_type_t mod_network_nic_type_wiznet5k; #define MICROPY_PY_LWIP_REENTER lwip_lock_acquire(); #define MICROPY_PY_LWIP_EXIT lwip_lock_release(); -#define MICROPY_EVENT_POLL_HOOK_FAST \ - do { \ - extern void mp_handle_pending(bool); \ - mp_handle_pending(true); \ +// Port level Wait-for-Event macro +// +// Do not use this macro directly, include py/runtime.h and +// call mp_event_wait_indefinite() or mp_event_wait_ms(timeout) +#define MICROPY_INTERNAL_WFE(TIMEOUT_MS) \ + do { \ + if ((TIMEOUT_MS) < 0) { \ + __wfe(); \ + } else { \ + best_effort_wfe_or_timeout(make_timeout_time_ms(TIMEOUT_MS)); \ + } \ } while (0) -#define MICROPY_EVENT_POLL_HOOK \ - do { \ - MICROPY_EVENT_POLL_HOOK_FAST; \ - __wfe(); \ - } while (0); - #define MICROPY_MAKE_POINTER_CALLABLE(p) ((void *)((mp_uint_t)(p) | 1)) #define MP_SSIZE_MAX (0x7fffffff) diff --git a/ports/rp2/mphalport.c b/ports/rp2/mphalport.c index 1fb833f2e5dc2..1c784fd737e8a 100644 --- a/ports/rp2/mphalport.c +++ b/ports/rp2/mphalport.c @@ -59,24 +59,17 @@ ringbuf_t stdin_ringbuf = { stdin_ringbuf_array, sizeof(stdin_ringbuf_array) }; #endif -#if MICROPY_HW_USB_CDC -// Explicitly run the USB stack in case the scheduler is locked (eg we are in an -// interrupt handler) and there is in/out data pending on the USB CDC interface. -#define MICROPY_EVENT_POLL_HOOK_WITH_USB \ - do { \ - MICROPY_EVENT_POLL_HOOK; \ - mp_usbd_task(); \ - } while (0) - -#else -#define MICROPY_EVENT_POLL_HOOK_WITH_USB MICROPY_EVENT_POLL_HOOK -#endif - #if MICROPY_HW_USB_CDC uint8_t cdc_itf_pending; // keep track of cdc interfaces which need attention to poll void poll_cdc_interfaces(void) { + if (!cdc_itf_pending) { + // Explicitly run the USB stack as the scheduler may be locked (eg we are in + // an interrupt handler) while there is data pending. + mp_usbd_task(); + } + // any CDC interfaces left to poll? if (cdc_itf_pending && ringbuf_free(&stdin_ringbuf)) { for (uint8_t itf = 0; itf < 8; ++itf) { @@ -153,7 +146,7 @@ int mp_hal_stdin_rx_chr(void) { return dupterm_c; } #endif - MICROPY_EVENT_POLL_HOOK_WITH_USB; + mp_event_wait_indefinite(); } } @@ -173,7 +166,11 @@ void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) { int timeout = 0; // Wait with a max of USC_CDC_TIMEOUT ms while (n > tud_cdc_write_available() && timeout++ < MICROPY_HW_USB_CDC_TX_TIMEOUT) { - MICROPY_EVENT_POLL_HOOK_WITH_USB; + mp_event_wait_ms(1); + + // Explicitly run the USB stack as the scheduler may be locked (eg we + // are in an interrupt handler), while there is data pending. + mp_usbd_task(); } if (timeout >= MICROPY_HW_USB_CDC_TX_TIMEOUT) { break; @@ -193,7 +190,7 @@ void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) { void mp_hal_delay_ms(mp_uint_t ms) { absolute_time_t t = make_timeout_time_ms(ms); do { - MICROPY_EVENT_POLL_HOOK_FAST; + mp_event_handle_nowait(); } while (!best_effort_wfe_or_timeout(t)); } diff --git a/ports/rp2/rp2_flash.c b/ports/rp2/rp2_flash.c index bc284cd976020..b1afe1cbd1e72 100644 --- a/ports/rp2/rp2_flash.c +++ b/ports/rp2/rp2_flash.c @@ -121,11 +121,10 @@ STATIC mp_obj_t rp2_flash_readblocks(size_t n_args, const mp_obj_t *args) { offset += mp_obj_get_int(args[3]); } memcpy(bufinfo.buf, (void *)(XIP_BASE + self->flash_base + offset), bufinfo.len); - // MICROPY_EVENT_POLL_HOOK_FAST is called here to avoid a fail in registering + // mp_event_handle_nowait() is called here to avoid a fail in registering // USB at boot time, if the board is busy loading files or scanning the file - // system. MICROPY_EVENT_POLL_HOOK_FAST calls tud_task(). As the alternative - // tud_task() should be called in the USB IRQ. See discussion in PR #10423. - MICROPY_EVENT_POLL_HOOK_FAST; + // system. mp_event_handle_nowait() will call the TinyUSB task if needed. + mp_event_handle_nowait(); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(rp2_flash_readblocks_obj, 3, 4, rp2_flash_readblocks); @@ -140,7 +139,7 @@ STATIC mp_obj_t rp2_flash_writeblocks(size_t n_args, const mp_obj_t *args) { mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); flash_range_erase(self->flash_base + offset, bufinfo.len); MICROPY_END_ATOMIC_SECTION(atomic_state); - MICROPY_EVENT_POLL_HOOK_FAST; + mp_event_handle_nowait(); // TODO check return value } else { offset += mp_obj_get_int(args[3]); @@ -149,7 +148,7 @@ STATIC mp_obj_t rp2_flash_writeblocks(size_t n_args, const mp_obj_t *args) { mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); flash_range_program(self->flash_base + offset, bufinfo.buf, bufinfo.len); MICROPY_END_ATOMIC_SECTION(atomic_state); - MICROPY_EVENT_POLL_HOOK_FAST; + mp_event_handle_nowait(); // TODO check return value return mp_const_none; } diff --git a/ports/rp2/rp2_pio.c b/ports/rp2/rp2_pio.c index 2e304752573b7..3a0ab844eafd4 100644 --- a/ports/rp2/rp2_pio.c +++ b/ports/rp2/rp2_pio.c @@ -729,7 +729,7 @@ STATIC mp_obj_t rp2_state_machine_get(size_t n_args, const mp_obj_t *args) { for (;;) { while (pio_sm_is_rx_fifo_empty(self->pio, self->sm)) { // This delay must be fast. - MICROPY_EVENT_POLL_HOOK_FAST; + mp_event_handle_nowait(); } uint32_t value = pio_sm_get(self->pio, self->sm) >> shift; if (dest == NULL) { @@ -787,7 +787,7 @@ STATIC mp_obj_t rp2_state_machine_put(size_t n_args, const mp_obj_t *args) { } while (pio_sm_is_tx_fifo_full(self->pio, self->sm)) { // This delay must be fast. - MICROPY_EVENT_POLL_HOOK_FAST; + mp_event_handle_nowait(); } pio_sm_put(self->pio, self->sm, value << shift); } diff --git a/ports/unix/coverage.c b/ports/unix/coverage.c index 88dd48bfabeb8..543af365c25e9 100644 --- a/ports/unix/coverage.c +++ b/ports/unix/coverage.c @@ -578,9 +578,10 @@ STATIC mp_obj_t extra_coverage(void) { mp_sched_unlock(); mp_printf(&mp_plat_print, "unlocked\n"); - // drain pending callbacks + // drain pending callbacks, and test mp_event_wait_indefinite(), mp_event_wait_ms() + mp_event_wait_indefinite(); // the unix port only waits 500us in this call while (mp_sched_num_pending()) { - mp_handle_pending(true); + mp_event_wait_ms(1); } // setting the keyboard interrupt and raising it during mp_handle_pending diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h index e7ce534a71e04..c7e7347cbb2b4 100644 --- a/ports/unix/mpconfigport.h +++ b/ports/unix/mpconfigport.h @@ -222,14 +222,10 @@ static inline unsigned long mp_random_seed_init(void) { #endif // In lieu of a WFI(), slow down polling from being a tight loop. -#ifndef MICROPY_EVENT_POLL_HOOK -#define MICROPY_EVENT_POLL_HOOK \ - do { \ - extern void mp_handle_pending(bool); \ - mp_handle_pending(true); \ - usleep(500); /* equivalent to mp_hal_delay_us(500) */ \ - } while (0); -#endif +// +// Note that we don't delay for the full TIMEOUT_MS, as execution +// can't be woken from the delay. +#define MICROPY_INTERNAL_WFE(TIMEOUT_MS) mp_hal_delay_us(500) // Configure the implementation of machine.idle(). #include diff --git a/ports/unix/unix_mphal.c b/ports/unix/unix_mphal.c index eafc915ca4b31..8d6539c88e382 100644 --- a/ports/unix/unix_mphal.c +++ b/ports/unix/unix_mphal.c @@ -237,17 +237,10 @@ uint64_t mp_hal_time_ns(void) { #ifndef mp_hal_delay_ms void mp_hal_delay_ms(mp_uint_t ms) { - #ifdef MICROPY_EVENT_POLL_HOOK mp_uint_t start = mp_hal_ticks_ms(); while (mp_hal_ticks_ms() - start < ms) { - // MICROPY_EVENT_POLL_HOOK does usleep(500). - MICROPY_EVENT_POLL_HOOK + mp_event_wait_ms(1); } - #else - // TODO: POSIX et al. define usleep() as guaranteedly capable only of 1s sleep: - // "The useconds argument shall be less than one million." - usleep(ms * 1000); - #endif } #endif diff --git a/ports/windows/mpconfigport.h b/ports/windows/mpconfigport.h index 2e1521b9c7ef9..e615fe8502b0c 100644 --- a/ports/windows/mpconfigport.h +++ b/ports/windows/mpconfigport.h @@ -227,14 +227,11 @@ typedef long mp_off_t; #include "sleep.h" #if MICROPY_ENABLE_SCHEDULER -// Use 1mSec sleep to make sure there is effectively a wait period: +// Use minimum 1mSec sleep to make sure there is effectively a wait period: // something like usleep(500) truncates and ends up calling Sleep(0). -#define MICROPY_EVENT_POLL_HOOK \ - do { \ - extern void mp_handle_pending(bool); \ - mp_handle_pending(true); \ - msec_sleep(1.0); \ - } while (0); +#define MICROPY_INTERNAL_WFE(TIMEOUT_MS) msec_sleep(MAX(1.0, (double)(TIMEOUT_MS))) +#else +#define MICROPY_INTERNAL_WFE(TIMEOUT_MS) /* No-op */ #endif #ifdef __GNUC__ diff --git a/py/mphal.h b/py/mphal.h index 19fceef71853d..81cf50918e35d 100644 --- a/py/mphal.h +++ b/py/mphal.h @@ -98,4 +98,17 @@ uint64_t mp_hal_time_ns(void); #include "extmod/virtpin.h" #endif +// Event handling and wait-for-event functions. + +#ifndef MICROPY_INTERNAL_WFE +// Fallback definition for ports that don't need to suspend the CPU. +#define MICROPY_INTERNAL_WFE(TIMEOUT_MS) (void)0 +#endif + +#ifndef MICROPY_INTERNAL_EVENT_HOOK +// Fallback definition for ports that don't need any port-specific +// non-blocking event processing. +#define MICROPY_INTERNAL_EVENT_HOOK (void)0 +#endif + #endif // MICROPY_INCLUDED_PY_MPHAL_H diff --git a/py/runtime.h b/py/runtime.h index 5fa072d7e99d2..a04d4584f804c 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -109,6 +109,23 @@ bool mp_sched_schedule(mp_obj_t function, mp_obj_t arg); bool mp_sched_schedule_node(mp_sched_node_t *node, mp_sched_callback_t callback); #endif +// Handles any pending MicroPython events without waiting for an interrupt or event. +void mp_event_handle_nowait(void); + +// Handles any pending MicroPython events and then suspends execution until the +// next interrupt or event. +// +// Note: on "tickless" ports this can suspend execution for a long time, +// don't call unless you know an interrupt is coming to continue execution. +// On "ticked" ports it may return early due to the tick interrupt. +void mp_event_wait_indefinite(void); + +// Handle any pending MicroPython events and then suspends execution until the +// next interrupt or event, or until timeout_ms milliseconds have elapsed. +// +// On "ticked" ports it may return early due to the tick interrupt. +void mp_event_wait_ms(mp_uint_t timeout_ms); + // extra printing method specifically for mp_obj_t's which are integral type int mp_print_mp_int(const mp_print_t *print, mp_obj_t x, int base, int base_char, int flags, char fill, int width, int prec); diff --git a/py/scheduler.c b/py/scheduler.c index b9a43bfbdb6f4..3eae8b4fa366c 100644 --- a/py/scheduler.c +++ b/py/scheduler.c @@ -241,3 +241,39 @@ void mp_handle_pending(bool raise_exc) { } #endif } + +// Handles any pending MicroPython events without waiting for an interrupt or event. +void mp_event_handle_nowait(void) { + #if defined(MICROPY_EVENT_POLL_HOOK_FAST) && !MICROPY_PREVIEW_VERSION_2 + // For ports still using the old macros. + MICROPY_EVENT_POLL_HOOK_FAST + #else + // Process any port layer (non-blocking) events. + MICROPY_INTERNAL_EVENT_HOOK; + mp_handle_pending(true); + #endif +} + +// Handles any pending MicroPython events and then suspends execution until the +// next interrupt or event. +void mp_event_wait_indefinite(void) { + #if defined(MICROPY_EVENT_POLL_HOOK) && !MICROPY_PREVIEW_VERSION_2 + // For ports still using the old macros. + MICROPY_EVENT_POLL_HOOK + #else + mp_event_handle_nowait(); + MICROPY_INTERNAL_WFE(-1); + #endif +} + +// Handle any pending MicroPython events and then suspends execution until the +// next interrupt or event, or until timeout_ms milliseconds have elapsed. +void mp_event_wait_ms(mp_uint_t timeout_ms) { + #if defined(MICROPY_EVENT_POLL_HOOK) && !MICROPY_PREVIEW_VERSION_2 + // For ports still using the old macros. + MICROPY_EVENT_POLL_HOOK + #else + mp_event_handle_nowait(); + MICROPY_INTERNAL_WFE(timeout_ms); + #endif +} pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy