mirror of
https://github.com/micropython/micropython.git
synced 2026-01-04 19:20:22 +01:00
stm32/timer: Support soft IRQ timer callbacks.
machine.Timer() has inconsistent behaviour between ports: some run callbacks in hard IRQ context whereas others schedule them like soft IRQs. As on the rp2 port, add support to the stm32 port for a hard= argument to explicitly choose between these, setting the default to True to match the existing behaviour. Signed-off-by: Chris Webb <chris@arachsys.com>
This commit is contained in:
committed by
Damien George
parent
a69b08b756
commit
49f2a1f0ed
@@ -29,6 +29,7 @@
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "py/gc.h"
|
||||
#include "shared/runtime/mpirq.h"
|
||||
#include "timer.h"
|
||||
#include "servo.h"
|
||||
#include "pin.h"
|
||||
@@ -131,6 +132,7 @@ typedef struct _pyb_timer_obj_t {
|
||||
uint8_t tim_id;
|
||||
uint8_t is_32bit;
|
||||
mp_obj_t callback;
|
||||
bool ishard;
|
||||
TIM_HandleTypeDef tim;
|
||||
IRQn_Type irqn;
|
||||
pyb_timer_channel_obj_t *channel;
|
||||
@@ -632,10 +634,14 @@ static void pyb_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_
|
||||
/// BRK_IN input is triggered. It can be set to `BRK_OFF`, `BRK_LOW`
|
||||
/// and `BRK_HIGH`.
|
||||
///
|
||||
/// - `hard` - specifies if the timer and channel callbacks should be run
|
||||
/// in hard-IRQ context (the default on stm32) or scheduled as a soft
|
||||
/// handler.
|
||||
///
|
||||
///
|
||||
/// You must either specify freq or both of period and prescaler.
|
||||
static mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_freq, ARG_prescaler, ARG_period, ARG_tick_hz, ARG_mode, ARG_div, ARG_callback, ARG_deadtime, ARG_brk };
|
||||
enum { ARG_freq, ARG_prescaler, ARG_period, ARG_tick_hz, ARG_mode, ARG_div, ARG_callback, ARG_deadtime, ARG_brk, ARG_hard };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
|
||||
{ MP_QSTR_prescaler, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} },
|
||||
@@ -646,6 +652,7 @@ static mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, size_t n_args, cons
|
||||
{ MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
|
||||
{ MP_QSTR_deadtime, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_brk, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = BRK_OFF} },
|
||||
{ MP_QSTR_hard, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
|
||||
};
|
||||
|
||||
// parse args
|
||||
@@ -828,6 +835,7 @@ static mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, size_t n_args, cons
|
||||
self->tim.Instance->CR1 |= TIM_CR1_ARPE;
|
||||
|
||||
// Start the timer running
|
||||
self->ishard = args[ARG_hard].u_bool;
|
||||
if (args[ARG_callback].u_obj == mp_const_none) {
|
||||
HAL_TIM_Base_Start(&self->tim);
|
||||
} else {
|
||||
@@ -1708,29 +1716,10 @@ static void timer_handle_irq_channel(pyb_timer_obj_t *tim, uint8_t channel, mp_o
|
||||
// clear the interrupt
|
||||
__HAL_TIM_CLEAR_IT(&tim->tim, irq_mask);
|
||||
|
||||
// execute callback if it's set
|
||||
if (callback != mp_const_none) {
|
||||
mp_sched_lock();
|
||||
// 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(callback, MP_OBJ_FROM_PTR(tim));
|
||||
nlr_pop();
|
||||
} else {
|
||||
// Uncaught exception; disable the callback so it doesn't run again.
|
||||
tim->callback = mp_const_none;
|
||||
__HAL_TIM_DISABLE_IT(&tim->tim, irq_mask);
|
||||
if (channel == 0) {
|
||||
mp_printf(MICROPY_ERROR_PRINTER, "uncaught exception in Timer(%u) interrupt handler\n", tim->tim_id);
|
||||
} else {
|
||||
mp_printf(MICROPY_ERROR_PRINTER, "uncaught exception in Timer(%u) channel %u interrupt handler\n", tim->tim_id, channel);
|
||||
}
|
||||
mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));
|
||||
}
|
||||
gc_unlock();
|
||||
mp_sched_unlock();
|
||||
if (mp_irq_dispatch(callback, MP_OBJ_FROM_PTR(tim), tim->ishard) < 0) {
|
||||
// Uncaught exception; disable the callback so it doesn't run again.
|
||||
tim->callback = mp_const_none;
|
||||
__HAL_TIM_DISABLE_IT(&tim->tim, irq_mask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user