Skip to content

Commit 7816b1f

Browse files
committed
rp2/machine_timer: Support hard IRQ timer callbacks.
Unlike some boards like stm32, timer callbacks on the rp2 port are unconditionally dispatched via mp_sched_schedule(), behaving like soft IRQs with consequent GC jitter and delays. Add a 'hard' keyword argument to the rp2 Timer constructor and init. This defaults to False but if it is set True, the timer callback will be dispatched in hard IRQ context rather than queued. Signed-off-by: Chris Webb <chris@arachsys.com>
1 parent cfcc53d commit 7816b1f

File tree

1 file changed

+28
-2
lines changed

1 file changed

+28
-2
lines changed

ports/rp2/machine_timer.c

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "py/runtime.h"
2828
#include "py/mperrno.h"
2929
#include "py/mphal.h"
30+
#include "py/gc.h"
3031
#include "pico/time.h"
3132

3233
#define ALARM_ID_INVALID (-1)
@@ -40,13 +41,36 @@ typedef struct _machine_timer_obj_t {
4041
uint32_t mode;
4142
uint64_t delta_us; // for periodic mode
4243
mp_obj_t callback;
44+
bool ishard;
4345
} machine_timer_obj_t;
4446

4547
const mp_obj_type_t machine_timer_type;
4648

4749
static int64_t alarm_callback(alarm_id_t id, void *user_data) {
4850
machine_timer_obj_t *self = user_data;
49-
mp_sched_schedule(self->callback, MP_OBJ_FROM_PTR(self));
51+
52+
if (self->ishard) {
53+
// When executing code within a handler we must lock the scheduler to
54+
// prevent any scheduled callbacks from running, and lock the GC to
55+
// prevent any memory allocations.
56+
mp_sched_lock();
57+
gc_lock();
58+
nlr_buf_t nlr;
59+
if (nlr_push(&nlr) == 0) {
60+
mp_call_function_1(self->callback, MP_OBJ_FROM_PTR(self));
61+
nlr_pop();
62+
} else {
63+
// Uncaught exception; disable the callback so it doesn't run again.
64+
self->mode = TIMER_MODE_ONE_SHOT;
65+
mp_printf(MICROPY_ERROR_PRINTER, "uncaught exception in timer callback\n");
66+
mp_obj_print_exception(MICROPY_ERROR_PRINTER, MP_OBJ_FROM_PTR(nlr.ret_val));
67+
}
68+
gc_unlock();
69+
mp_sched_unlock();
70+
} else {
71+
mp_sched_schedule(self->callback, MP_OBJ_FROM_PTR(self));
72+
}
73+
5074
if (self->mode == TIMER_MODE_ONE_SHOT) {
5175
return 0;
5276
} else {
@@ -66,13 +90,14 @@ static void machine_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_pr
6690
}
6791

6892
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) {
69-
enum { ARG_mode, ARG_callback, ARG_period, ARG_tick_hz, ARG_freq, };
93+
enum { ARG_mode, ARG_callback, ARG_period, ARG_tick_hz, ARG_freq, ARG_hard, };
7094
static const mp_arg_t allowed_args[] = {
7195
{ MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = TIMER_MODE_PERIODIC} },
7296
{ MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
7397
{ MP_QSTR_period, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} },
7498
{ MP_QSTR_tick_hz, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1000} },
7599
{ MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
100+
{ MP_QSTR_hard, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
76101
};
77102

78103
// Parse args
@@ -96,6 +121,7 @@ static mp_obj_t machine_timer_init_helper(machine_timer_obj_t *self, size_t n_ar
96121
}
97122

98123
self->callback = args[ARG_callback].u_obj;
124+
self->ishard = args[ARG_hard].u_bool;
99125
self->alarm_id = alarm_pool_add_alarm_in_us(self->pool, self->delta_us, alarm_callback, self, true);
100126
if (self->alarm_id == -1) {
101127
mp_raise_OSError(MP_ENOMEM);

0 commit comments

Comments
 (0)
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