95
95
// The USB_FS_WAKUP event is a direct type and there is no support for it.
96
96
#define EXTI_Mode_Interrupt offsetof(EXTI_TypeDef, IMR1)
97
97
#define EXTI_Mode_Event offsetof(EXTI_TypeDef, EMR1)
98
+ #define EXTI_RTSR EXTI->RTSR1
99
+ #define EXTI_FTSR EXTI->FTSR1
98
100
#else
99
101
#define EXTI_Mode_Interrupt offsetof(EXTI_TypeDef, IMR)
100
102
#define EXTI_Mode_Event offsetof(EXTI_TypeDef, EMR)
103
+ #define EXTI_RTSR EXTI->RTSR
104
+ #define EXTI_FTSR EXTI->FTSR
101
105
#endif
102
106
103
107
#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 {
107
111
mp_int_t line ;
108
112
} extint_obj_t ;
109
113
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 ];
111
119
112
120
#if !defined(ETH )
113
121
#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
187
195
EXTI_Mode_Interrupt : EXTI_Mode_Event ;
188
196
189
197
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 );
190
200
191
201
mp_hal_gpio_clock_enable (pin -> gpio );
192
202
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
205
215
return v_line ;
206
216
}
207
217
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
+
208
276
void extint_enable (uint line ) {
209
277
if (line >= EXTI_NUM_VECTORS ) {
210
278
return ;
@@ -411,13 +479,19 @@ void Handle_EXTI_Irq(uint32_t line) {
411
479
if (line < EXTI_NUM_VECTORS ) {
412
480
mp_obj_t * cb = & MP_STATE_PORT (pyb_extint_callback )[line ];
413
481
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
+
414
488
mp_sched_lock ();
415
489
// When executing code within a handler we must lock the GC to prevent
416
490
// any memory allocations. We must also catch any exceptions.
417
491
gc_lock ();
418
492
nlr_buf_t nlr ;
419
493
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 ] );
421
495
nlr_pop ();
422
496
} else {
423
497
// Uncaught exception; disable the callback so it doesn't run again.
0 commit comments