stmhal: Add initial implementation of Pin.irq() method.
This method follows the new HW API and allows to set a hard or soft IRQ callback when a Pin has a level change. It still remains to make this method return a IRQ object.
This commit is contained in:
parent
e269cabe3e
commit
4abe3731e3
@ -95,9 +95,13 @@
|
|||||||
// The USB_FS_WAKUP event is a direct type and there is no support for it.
|
// The USB_FS_WAKUP event is a direct type and there is no support for it.
|
||||||
#define EXTI_Mode_Interrupt offsetof(EXTI_TypeDef, IMR1)
|
#define EXTI_Mode_Interrupt offsetof(EXTI_TypeDef, IMR1)
|
||||||
#define EXTI_Mode_Event offsetof(EXTI_TypeDef, EMR1)
|
#define EXTI_Mode_Event offsetof(EXTI_TypeDef, EMR1)
|
||||||
|
#define EXTI_RTSR EXTI->RTSR1
|
||||||
|
#define EXTI_FTSR EXTI->FTSR1
|
||||||
#else
|
#else
|
||||||
#define EXTI_Mode_Interrupt offsetof(EXTI_TypeDef, IMR)
|
#define EXTI_Mode_Interrupt offsetof(EXTI_TypeDef, IMR)
|
||||||
#define EXTI_Mode_Event offsetof(EXTI_TypeDef, EMR)
|
#define EXTI_Mode_Event offsetof(EXTI_TypeDef, EMR)
|
||||||
|
#define EXTI_RTSR EXTI->RTSR
|
||||||
|
#define EXTI_FTSR EXTI->FTSR
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define EXTI_SWIER_BB(line) (*(__IO uint32_t *)(PERIPH_BB_BASE + ((EXTI_OFFSET + offsetof(EXTI_TypeDef, SWIER)) * 32) + ((line) * 4)))
|
#define EXTI_SWIER_BB(line) (*(__IO uint32_t *)(PERIPH_BB_BASE + ((EXTI_OFFSET + offsetof(EXTI_TypeDef, SWIER)) * 32) + ((line) * 4)))
|
||||||
@ -107,7 +111,11 @@ typedef struct {
|
|||||||
mp_int_t line;
|
mp_int_t line;
|
||||||
} extint_obj_t;
|
} extint_obj_t;
|
||||||
|
|
||||||
STATIC uint32_t pyb_extint_mode[EXTI_NUM_VECTORS];
|
STATIC uint8_t pyb_extint_mode[EXTI_NUM_VECTORS];
|
||||||
|
STATIC bool pyb_extint_hard_irq[EXTI_NUM_VECTORS];
|
||||||
|
|
||||||
|
// The callback arg is a small-int or a ROM Pin object, so no need to scan by GC
|
||||||
|
STATIC mp_obj_t pyb_extint_callback_arg[EXTI_NUM_VECTORS];
|
||||||
|
|
||||||
#if !defined(ETH)
|
#if !defined(ETH)
|
||||||
#define ETH_WKUP_IRQn 62 // Some MCUs don't have ETH, but we want a value to put in our table
|
#define ETH_WKUP_IRQn 62 // Some MCUs don't have ETH, but we want a value to put in our table
|
||||||
@ -187,6 +195,8 @@ uint extint_register(mp_obj_t pin_obj, uint32_t mode, uint32_t pull, mp_obj_t ca
|
|||||||
EXTI_Mode_Interrupt : EXTI_Mode_Event;
|
EXTI_Mode_Interrupt : EXTI_Mode_Event;
|
||||||
|
|
||||||
if (*cb != mp_const_none) {
|
if (*cb != mp_const_none) {
|
||||||
|
pyb_extint_hard_irq[v_line] = true;
|
||||||
|
pyb_extint_callback_arg[v_line] = MP_OBJ_NEW_SMALL_INT(v_line);
|
||||||
|
|
||||||
mp_hal_gpio_clock_enable(pin->gpio);
|
mp_hal_gpio_clock_enable(pin->gpio);
|
||||||
GPIO_InitTypeDef exti;
|
GPIO_InitTypeDef exti;
|
||||||
@ -205,6 +215,64 @@ uint extint_register(mp_obj_t pin_obj, uint32_t mode, uint32_t pull, mp_obj_t ca
|
|||||||
return v_line;
|
return v_line;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This function is intended to be used by the Pin.irq() method
|
||||||
|
void extint_register_pin(const pin_obj_t *pin, uint32_t mode, bool hard_irq, mp_obj_t callback_obj) {
|
||||||
|
uint32_t line = pin->pin;
|
||||||
|
|
||||||
|
// Check if the ExtInt line is already in use by another Pin/ExtInt
|
||||||
|
mp_obj_t *cb = &MP_STATE_PORT(pyb_extint_callback)[line];
|
||||||
|
if (*cb != mp_const_none && MP_OBJ_FROM_PTR(pin) != pyb_extint_callback_arg[line]) {
|
||||||
|
if (MP_OBJ_IS_SMALL_INT(pyb_extint_callback_arg[line])) {
|
||||||
|
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
|
||||||
|
"ExtInt vector %d is already in use", line));
|
||||||
|
} else {
|
||||||
|
const pin_obj_t *other_pin = (const pin_obj_t*)pyb_extint_callback_arg[line];
|
||||||
|
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
|
||||||
|
"IRQ resource already taken by Pin('%q')", other_pin->name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extint_disable(line);
|
||||||
|
|
||||||
|
*cb = callback_obj;
|
||||||
|
pyb_extint_mode[line] = (mode & 0x00010000) ? // GPIO_MODE_IT == 0x00010000
|
||||||
|
EXTI_Mode_Interrupt : EXTI_Mode_Event;
|
||||||
|
|
||||||
|
if (*cb != mp_const_none) {
|
||||||
|
// Configure and enable the callback
|
||||||
|
|
||||||
|
pyb_extint_hard_irq[line] = hard_irq;
|
||||||
|
pyb_extint_callback_arg[line] = MP_OBJ_FROM_PTR(pin);
|
||||||
|
|
||||||
|
// Route the GPIO to EXTI
|
||||||
|
__HAL_RCC_SYSCFG_CLK_ENABLE();
|
||||||
|
SYSCFG->EXTICR[line >> 2] =
|
||||||
|
(SYSCFG->EXTICR[line >> 2] & ~(0x0f << (4 * (line & 0x03))))
|
||||||
|
| ((uint32_t)(GPIO_GET_INDEX(pin->gpio)) << (4 * (line & 0x03)));
|
||||||
|
|
||||||
|
// Enable or disable the rising detector
|
||||||
|
if ((mode & GPIO_MODE_IT_RISING) == GPIO_MODE_IT_RISING) {
|
||||||
|
EXTI_RTSR |= 1 << line;
|
||||||
|
} else {
|
||||||
|
EXTI_RTSR &= ~(1 << line);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable or disable the falling detector
|
||||||
|
if ((mode & GPIO_MODE_IT_FALLING) == GPIO_MODE_IT_FALLING) {
|
||||||
|
EXTI_FTSR |= 1 << line;
|
||||||
|
} else {
|
||||||
|
EXTI_FTSR &= ~(1 << line);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure the NVIC
|
||||||
|
HAL_NVIC_SetPriority(nvic_irq_channel[line], IRQ_PRI_EXTINT, IRQ_SUBPRI_EXTINT);
|
||||||
|
HAL_NVIC_EnableIRQ(nvic_irq_channel[line]);
|
||||||
|
|
||||||
|
// Enable the interrupt
|
||||||
|
extint_enable(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void extint_enable(uint line) {
|
void extint_enable(uint line) {
|
||||||
if (line >= EXTI_NUM_VECTORS) {
|
if (line >= EXTI_NUM_VECTORS) {
|
||||||
return;
|
return;
|
||||||
@ -411,13 +479,19 @@ void Handle_EXTI_Irq(uint32_t line) {
|
|||||||
if (line < EXTI_NUM_VECTORS) {
|
if (line < EXTI_NUM_VECTORS) {
|
||||||
mp_obj_t *cb = &MP_STATE_PORT(pyb_extint_callback)[line];
|
mp_obj_t *cb = &MP_STATE_PORT(pyb_extint_callback)[line];
|
||||||
if (*cb != mp_const_none) {
|
if (*cb != mp_const_none) {
|
||||||
|
// If it's a soft IRQ handler then just schedule callback for later
|
||||||
|
if (!pyb_extint_hard_irq[line]) {
|
||||||
|
mp_sched_schedule(*cb, pyb_extint_callback_arg[line]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mp_sched_lock();
|
mp_sched_lock();
|
||||||
// When executing code within a handler we must lock the GC to prevent
|
// When executing code within a handler we must lock the GC to prevent
|
||||||
// any memory allocations. We must also catch any exceptions.
|
// any memory allocations. We must also catch any exceptions.
|
||||||
gc_lock();
|
gc_lock();
|
||||||
nlr_buf_t nlr;
|
nlr_buf_t nlr;
|
||||||
if (nlr_push(&nlr) == 0) {
|
if (nlr_push(&nlr) == 0) {
|
||||||
mp_call_function_1(*cb, MP_OBJ_NEW_SMALL_INT(line));
|
mp_call_function_1(*cb, pyb_extint_callback_arg[line]);
|
||||||
nlr_pop();
|
nlr_pop();
|
||||||
} else {
|
} else {
|
||||||
// Uncaught exception; disable the callback so it doesn't run again.
|
// Uncaught exception; disable the callback so it doesn't run again.
|
||||||
|
@ -52,6 +52,7 @@
|
|||||||
void extint_init0(void);
|
void extint_init0(void);
|
||||||
|
|
||||||
uint extint_register(mp_obj_t pin_obj, uint32_t mode, uint32_t pull, mp_obj_t callback_obj, bool override_callback_obj);
|
uint extint_register(mp_obj_t pin_obj, uint32_t mode, uint32_t pull, mp_obj_t callback_obj, bool override_callback_obj);
|
||||||
|
void extint_register_pin(const pin_obj_t *pin, uint32_t mode, bool hard_irq, mp_obj_t callback_obj);
|
||||||
|
|
||||||
void extint_enable(uint line);
|
void extint_enable(uint line);
|
||||||
void extint_disable(uint line);
|
void extint_disable(uint line);
|
||||||
|
28
stmhal/pin.c
28
stmhal/pin.c
@ -33,6 +33,7 @@
|
|||||||
#include "py/mphal.h"
|
#include "py/mphal.h"
|
||||||
#include "extmod/virtpin.h"
|
#include "extmod/virtpin.h"
|
||||||
#include "pin.h"
|
#include "pin.h"
|
||||||
|
#include "extint.h"
|
||||||
|
|
||||||
/// \moduleref pyb
|
/// \moduleref pyb
|
||||||
/// \class Pin - control I/O pins
|
/// \class Pin - control I/O pins
|
||||||
@ -414,6 +415,29 @@ STATIC mp_obj_t pin_on(mp_obj_t self_in) {
|
|||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_on_obj, pin_on);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_on_obj, pin_on);
|
||||||
|
|
||||||
|
// pin.irq(handler=None, trigger=IRQ_FALLING|IRQ_RISING, hard=False)
|
||||||
|
STATIC mp_obj_t pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||||
|
enum { ARG_handler, ARG_trigger, ARG_hard };
|
||||||
|
static const mp_arg_t allowed_args[] = {
|
||||||
|
{ MP_QSTR_handler, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||||
|
{ MP_QSTR_trigger, MP_ARG_INT, {.u_int = GPIO_MODE_IT_RISING | GPIO_MODE_IT_FALLING} },
|
||||||
|
{ MP_QSTR_hard, MP_ARG_BOOL, {.u_bool = false} },
|
||||||
|
};
|
||||||
|
pin_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
|
||||||
|
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||||
|
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||||
|
|
||||||
|
if (n_args > 1 || kw_args->used != 0) {
|
||||||
|
// configure irq
|
||||||
|
extint_register_pin(self, args[ARG_trigger].u_int,
|
||||||
|
args[ARG_hard].u_bool, args[ARG_handler].u_obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO should return an IRQ object
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pin_irq_obj, 1, pin_irq);
|
||||||
|
|
||||||
/// \method name()
|
/// \method name()
|
||||||
/// Get the pin name.
|
/// Get the pin name.
|
||||||
STATIC mp_obj_t pin_name(mp_obj_t self_in) {
|
STATIC mp_obj_t pin_name(mp_obj_t self_in) {
|
||||||
@ -498,6 +522,8 @@ STATIC const mp_rom_map_elem_t pin_locals_dict_table[] = {
|
|||||||
{ MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&pin_value_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&pin_value_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&pin_off_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&pin_off_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&pin_on_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&pin_on_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&pin_irq_obj) },
|
||||||
|
|
||||||
// Legacy names as used by pyb.Pin
|
// Legacy names as used by pyb.Pin
|
||||||
{ MP_ROM_QSTR(MP_QSTR_low), MP_ROM_PTR(&pin_off_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_low), MP_ROM_PTR(&pin_off_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_high), MP_ROM_PTR(&pin_on_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_high), MP_ROM_PTR(&pin_on_obj) },
|
||||||
@ -529,6 +555,8 @@ STATIC const mp_rom_map_elem_t pin_locals_dict_table[] = {
|
|||||||
{ MP_ROM_QSTR(MP_QSTR_ANALOG), MP_ROM_INT(GPIO_MODE_ANALOG) },
|
{ MP_ROM_QSTR(MP_QSTR_ANALOG), MP_ROM_INT(GPIO_MODE_ANALOG) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_PULL_UP), MP_ROM_INT(GPIO_PULLUP) },
|
{ MP_ROM_QSTR(MP_QSTR_PULL_UP), MP_ROM_INT(GPIO_PULLUP) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(GPIO_PULLDOWN) },
|
{ MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(GPIO_PULLDOWN) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(GPIO_MODE_IT_RISING) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(GPIO_MODE_IT_FALLING) },
|
||||||
|
|
||||||
// legacy class constants
|
// legacy class constants
|
||||||
{ MP_ROM_QSTR(MP_QSTR_OUT_PP), MP_ROM_INT(GPIO_MODE_OUTPUT_PP) },
|
{ MP_ROM_QSTR(MP_QSTR_OUT_PP), MP_ROM_INT(GPIO_MODE_OUTPUT_PP) },
|
||||||
|
Loading…
Reference in New Issue
Block a user