Skip to content

Commit 4abe373

Browse files
committed
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.
1 parent e269cab commit 4abe373

File tree

3 files changed

+105
-2
lines changed

3 files changed

+105
-2
lines changed

stmhal/extint.c

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,13 @@
9595
// The USB_FS_WAKUP event is a direct type and there is no support for it.
9696
#define EXTI_Mode_Interrupt offsetof(EXTI_TypeDef, IMR1)
9797
#define EXTI_Mode_Event offsetof(EXTI_TypeDef, EMR1)
98+
#define EXTI_RTSR EXTI->RTSR1
99+
#define EXTI_FTSR EXTI->FTSR1
98100
#else
99101
#define EXTI_Mode_Interrupt offsetof(EXTI_TypeDef, IMR)
100102
#define EXTI_Mode_Event offsetof(EXTI_TypeDef, EMR)
103+
#define EXTI_RTSR EXTI->RTSR
104+
#define EXTI_FTSR EXTI->FTSR
101105
#endif
102106

103107
#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 {
107111
mp_int_t line;
108112
} extint_obj_t;
109113

110-
STATIC uint32_t pyb_extint_mode[EXTI_NUM_VECTORS];
114+
STATIC uint8_t pyb_extint_mode[EXTI_NUM_VECTORS];
115+
STATIC bool pyb_extint_hard_irq[EXTI_NUM_VECTORS];
116+
117+
// The callback arg is a small-int or a ROM Pin object, so no need to scan by GC
118+
STATIC mp_obj_t pyb_extint_callback_arg[EXTI_NUM_VECTORS];
111119

112120
#if !defined(ETH)
113121
#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
187195
EXTI_Mode_Interrupt : EXTI_Mode_Event;
188196

189197
if (*cb != mp_const_none) {
198+
pyb_extint_hard_irq[v_line] = true;
199+
pyb_extint_callback_arg[v_line] = MP_OBJ_NEW_SMALL_INT(v_line);
190200

191201
mp_hal_gpio_clock_enable(pin->gpio);
192202
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
205215
return v_line;
206216
}
207217

218+
// This function is intended to be used by the Pin.irq() method
219+
void extint_register_pin(const pin_obj_t *pin, uint32_t mode, bool hard_irq, mp_obj_t callback_obj) {
220+
uint32_t line = pin->pin;
221+
222+
// Check if the ExtInt line is already in use by another Pin/ExtInt
223+
mp_obj_t *cb = &MP_STATE_PORT(pyb_extint_callback)[line];
224+
if (*cb != mp_const_none && MP_OBJ_FROM_PTR(pin) != pyb_extint_callback_arg[line]) {
225+
if (MP_OBJ_IS_SMALL_INT(pyb_extint_callback_arg[line])) {
226+
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
227+
"ExtInt vector %d is already in use", line));
228+
} else {
229+
const pin_obj_t *other_pin = (const pin_obj_t*)pyb_extint_callback_arg[line];
230+
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
231+
"IRQ resource already taken by Pin('%q')", other_pin->name));
232+
}
233+
}
234+
235+
extint_disable(line);
236+
237+
*cb = callback_obj;
238+
pyb_extint_mode[line] = (mode & 0x00010000) ? // GPIO_MODE_IT == 0x00010000
239+
EXTI_Mode_Interrupt : EXTI_Mode_Event;
240+
241+
if (*cb != mp_const_none) {
242+
// Configure and enable the callback
243+
244+
pyb_extint_hard_irq[line] = hard_irq;
245+
pyb_extint_callback_arg[line] = MP_OBJ_FROM_PTR(pin);
246+
247+
// Route the GPIO to EXTI
248+
__HAL_RCC_SYSCFG_CLK_ENABLE();
249+
SYSCFG->EXTICR[line >> 2] =
250+
(SYSCFG->EXTICR[line >> 2] & ~(0x0f << (4 * (line & 0x03))))
251+
| ((uint32_t)(GPIO_GET_INDEX(pin->gpio)) << (4 * (line & 0x03)));
252+
253+
// Enable or disable the rising detector
254+
if ((mode & GPIO_MODE_IT_RISING) == GPIO_MODE_IT_RISING) {
255+
EXTI_RTSR |= 1 << line;
256+
} else {
257+
EXTI_RTSR &= ~(1 << line);
258+
}
259+
260+
// Enable or disable the falling detector
261+
if ((mode & GPIO_MODE_IT_FALLING) == GPIO_MODE_IT_FALLING) {
262+
EXTI_FTSR |= 1 << line;
263+
} else {
264+
EXTI_FTSR &= ~(1 << line);
265+
}
266+
267+
// Configure the NVIC
268+
HAL_NVIC_SetPriority(nvic_irq_channel[line], IRQ_PRI_EXTINT, IRQ_SUBPRI_EXTINT);
269+
HAL_NVIC_EnableIRQ(nvic_irq_channel[line]);
270+
271+
// Enable the interrupt
272+
extint_enable(line);
273+
}
274+
}
275+
208276
void extint_enable(uint line) {
209277
if (line >= EXTI_NUM_VECTORS) {
210278
return;
@@ -411,13 +479,19 @@ void Handle_EXTI_Irq(uint32_t line) {
411479
if (line < EXTI_NUM_VECTORS) {
412480
mp_obj_t *cb = &MP_STATE_PORT(pyb_extint_callback)[line];
413481
if (*cb != mp_const_none) {
482+
// If it's a soft IRQ handler then just schedule callback for later
483+
if (!pyb_extint_hard_irq[line]) {
484+
mp_sched_schedule(*cb, pyb_extint_callback_arg[line]);
485+
return;
486+
}
487+
414488
mp_sched_lock();
415489
// When executing code within a handler we must lock the GC to prevent
416490
// any memory allocations. We must also catch any exceptions.
417491
gc_lock();
418492
nlr_buf_t nlr;
419493
if (nlr_push(&nlr) == 0) {
420-
mp_call_function_1(*cb, MP_OBJ_NEW_SMALL_INT(line));
494+
mp_call_function_1(*cb, pyb_extint_callback_arg[line]);
421495
nlr_pop();
422496
} else {
423497
// Uncaught exception; disable the callback so it doesn't run again.

stmhal/extint.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
void extint_init0(void);
5353

5454
uint extint_register(mp_obj_t pin_obj, uint32_t mode, uint32_t pull, mp_obj_t callback_obj, bool override_callback_obj);
55+
void extint_register_pin(const pin_obj_t *pin, uint32_t mode, bool hard_irq, mp_obj_t callback_obj);
5556

5657
void extint_enable(uint line);
5758
void extint_disable(uint line);

stmhal/pin.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "py/mphal.h"
3434
#include "extmod/virtpin.h"
3535
#include "pin.h"
36+
#include "extint.h"
3637

3738
/// \moduleref pyb
3839
/// \class Pin - control I/O pins
@@ -414,6 +415,29 @@ STATIC mp_obj_t pin_on(mp_obj_t self_in) {
414415
}
415416
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_on_obj, pin_on);
416417

418+
// pin.irq(handler=None, trigger=IRQ_FALLING|IRQ_RISING, hard=False)
419+
STATIC mp_obj_t pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
420+
enum { ARG_handler, ARG_trigger, ARG_hard };
421+
static const mp_arg_t allowed_args[] = {
422+
{ MP_QSTR_handler, MP_ARG_OBJ, {.u_obj = mp_const_none} },
423+
{ MP_QSTR_trigger, MP_ARG_INT, {.u_int = GPIO_MODE_IT_RISING | GPIO_MODE_IT_FALLING} },
424+
{ MP_QSTR_hard, MP_ARG_BOOL, {.u_bool = false} },
425+
};
426+
pin_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
427+
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
428+
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
429+
430+
if (n_args > 1 || kw_args->used != 0) {
431+
// configure irq
432+
extint_register_pin(self, args[ARG_trigger].u_int,
433+
args[ARG_hard].u_bool, args[ARG_handler].u_obj);
434+
}
435+
436+
// TODO should return an IRQ object
437+
return mp_const_none;
438+
}
439+
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pin_irq_obj, 1, pin_irq);
440+
417441
/// \method name()
418442
/// Get the pin name.
419443
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[] = {
498522
{ MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&pin_value_obj) },
499523
{ MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&pin_off_obj) },
500524
{ MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&pin_on_obj) },
525+
{ MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&pin_irq_obj) },
526+
501527
// Legacy names as used by pyb.Pin
502528
{ MP_ROM_QSTR(MP_QSTR_low), MP_ROM_PTR(&pin_off_obj) },
503529
{ 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[] = {
529555
{ MP_ROM_QSTR(MP_QSTR_ANALOG), MP_ROM_INT(GPIO_MODE_ANALOG) },
530556
{ MP_ROM_QSTR(MP_QSTR_PULL_UP), MP_ROM_INT(GPIO_PULLUP) },
531557
{ MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(GPIO_PULLDOWN) },
558+
{ MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(GPIO_MODE_IT_RISING) },
559+
{ MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(GPIO_MODE_IT_FALLING) },
532560

533561
// legacy class constants
534562
{ MP_ROM_QSTR(MP_QSTR_OUT_PP), MP_ROM_INT(GPIO_MODE_OUTPUT_PP) },

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