summaryrefslogtreecommitdiffstatshomepage
path: root/ports/rp2/machine_timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'ports/rp2/machine_timer.c')
-rw-r--r--ports/rp2/machine_timer.c30
1 files changed, 28 insertions, 2 deletions
diff --git a/ports/rp2/machine_timer.c b/ports/rp2/machine_timer.c
index 6f8b04f10e..ffb4c70243 100644
--- a/ports/rp2/machine_timer.c
+++ b/ports/rp2/machine_timer.c
@@ -27,6 +27,7 @@
#include "py/runtime.h"
#include "py/mperrno.h"
#include "py/mphal.h"
+#include "py/gc.h"
#include "pico/time.h"
#define ALARM_ID_INVALID (-1)
@@ -40,13 +41,36 @@ typedef struct _machine_timer_obj_t {
uint32_t mode;
uint64_t delta_us; // for periodic mode
mp_obj_t callback;
+ bool ishard;
} machine_timer_obj_t;
const mp_obj_type_t machine_timer_type;
static int64_t alarm_callback(alarm_id_t id, void *user_data) {
machine_timer_obj_t *self = user_data;
- mp_sched_schedule(self->callback, MP_OBJ_FROM_PTR(self));
+
+ if (self->ishard) {
+ // When executing code within a handler we must lock the scheduler to
+ // prevent any scheduled callbacks from running, and lock the GC to
+ // prevent any memory allocations.
+ mp_sched_lock();
+ gc_lock();
+ nlr_buf_t nlr;
+ if (nlr_push(&nlr) == 0) {
+ mp_call_function_1(self->callback, MP_OBJ_FROM_PTR(self));
+ nlr_pop();
+ } else {
+ // Uncaught exception; disable the callback so it doesn't run again.
+ self->mode = TIMER_MODE_ONE_SHOT;
+ mp_printf(MICROPY_ERROR_PRINTER, "uncaught exception in timer callback\n");
+ mp_obj_print_exception(MICROPY_ERROR_PRINTER, MP_OBJ_FROM_PTR(nlr.ret_val));
+ }
+ gc_unlock();
+ mp_sched_unlock();
+ } else {
+ mp_sched_schedule(self->callback, MP_OBJ_FROM_PTR(self));
+ }
+
if (self->mode == TIMER_MODE_ONE_SHOT) {
return 0;
} else {
@@ -66,13 +90,14 @@ static void machine_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_pr
}
static mp_obj_t machine_timer_init_helper(machine_timer_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
- enum { ARG_mode, ARG_callback, ARG_period, ARG_tick_hz, ARG_freq, };
+ enum { ARG_mode, ARG_callback, ARG_period, ARG_tick_hz, 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} },
{ MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
{ MP_QSTR_period, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} },
{ MP_QSTR_tick_hz, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1000} },
{ MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
+ { MP_QSTR_hard, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
};
// Parse args
@@ -96,6 +121,7 @@ static mp_obj_t machine_timer_init_helper(machine_timer_obj_t *self, size_t n_ar
}
self->callback = args[ARG_callback].u_obj;
+ self->ishard = args[ARG_hard].u_bool;
self->alarm_id = alarm_pool_add_alarm_in_us(self->pool, self->delta_us, alarm_callback, self, true);
if (self->alarm_id == -1) {
mp_raise_OSError(MP_ENOMEM);