summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Walther <cwalther@gmx.ch>2024-01-05 16:17:55 +0100
committerDamien George <damien@micropython.org>2024-03-26 15:21:01 +1100
commit5e926b222259cb38db5c044b2f7656e2bdba2513 (patch)
tree47c9984cc8052be7707d303c909b25c4ef4c5330
parentb10182bbcc0ee78ce5d12902bc8da68bdc4429c5 (diff)
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 <cwalther@gmx.ch>
-rw-r--r--ports/nrf/modules/machine/pin.c25
-rw-r--r--ports/nrf/modules/machine/uart.c8
2 files changed, 27 insertions, 6 deletions
diff --git a/ports/nrf/modules/machine/pin.c b/ports/nrf/modules/machine/pin.c
index f86d878d1..2191cc952 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 9e502941a..de26fa1b1 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) {