From 5e926b222259cb38db5c044b2f7656e2bdba2513 Mon Sep 17 00:00:00 2001 From: Christian Walther Date: Fri, 5 Jan 2024 16:17:55 +0100 Subject: [PATCH] nrf/modules/machine: Catch exceptions from pin interrupts. Exceptions in pin interrupt handlers would end up crashing MicroPython with a "FATAL: uncaught exception". In addition, MicroPython would get stuck trying to output this error message, or generally any print output from inside a pin interrupt handler, through the UART after the first character, so that only "F" was visible. The reason was a matching interrupt priority between the running pin interrupt and the UARTE interrupt signaling completion of the output operation. Fix that by increasing the UARTE interrupt priority. Code taken from the stm32 port and adapted. Signed-off-by: Christian Walther --- ports/nrf/modules/machine/pin.c | 25 ++++++++++++++++++++++++- ports/nrf/modules/machine/uart.c | 8 +++----- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/ports/nrf/modules/machine/pin.c b/ports/nrf/modules/machine/pin.c index f86d878d17..2191cc9521 100644 --- a/ports/nrf/modules/machine/pin.c +++ b/ports/nrf/modules/machine/pin.c @@ -33,6 +33,7 @@ #include "py/nlr.h" #include "py/runtime.h" #include "py/mphal.h" +#include "py/gc.h" #include "pin.h" #include "nrf_gpio.h" #include "nrfx_gpiote.h" @@ -498,7 +499,29 @@ static void pin_common_irq_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t mp_obj_t pin_number = MP_OBJ_NEW_SMALL_INT(pin); const pin_obj_t *pin_obj = pin_find(pin_number); - mp_call_function_1(pin_handler, (mp_obj_t)pin_obj); + if (pin_handler != mp_const_none) { + #if MICROPY_ENABLE_SCHEDULER + mp_sched_lock(); + #endif + // When executing code within a handler we must lock the GC to prevent + // any memory allocations. We must also catch any exceptions. + gc_lock(); + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_call_function_1(pin_handler, (mp_obj_t)pin_obj); + nlr_pop(); + } else { + // Uncaught exception; disable the callback so it doesn't run again. + MP_STATE_PORT(pin_irq_handlers)[pin] = mp_const_none; + nrfx_gpiote_in_uninit(pin); + mp_printf(MICROPY_ERROR_PRINTER, "uncaught exception in interrupt handler for Pin('%q')\n", pin_obj->name); + mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); + } + gc_unlock(); + #if MICROPY_ENABLE_SCHEDULER + mp_sched_unlock(); + #endif + } } static mp_obj_t pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { diff --git a/ports/nrf/modules/machine/uart.c b/ports/nrf/modules/machine/uart.c index 9e502941ab..de26fa1b12 100644 --- a/ports/nrf/modules/machine/uart.c +++ b/ports/nrf/modules/machine/uart.c @@ -214,11 +214,9 @@ static mp_obj_t mp_machine_uart_make_new(const mp_obj_type_t *type, size_t n_arg config.hal_cfg.parity = NRF_UART_PARITY_EXCLUDED; - #if (BLUETOOTH_SD == 100) - config.interrupt_priority = 3; - #else - config.interrupt_priority = 6; - #endif + // Higher priority than pin interrupts, otherwise printing exceptions from + // interrupt handlers gets stuck. + config.interrupt_priority = NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY - 1; // These baudrates are not supported, it seems. if (args[ARG_baudrate].u_int < 1200 || args[ARG_baudrate].u_int > 1000000) {