diff --git a/ports/zephyr/machine_timer.c b/ports/zephyr/machine_timer.c index 1bb743c2eb..410e86762b 100644 --- a/ports/zephyr/machine_timer.c +++ b/ports/zephyr/machine_timer.c @@ -27,9 +27,11 @@ #include #include +#include "py/gc.h" #include "py/mperrno.h" #include "py/obj.h" #include "py/runtime.h" +#include "shared/runtime/mpirq.h" #include "modmachine.h" #include #include @@ -51,6 +53,7 @@ typedef struct _machine_timer_obj_t { uint32_t period_ms; mp_obj_t callback; + bool ishard; struct _machine_timer_obj_t *next; } machine_timer_obj_t; @@ -62,12 +65,31 @@ static mp_obj_t machine_timer_deinit(mp_obj_t self_in); static void machine_timer_callback(struct k_timer *timer) { machine_timer_obj_t *self = (machine_timer_obj_t *)k_timer_user_data_get(timer); + + #if MICROPY_STACK_CHECK + // This callback executes in an ISR context so the stack-limit check must + // be changed to use the ISR stack for the duration of this function (so + // that hard IRQ callbacks work). + char *orig_stack_top = MP_STATE_THREAD(stack_top); + size_t orig_stack_limit = MP_STATE_THREAD(stack_limit); + MP_STATE_THREAD(stack_top) = (void *)&self; + MP_STATE_THREAD(stack_limit) = CONFIG_ISR_STACK_SIZE - 512; + #endif + + if (mp_irq_dispatch(self->callback, MP_OBJ_FROM_PTR(self), self->ishard) < 0) { + // Uncaught exception; disable the callback so it doesn't run again. + self->mode = TIMER_MODE_ONE_SHOT; + } + if (self->mode == TIMER_MODE_ONE_SHOT) { machine_timer_deinit(self); } - if (self->callback != mp_const_none) { - mp_sched_schedule(self->callback, MP_OBJ_FROM_PTR(self)); - } + + #if MICROPY_STACK_CHECK + // Restore original stack-limit checking values. + MP_STATE_THREAD(stack_top) = orig_stack_top; + MP_STATE_THREAD(stack_limit) = orig_stack_limit; + #endif } static void machine_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { @@ -109,6 +131,7 @@ static mp_obj_t machine_timer_init_helper(machine_timer_obj_t *self, mp_uint_t n ARG_callback, ARG_period, ARG_freq, + ARG_hard, }; static const mp_arg_t allowed_args[] = { { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = TIMER_MODE_PERIODIC} }, @@ -119,6 +142,7 @@ static mp_obj_t machine_timer_init_helper(machine_timer_obj_t *self, mp_uint_t n #else { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} }, #endif + { MP_QSTR_hard, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -139,6 +163,7 @@ static mp_obj_t machine_timer_init_helper(machine_timer_obj_t *self, mp_uint_t n self->mode = args[ARG_mode].u_int; self->callback = args[ARG_callback].u_obj; + self->ishard = args[ARG_hard].u_bool; k_timer_init(&self->my_timer, machine_timer_callback, NULL); k_timer_user_data_set(&self->my_timer, self);