3030#include "extmod/virtpin.h"
3131#include "shared/runtime/mpirq.h"
3232
33+ #ifndef MACHINE_PIN_NUM_VECTORS
34+ #define MACHINE_PIN_NUM_PORT_IO (8)
35+ #define MACHINE_PIN_NUM_VECTORS (16 * MACHINE_PIN_NUM_PORT_IO)
36+ #endif
37+
38+ typedef struct _machine_pin_irq_obj_t {
39+ mp_irq_obj_t base ;
40+ uint32_t flags ;
41+ uint32_t trigger ;
42+ IRQn_Type irq_num ;
43+ bool reserved ; // for use by other drivers
44+ } machine_pin_irq_obj_t ;
45+
46+ #define MACHINE_PIN_IRQ_INDEX (port , pin ) \
47+ ((port) * MACHINE_PIN_NUM_PORT_IO + (pin))
48+
49+ #define MACHINE_PIN_IRQ_OBJECT (port , pin ) \
50+ (MP_STATE_PORT(machine_pin_irq_obj[MACHINE_PIN_IRQ_INDEX((port), (pin))]))
51+
52+ // Defines a single GPIO IRQ handler
53+ #define DEFINE_GPIO_IRQ_HANDLER (pname , port , pin ) \
54+ void pname##_IRQ##pin##Handler(void) { \
55+ machine_pin_irq_obj_t *irq = MACHINE_PIN_IRQ_OBJECT(port, pin); \
56+ machine_pin_obj_t *self = MP_OBJ_TO_PTR(irq->base.parent); \
57+ gpio_interrupt_eoi(self->gpio, pin); \
58+ irq->flags = irq->trigger; \
59+ mp_irq_handler(&irq->base); \
60+ }
61+
62+ // Defines all 8 pin IRQ handlers for a port
63+ #define DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT (gpio , port ) \
64+ DEFINE_GPIO_IRQ_HANDLER(gpio, port, 0) \
65+ DEFINE_GPIO_IRQ_HANDLER(gpio, port, 1) \
66+ DEFINE_GPIO_IRQ_HANDLER(gpio, port, 2) \
67+ DEFINE_GPIO_IRQ_HANDLER(gpio, port, 3) \
68+ DEFINE_GPIO_IRQ_HANDLER(gpio, port, 4) \
69+ DEFINE_GPIO_IRQ_HANDLER(gpio, port, 5) \
70+ DEFINE_GPIO_IRQ_HANDLER(gpio, port, 6) \
71+ DEFINE_GPIO_IRQ_HANDLER(gpio, port, 7)
72+
73+ // Generate handlers for GPIO ports 0 to 14 + LPGPIO
74+ DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT (GPIO0 , 0 )
75+ DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT (GPIO1 , 1 )
76+ DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT (GPIO2 , 2 )
77+ DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT (GPIO3 , 3 )
78+ DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT (GPIO4 , 4 )
79+ DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT (GPIO5 , 5 )
80+ DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT (GPIO6 , 6 )
81+ DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT (GPIO7 , 7 )
82+ DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT (GPIO8 , 8 )
83+
84+ DEFINE_GPIO_IRQ_HANDLER (GPIO9 , 9 , 0 )
85+ DEFINE_GPIO_IRQ_HANDLER (GPIO9 , 9 , 1 )
86+ DEFINE_GPIO_IRQ_HANDLER (GPIO9 , 9 , 2 )
87+ DEFINE_GPIO_IRQ_HANDLER (GPIO9 , 9 , 3 )
88+ DEFINE_GPIO_IRQ_HANDLER (GPIO9 , 9 , 4 )
89+ DEFINE_GPIO_IRQ_HANDLER (GPIO9 , 9 , 5 )
90+ // DEFINE_GPIO_IRQ_HANDLER(GPIO9, 9, 6) // Reserved for WiFi
91+ DEFINE_GPIO_IRQ_HANDLER (GPIO9 , 9 , 7 )
92+
93+ DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT (GPIO10 , 10 )
94+ DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT (GPIO11 , 11 )
95+ DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT (GPIO12 , 12 )
96+ DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT (GPIO13 , 13 )
97+ DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT (GPIO14 , 14 )
98+ DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT (LPGPIO , 15 )
99+
33100extern const mp_obj_dict_t machine_pin_cpu_pins_locals_dict ;
34101extern const mp_obj_dict_t machine_pin_board_pins_locals_dict ;
102+ static const mp_irq_methods_t machine_pin_irq_methods ;
35103
36104static const machine_pin_obj_t * machine_pin_find_named (const mp_obj_dict_t * named_pins , mp_obj_t name ) {
37105 const mp_map_t * named_map = & named_pins -> map ;
@@ -171,6 +239,7 @@ mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw,
171239 mp_map_init_fixed_table (& kw_args , n_kw , args + n_args );
172240 machine_pin_obj_init_helper (self , n_args - 1 , args + 1 , & kw_args );
173241 }
242+
174243 return MP_OBJ_FROM_PTR (self );
175244}
176245
@@ -225,6 +294,129 @@ static mp_obj_t machine_pin_toggle(mp_obj_t self_in) {
225294}
226295static MP_DEFINE_CONST_FUN_OBJ_1 (machine_pin_toggle_obj , machine_pin_toggle ) ;
227296
297+ static mp_uint_t machine_pin_irq_trigger (mp_obj_t self_in , mp_uint_t trigger ) {
298+ machine_pin_obj_t * self = MP_OBJ_TO_PTR (self_in );
299+ machine_pin_irq_obj_t * irq = MACHINE_PIN_IRQ_OBJECT (self -> port , self -> pin );
300+
301+ irq -> flags = 0 ;
302+ irq -> trigger = trigger ;
303+
304+ // Disable IRQs.
305+ gpio_disable_interrupt (self -> gpio , self -> pin );
306+ gpio_mask_interrupt (self -> gpio , self -> pin );
307+
308+ NVIC_ClearPendingIRQ (irq -> irq_num );
309+ NVIC_DisableIRQ (irq -> irq_num );
310+
311+ // Return if the trigger is disabled.
312+ if (trigger == 0 ) {
313+ return 0 ;
314+ }
315+
316+ // Clear and enable GPIO IRQ.
317+ gpio_enable_interrupt (self -> gpio , self -> pin );
318+ gpio_unmask_interrupt (self -> gpio , self -> pin );
319+
320+ // Clear GPIO config.
321+ self -> gpio -> GPIO_INT_BOTHEDGE &= ~(1 << self -> pin );
322+ self -> gpio -> GPIO_INT_POLARITY &= ~(1 << self -> pin );
323+ self -> gpio -> GPIO_INTTYPE_LEVEL &= ~(1 << self -> pin );
324+
325+ // Configure GPIO IRQ trigger
326+ if (trigger == MP_HAL_PIN_TRIGGER_FALL ) {
327+ gpio_interrupt_set_edge_trigger (self -> gpio , self -> pin );
328+ gpio_interrupt_set_polarity_low (self -> gpio , self -> pin );
329+ } else if (trigger == MP_HAL_PIN_TRIGGER_RISE ) {
330+ gpio_interrupt_set_edge_trigger (self -> gpio , self -> pin );
331+ gpio_interrupt_set_polarity_high (self -> gpio , self -> pin );
332+ } else if (trigger == (MP_HAL_PIN_TRIGGER_FALL | MP_HAL_PIN_TRIGGER_RISE )) {
333+ gpio_interrupt_set_both_edge_trigger (self -> gpio , self -> pin );
334+ } else {
335+ mp_raise_ValueError (MP_ERROR_TEXT ("Invalid IRQ trigger" ));
336+ }
337+
338+ // Clear GPIO IRQ (must be done after configuring trigger)
339+ gpio_interrupt_eoi (self -> gpio , self -> pin );
340+
341+ // Clear and enable NVIC GPIO IRQ.
342+ NVIC_ClearPendingIRQ (irq -> irq_num );
343+ NVIC_SetPriority (irq -> irq_num , IRQ_PRI_GPIO );
344+ NVIC_EnableIRQ (irq -> irq_num );
345+
346+ return 0 ;
347+ }
348+
349+ static mp_uint_t machine_pin_irq_info (mp_obj_t self_in , mp_uint_t info_type ) {
350+ machine_pin_obj_t * self = MP_OBJ_TO_PTR (self_in );
351+ machine_pin_irq_obj_t * irq = MACHINE_PIN_IRQ_OBJECT (self -> port , self -> pin );
352+
353+ if (info_type == MP_IRQ_INFO_FLAGS ) {
354+ return irq -> flags ;
355+ } else if (info_type == MP_IRQ_INFO_TRIGGERS ) {
356+ return irq -> trigger ;
357+ }
358+ return 0 ;
359+ }
360+
361+ static const mp_irq_methods_t machine_pin_irq_methods = {
362+ .trigger = machine_pin_irq_trigger ,
363+ .info = machine_pin_irq_info ,
364+ };
365+
366+ // pin.irq(handler=None, trigger=IRQ_FALLING|IRQ_RISING, hard=False)
367+ static mp_obj_t machine_pin_irq (size_t n_args , const mp_obj_t * pos_args , mp_map_t * kw_args ) {
368+ enum { ARG_handler , ARG_trigger , ARG_hard };
369+ static const mp_arg_t allowed_args [] = {
370+ { MP_QSTR_handler , MP_ARG_OBJ , {.u_rom_obj = MP_ROM_NONE } },
371+ { MP_QSTR_trigger , MP_ARG_INT , {.u_int = MP_HAL_PIN_TRIGGER_FALL | MP_HAL_PIN_TRIGGER_RISE } },
372+ { MP_QSTR_hard , MP_ARG_BOOL , {.u_bool = false} },
373+ };
374+
375+ machine_pin_obj_t * self = MP_OBJ_TO_PTR (pos_args [0 ]);
376+ mp_arg_val_t args [MP_ARRAY_SIZE (allowed_args )];
377+ mp_arg_parse_all (n_args - 1 , pos_args + 1 , kw_args , MP_ARRAY_SIZE (allowed_args ), allowed_args , args );
378+
379+ machine_pin_irq_obj_t * irq = MACHINE_PIN_IRQ_OBJECT (self -> port , self -> pin );
380+
381+ // Allocate a new IRQ object if it doesn't exist.
382+ if (irq == NULL ) {
383+ irq = m_new_obj (machine_pin_irq_obj_t );
384+ uint32_t idx = MACHINE_PIN_IRQ_INDEX (self -> port , self -> pin );
385+
386+ irq -> base .base .type = & mp_irq_type ;
387+ irq -> base .methods = (mp_irq_methods_t * )& machine_pin_irq_methods ;
388+ irq -> base .parent = MP_OBJ_FROM_PTR (self );
389+ irq -> base .handler = mp_const_none ;
390+ irq -> base .ishard = false;
391+ irq -> reserved = false;
392+ irq -> irq_num = (self -> port < 15 ) ? (GPIO0_IRQ0_IRQn + idx ) : (LPGPIO_IRQ0_IRQn + self -> pin );
393+ MP_STATE_PORT (machine_pin_irq_obj [idx ]) = irq ;
394+ }
395+
396+ if (n_args > 1 || kw_args -> used != 0 ) {
397+ if (irq -> reserved ) {
398+ mp_raise_msg (& mp_type_ValueError , MP_ERROR_TEXT ("Pin IRQ is reserved" ));
399+ }
400+ irq -> base .handler = args [ARG_handler ].u_obj ;
401+ irq -> base .ishard = args [ARG_hard ].u_bool ;
402+ machine_pin_irq_trigger (self , args [ARG_trigger ].u_int );
403+ }
404+
405+ return MP_OBJ_FROM_PTR (irq );
406+ }
407+ static MP_DEFINE_CONST_FUN_OBJ_KW (machine_pin_irq_obj , 1 , machine_pin_irq ) ;
408+
409+ void machine_pin_irq_deinit (void ) {
410+ for (size_t i = 0 ; i < MP_ARRAY_SIZE (MP_STATE_PORT (machine_pin_irq_obj )); i ++ ) {
411+ machine_pin_irq_obj_t * irq = MP_STATE_PORT (machine_pin_irq_obj [i ]);
412+ if (irq != NULL ) {
413+ machine_pin_obj_t * self = MP_OBJ_TO_PTR (irq -> base .parent );
414+ machine_pin_irq_trigger (self , 0 );
415+ MP_STATE_PORT (machine_pin_irq_obj [i ]) = NULL ;
416+ }
417+ }
418+ }
419+
228420static MP_DEFINE_CONST_OBJ_TYPE (
229421 pin_cpu_pins_obj_type ,
230422 MP_QSTR_cpu ,
@@ -248,6 +440,7 @@ static const mp_rom_map_elem_t machine_pin_locals_dict_table[] = {
248440 { MP_ROM_QSTR (MP_QSTR_off ), MP_ROM_PTR (& machine_pin_low_obj ) },
249441 { MP_ROM_QSTR (MP_QSTR_on ), MP_ROM_PTR (& machine_pin_high_obj ) },
250442 { MP_ROM_QSTR (MP_QSTR_toggle ), MP_ROM_PTR (& machine_pin_toggle_obj ) },
443+ { MP_ROM_QSTR (MP_QSTR_irq ), MP_ROM_PTR (& machine_pin_irq_obj ) },
251444
252445 // class attributes
253446 { MP_ROM_QSTR (MP_QSTR_board ), MP_ROM_PTR (& pin_board_pins_obj_type ) },
@@ -259,6 +452,8 @@ static const mp_rom_map_elem_t machine_pin_locals_dict_table[] = {
259452 { MP_ROM_QSTR (MP_QSTR_OPEN_DRAIN ), MP_ROM_INT (MP_HAL_PIN_MODE_OPEN_DRAIN ) },
260453 { MP_ROM_QSTR (MP_QSTR_PULL_UP ), MP_ROM_INT (MP_HAL_PIN_PULL_UP ) },
261454 { MP_ROM_QSTR (MP_QSTR_PULL_DOWN ), MP_ROM_INT (MP_HAL_PIN_PULL_DOWN ) },
455+ { MP_ROM_QSTR (MP_QSTR_IRQ_FALLING ), MP_ROM_INT (MP_HAL_PIN_TRIGGER_FALL ) },
456+ { MP_ROM_QSTR (MP_QSTR_IRQ_RISING ), MP_ROM_INT (MP_HAL_PIN_TRIGGER_RISE ) },
262457};
263458static MP_DEFINE_CONST_DICT (machine_pin_locals_dict , machine_pin_locals_dict_table ) ;
264459
@@ -296,3 +491,5 @@ MP_DEFINE_CONST_OBJ_TYPE(
296491mp_hal_pin_obj_t mp_hal_get_pin_obj (mp_obj_t obj ) {
297492 return machine_pin_find (obj );
298493}
494+
495+ MP_REGISTER_ROOT_POINTER (void * machine_pin_irq_obj [MACHINE_PIN_NUM_VECTORS ]);
0 commit comments