1 /**
2 ******************************************************************************
3 * @file stm32u0xx_hal_exti.c
4 * @author MCD Application Team
5 * @brief EXTI HAL module driver.
6 * This file provides firmware functions to manage the following
7 * functionalities of the General Purpose Input/Output (EXTI) peripheral:
8 * + Initialization and de-initialization functions
9 * + IO operation functions
10 *
11 @verbatim
12 ==============================================================================
13 ##### EXTI Peripheral features #####
14 ==============================================================================
15 [..]
16 (+) Each Exti line can be configured within this driver.
17
18 (+) Exti line can be configured in 3 different modes
19 (++) Interrupt
20 (++) Event
21 (++) Both of them
22
23 (+) Configurable Exti lines can be configured with 3 different triggers
24 (++) Rising
25 (++) Falling
26 (++) Both of them
27
28 (+) When set in interrupt mode, configurable Exti lines have two diffenrents
29 interrupt pending registers which allow to distinguish which transition
30 occurs:
31 (++) Rising edge pending interrupt
32 (++) Falling
33
34 (+) Exti lines 0 to 15 are linked to gpio pin number 0 to 15. Gpio port can
35 be selected through multiplexer.
36
37 ##### How to use this driver #####
38 ==============================================================================
39 [..]
40
41 (#) Configure the EXTI line using HAL_EXTI_SetConfigLine().
42 (++) Choose the interrupt line number by setting "Line" member from
43 EXTI_ConfigTypeDef structure.
44 (++) Configure the interrupt and/or event mode using "Mode" member from
45 EXTI_ConfigTypeDef structure.
46 (++) For configurable lines, configure rising and/or falling trigger
47 "Trigger" member from EXTI_ConfigTypeDef structure.
48 (++) For Exti lines linked to gpio, choose gpio port using "GPIOSel"
49 member from GPIO_InitTypeDef structure.
50
51 (#) Get current Exti configuration of a dedicated line using
52 HAL_EXTI_GetConfigLine().
53 (++) Provide exiting handle as parameter.
54 (++) Provide pointer on EXTI_ConfigTypeDef structure as second parameter.
55
56 (#) Clear Exti configuration of a dedicated line using HAL_EXTI_GetConfigLine().
57 (++) Provide exiting handle as parameter.
58
59 (#) Register callback to treat Exti interrupts using HAL_EXTI_RegisterCallback().
60 (++) Provide exiting handle as first parameter.
61 (++) Provide which callback will be registered using one value from
62 EXTI_CallbackIDTypeDef.
63 (++) Provide callback function pointer.
64
65 (#) Get interrupt pending bit using HAL_EXTI_GetPending().
66
67 (#) Clear interrupt pending bit using HAL_EXTI_GetPending().
68
69 (#) Generate software interrupt using HAL_EXTI_GenerateSWI().
70
71 @endverbatim
72 ******************************************************************************
73 * @attention
74 *
75 * Copyright (c) 2023 STMicroelectronics.
76 * All rights reserved.
77 *
78 * This software is licensed under terms that can be found in the LICENSE file
79 * in the root directory of this software component.
80 * If no LICENSE file comes with this software, it is provided AS-IS.
81 *
82 ******************************************************************************
83 */
84
85 /* Includes ------------------------------------------------------------------*/
86 #include "stm32u0xx_hal.h"
87
88 /** @addtogroup STM32U0xx_HAL_Driver
89 * @{
90 */
91
92 /** @addtogroup EXTI
93 * @{
94 */
95
96 #ifdef HAL_EXTI_MODULE_ENABLED
97
98 /* Private typedef -----------------------------------------------------------*/
99 /* Private defines ------------------------------------------------------------*/
100 /** @defgroup EXTI_Private_Constants EXTI Private Constants
101 * @{
102 */
103 #define EXTI_MODE_OFFSET 0x04U /* byte offset between CPU IMR/EMR registers */
104 #define EXTI_CONFIG_OFFSET 0x08U /* byte offset between Rising/Falling configuration registers */
105 /**
106 * @}
107 */
108
109 /* Private macros ------------------------------------------------------------*/
110 /* Private variables ---------------------------------------------------------*/
111 /* Private function prototypes -----------------------------------------------*/
112 /* Exported functions --------------------------------------------------------*/
113
114 /** @addtogroup EXTI_Exported_Functions
115 * @{
116 */
117
118 /** @addtogroup EXTI_Exported_Functions_Group1
119 * @brief Configuration functions
120 *
121 @verbatim
122 ===============================================================================
123 ##### Configuration functions #####
124 ===============================================================================
125
126 @endverbatim
127 * @{
128 */
129
130 /**
131 * @brief Set configuration of a dedicated Exti line.
132 * @param hexti Exti handle.
133 * @param pExtiConfig Pointer on EXTI configuration to be set.
134 * @retval HAL Status.
135 */
HAL_EXTI_SetConfigLine(EXTI_HandleTypeDef * hexti,EXTI_ConfigTypeDef * pExtiConfig)136 HAL_StatusTypeDef HAL_EXTI_SetConfigLine(EXTI_HandleTypeDef *hexti, EXTI_ConfigTypeDef *pExtiConfig)
137 {
138 uint32_t *regaddr;
139 uint32_t regval;
140 uint32_t linepos;
141 uint32_t maskline;
142 uint32_t offset;
143
144 /* Check null pointer */
145 if ((hexti == NULL) || (pExtiConfig == NULL))
146 {
147 return HAL_ERROR;
148 }
149
150 /* Check the parameters */
151 assert_param(IS_EXTI_LINE(pExtiConfig->Line));
152 assert_param(IS_EXTI_MODE(pExtiConfig->Mode));
153
154 /* Assign line number to handle */
155 hexti->Line = pExtiConfig->Line;
156
157 /* compute line register offset and line mask */
158 offset = ((pExtiConfig->Line & EXTI_REG_MASK) >> EXTI_REG_SHIFT);
159 linepos = (pExtiConfig->Line & EXTI_PIN_MASK);
160 maskline = (1UL << linepos);
161
162 /* Configure triggers for configurable lines */
163 if ((pExtiConfig->Line & EXTI_CONFIG) != 0x00U)
164 {
165 assert_param(IS_EXTI_TRIGGER(pExtiConfig->Trigger));
166
167 /* Configure rising trigger */
168 regaddr = (uint32_t *)(&EXTI->RTSR1 + (EXTI_CONFIG_OFFSET * offset));
169 regval = *regaddr;
170
171 /* Mask or set line */
172 if ((pExtiConfig->Trigger & EXTI_TRIGGER_RISING) != 0x00U)
173 {
174 regval |= maskline;
175 }
176 else
177 {
178 regval &= ~maskline;
179 }
180
181 /* Store rising trigger mode */
182 *regaddr = regval;
183
184 /* Configure falling trigger */
185 regaddr = (uint32_t *)(&EXTI->FTSR1 + (EXTI_CONFIG_OFFSET * offset));
186 regval = *regaddr;
187
188 /* Mask or set line */
189 if ((pExtiConfig->Trigger & EXTI_TRIGGER_FALLING) != 0x00U)
190 {
191 regval |= maskline;
192 }
193 else
194 {
195 regval &= ~maskline;
196 }
197
198 /* Store falling trigger mode */
199 *regaddr = regval;
200
201 /* Configure gpio port selection in case of gpio exti line */
202 if ((pExtiConfig->Line & EXTI_GPIO) == EXTI_GPIO)
203 {
204 assert_param(IS_EXTI_GPIO_PORT(pExtiConfig->GPIOSel));
205 assert_param(IS_EXTI_GPIO_PIN(linepos));
206
207 regval = EXTI->EXTICR[linepos >> 2U];
208 regval &= ~(0xFFU << (8U * (linepos & 0x03U)));
209 regval |= (pExtiConfig->GPIOSel << (8U * (linepos & 0x03U)));
210 EXTI->EXTICR[linepos >> 2U] = regval;
211 }
212 }
213
214 /* Configure interrupt mode : read current mode */
215 regaddr = (uint32_t *)(&EXTI->IMR1 + (EXTI_MODE_OFFSET * offset));
216 regval = *regaddr;
217
218 /* Mask or set line */
219 if ((pExtiConfig->Mode & EXTI_MODE_INTERRUPT) != 0x00U)
220 {
221 regval |= maskline;
222 }
223 else
224 {
225 regval &= ~maskline;
226 }
227
228 /* Store interrupt mode */
229 *regaddr = regval;
230
231 /* Configure event mode : read current mode */
232 regaddr = (uint32_t *)(&EXTI->EMR1 + (EXTI_MODE_OFFSET * offset));
233 regval = *regaddr;
234
235 /* Mask or set line */
236 if ((pExtiConfig->Mode & EXTI_MODE_EVENT) != 0x00U)
237 {
238 regval |= maskline;
239 }
240 else
241 {
242 regval &= ~maskline;
243 }
244
245 /* Store event mode */
246 *regaddr = regval;
247
248 return HAL_OK;
249 }
250
251 /**
252 * @brief Get configuration of a dedicated Exti line.
253 * @param hexti Exti handle.
254 * @param pExtiConfig Pointer on structure to store Exti configuration.
255 * @retval HAL Status.
256 */
HAL_EXTI_GetConfigLine(EXTI_HandleTypeDef * hexti,EXTI_ConfigTypeDef * pExtiConfig)257 HAL_StatusTypeDef HAL_EXTI_GetConfigLine(EXTI_HandleTypeDef *hexti, EXTI_ConfigTypeDef *pExtiConfig)
258 {
259 uint32_t *regaddr;
260 uint32_t regval;
261 uint32_t linepos;
262 uint32_t maskline;
263 uint32_t offset;
264
265 /* Check null pointer */
266 if ((hexti == NULL) || (pExtiConfig == NULL))
267 {
268 return HAL_ERROR;
269 }
270
271 /* Check the parameter */
272 assert_param(IS_EXTI_LINE(hexti->Line));
273
274 /* Store handle line number to configiguration structure */
275 pExtiConfig->Line = hexti->Line;
276
277 /* compute line register offset and line mask */
278 offset = ((pExtiConfig->Line & EXTI_REG_MASK) >> EXTI_REG_SHIFT);
279 linepos = (pExtiConfig->Line & EXTI_PIN_MASK);
280 maskline = (1UL << linepos);
281
282 /* 1] Get core mode : interrupt */
283 regaddr = (uint32_t *)(&EXTI->IMR1 + (EXTI_MODE_OFFSET * offset));
284 regval = *regaddr;
285
286 /* Check if selected line is enable */
287 if ((regval & maskline) != 0x00U)
288 {
289 pExtiConfig->Mode = EXTI_MODE_INTERRUPT;
290 }
291 else
292 {
293 pExtiConfig->Mode = EXTI_MODE_NONE;
294 }
295
296 /* Get event mode */
297 regaddr = (uint32_t *)(&EXTI->EMR1 + (EXTI_MODE_OFFSET * offset));
298 regval = *regaddr;
299
300 /* Check if selected line is enable */
301 if ((regval & maskline) != 0x00U)
302 {
303 pExtiConfig->Mode |= EXTI_MODE_EVENT;
304 }
305
306 /* 2] Get trigger for configurable lines : rising */
307 if ((pExtiConfig->Line & EXTI_CONFIG) != 0x00U)
308 {
309 regaddr = (uint32_t *)(&EXTI->RTSR1 + (EXTI_CONFIG_OFFSET * offset));
310 regval = *regaddr;
311
312 /* Get default Trigger and GPIOSel configuration */
313 pExtiConfig->Trigger = EXTI_TRIGGER_NONE;
314 pExtiConfig->GPIOSel = 0x00u;
315
316 /* Check if configuration of selected line is enable */
317 if ((regval & maskline) != 0x00U)
318 {
319 pExtiConfig->Trigger = EXTI_TRIGGER_RISING;
320 }
321
322 /* Get falling configuration */
323 regaddr = (uint32_t *)(&EXTI->FTSR1 + (EXTI_CONFIG_OFFSET * offset));
324 regval = *regaddr;
325
326 /* Check if configuration of selected line is enable */
327 if ((regval & maskline) != 0x00U)
328 {
329 pExtiConfig->Trigger |= EXTI_TRIGGER_FALLING;
330 }
331
332 /* Get Gpio port selection for gpio lines */
333 if ((pExtiConfig->Line & EXTI_GPIO) == EXTI_GPIO)
334 {
335 assert_param(IS_EXTI_GPIO_PIN(linepos));
336 regval = EXTI->EXTICR[linepos >> 2U];
337 pExtiConfig->GPIOSel = ((regval << (8U * (3 - (linepos & 0x03U)))) >> 24);
338 }
339 }
340 else
341 {
342 pExtiConfig->Trigger = EXTI_TRIGGER_NONE;
343 pExtiConfig->GPIOSel = 0x00U;
344 }
345
346 return HAL_OK;
347 }
348
349 /**
350 * @brief Clear whole configuration of a dedicated Exti line.
351 * @param hexti Exti handle.
352 * @retval HAL Status.
353 */
HAL_EXTI_ClearConfigLine(EXTI_HandleTypeDef * hexti)354 HAL_StatusTypeDef HAL_EXTI_ClearConfigLine(EXTI_HandleTypeDef *hexti)
355 {
356 uint32_t *regaddr;
357 uint32_t regval;
358 uint32_t linepos;
359 uint32_t maskline;
360 uint32_t offset;
361
362 /* Check null pointer */
363 if (hexti == NULL)
364 {
365 return HAL_ERROR;
366 }
367
368 /* Check the parameter */
369 assert_param(IS_EXTI_LINE(hexti->Line));
370 /* compute line register offset and line mask */
371 offset = ((hexti->Line & EXTI_REG_MASK) >> EXTI_REG_SHIFT);
372 linepos = (hexti->Line & EXTI_PIN_MASK);
373 maskline = (1 << linepos);
374
375 /* 1] Clear interrupt mode */
376 regaddr = (uint32_t *)(&EXTI->IMR1 + (EXTI_MODE_OFFSET * offset));
377 regval = (*regaddr & ~maskline);
378 *regaddr = regval;
379
380 /* 2] Clear event mode */
381 regaddr = (uint32_t *)(&EXTI->EMR1 + (EXTI_MODE_OFFSET * offset));
382 regval = (*regaddr & ~maskline);
383 *regaddr = regval;
384
385 /* 3] Clear triggers in case of configurable lines */
386 if ((hexti->Line & EXTI_CONFIG) != 0x00U)
387 {
388 regaddr = (uint32_t *)(&EXTI->RTSR1 + (EXTI_CONFIG_OFFSET * offset));
389 regval = (*regaddr & ~maskline);
390 *regaddr = regval;
391
392 regaddr = (uint32_t *)(&EXTI->FTSR1 + (EXTI_CONFIG_OFFSET * offset));
393 regval = (*regaddr & ~maskline);
394 *regaddr = regval;
395
396 /* Get Gpio port selection for gpio lines */
397 if ((hexti->Line & EXTI_GPIO) != 0x00U)
398 {
399 assert_param(IS_EXTI_GPIO_PIN(linepos));
400 regval = EXTI->EXTICR[linepos >> 2U];
401 regval &= ~(0xFFU << (8U * (linepos & 0x03U)));
402 EXTI->EXTICR[linepos >> 2U] = regval;
403 }
404 }
405
406 return HAL_OK;
407 }
408
409 /**
410 * @brief Register callback for a dedicaated Exti line.
411 * @param hexti Exti handle.
412 * @param CallbackID User callback identifier.
413 * This parameter can be one of @arg @ref EXTI_CallbackIDTypeDef values.
414 * @param pPendingCbfn function pointer to be stored as callback.
415 * @retval HAL Status.
416 */
HAL_EXTI_RegisterCallback(EXTI_HandleTypeDef * hexti,EXTI_CallbackIDTypeDef CallbackID,void (* pPendingCbfn)(void))417 HAL_StatusTypeDef HAL_EXTI_RegisterCallback(EXTI_HandleTypeDef *hexti, EXTI_CallbackIDTypeDef CallbackID,
418 void (*pPendingCbfn)(void))
419 {
420 HAL_StatusTypeDef status = HAL_OK;
421
422 switch (CallbackID)
423 {
424 case HAL_EXTI_COMMON_CB_ID:
425 hexti->RisingCallback = pPendingCbfn;
426 hexti->FallingCallback = pPendingCbfn;
427 break;
428
429 case HAL_EXTI_RISING_CB_ID:
430 hexti->RisingCallback = pPendingCbfn;
431 break;
432
433 case HAL_EXTI_FALLING_CB_ID:
434 hexti->FallingCallback = pPendingCbfn;
435 break;
436
437 default:
438 status = HAL_ERROR;
439 break;
440 }
441
442 return status;
443 }
444
445 /**
446 * @brief Store line number as handle private field.
447 * @param hexti Exti handle.
448 * @param ExtiLine Exti line number.
449 * This parameter can be from 0 to @ref EXTI_LINE_NB.
450 * @retval HAL Status.
451 */
HAL_EXTI_GetHandle(EXTI_HandleTypeDef * hexti,uint32_t ExtiLine)452 HAL_StatusTypeDef HAL_EXTI_GetHandle(EXTI_HandleTypeDef *hexti, uint32_t ExtiLine)
453 {
454 /* Check the parameters */
455 assert_param(IS_EXTI_LINE(ExtiLine));
456
457 /* Check null pointer */
458 if (hexti == NULL)
459 {
460 return HAL_ERROR;
461 }
462 else
463 {
464 /* Store line number as handle private field */
465 hexti->Line = ExtiLine;
466
467 return HAL_OK;
468 }
469 }
470
471 /**
472 * @}
473 */
474
475 /** @addtogroup EXTI_Exported_Functions_Group2
476 * @brief EXTI IO functions.
477 *
478 @verbatim
479 ===============================================================================
480 ##### IO operation functions #####
481 ===============================================================================
482
483 @endverbatim
484 * @{
485 */
486
487 /**
488 * @brief Handle EXTI interrupt request.
489 * @param hexti Exti handle.
490 * @retval none.
491 */
HAL_EXTI_IRQHandler(EXTI_HandleTypeDef * hexti)492 void HAL_EXTI_IRQHandler(EXTI_HandleTypeDef *hexti)
493 {
494 uint32_t *regaddr;
495 uint32_t regval;
496 uint32_t maskline;
497 uint32_t offset;
498
499 /* compute line register offset and line mask */
500 offset = ((hexti->Line & EXTI_REG_MASK) >> EXTI_REG_SHIFT);
501 maskline = (1 << (hexti->Line & EXTI_PIN_MASK));
502
503 /* Get rising edge pending bit */
504 regaddr = (uint32_t *)(&EXTI->RPR1 + (EXTI_CONFIG_OFFSET * offset));
505 regval = (*regaddr & maskline);
506
507 if (regval != 0x00U)
508 {
509 /* Clear pending bit */
510 *regaddr = maskline;
511
512 /* Call rising callback */
513 if (hexti->RisingCallback != NULL)
514 {
515 hexti->RisingCallback();
516 }
517 }
518
519 /* Get falling edge pending bit */
520 regaddr = (uint32_t *)(&EXTI->FPR1 + (EXTI_CONFIG_OFFSET * offset));
521 regval = (*regaddr & maskline);
522
523 if (regval != 0x00U)
524 {
525 /* Clear pending bit */
526 *regaddr = maskline;
527
528 /* Call rising callback */
529 if (hexti->FallingCallback != NULL)
530 {
531 hexti->FallingCallback();
532 }
533 }
534 }
535
536 /**
537 * @brief Get interrupt pending bit of a dedicated line.
538 * @param hexti Exti handle.
539 * @param Edge Specify which pending edge as to be checked.
540 * This parameter can be one of the following values:
541 * @arg @ref EXTI_TRIGGER_RISING
542 * @arg @ref EXTI_TRIGGER_FALLING
543 * @retval 1 if interrupt is pending else 0.
544 */
HAL_EXTI_GetPending(EXTI_HandleTypeDef * hexti,uint32_t Edge)545 uint32_t HAL_EXTI_GetPending(EXTI_HandleTypeDef *hexti, uint32_t Edge)
546 {
547 uint32_t *regaddr;
548 uint32_t regval;
549 uint32_t linepos;
550 uint32_t maskline;
551 uint32_t offset;
552
553 /* Check parameters */
554 assert_param(IS_EXTI_CONFIG_LINE(hexti->Line));
555 assert_param(IS_EXTI_PENDING_EDGE(Edge));
556
557 /* compute line register offset and line mask */
558 offset = ((hexti->Line & EXTI_REG_MASK) >> EXTI_REG_SHIFT);
559 linepos = (hexti->Line & EXTI_PIN_MASK);
560 maskline = (1 << linepos);
561
562 if (Edge != EXTI_TRIGGER_RISING)
563 {
564 /* Get falling edge pending bit */
565 regaddr = (uint32_t *)(&EXTI->FPR1 + (EXTI_CONFIG_OFFSET * offset));
566 }
567 else
568 {
569 /* Get rising edge pending bit */
570 regaddr = (uint32_t *)(&EXTI->RPR1 + (EXTI_CONFIG_OFFSET * offset));
571 }
572
573 /* return 1 if bit is set else 0 */
574 regval = ((*regaddr & maskline) >> linepos);
575 return regval;
576 }
577
578 /**
579 * @brief Clear interrupt pending bit of a dedicated line.
580 * @param hexti Exti handle.
581 * @param Edge Specify which pending edge as to be clear.
582 * This parameter can be one of the following values:
583 * @arg @ref EXTI_TRIGGER_RISING
584 * @arg @ref EXTI_TRIGGER_FALLING
585 * @retval None.
586 */
HAL_EXTI_ClearPending(EXTI_HandleTypeDef * hexti,uint32_t Edge)587 void HAL_EXTI_ClearPending(EXTI_HandleTypeDef *hexti, uint32_t Edge)
588 {
589 uint32_t *regaddr;
590 uint32_t maskline;
591 uint32_t offset;
592
593 /* Check parameters */
594 assert_param(IS_EXTI_LINE(hexti->Line));
595 assert_param(IS_EXTI_CONFIG_LINE(hexti->Line));
596 assert_param(IS_EXTI_PENDING_EDGE(Edge));
597
598 /* compute line register offset and line mask */
599 offset = ((hexti->Line & EXTI_REG_MASK) >> EXTI_REG_SHIFT);
600 maskline = (1 << (hexti->Line & EXTI_PIN_MASK));
601
602 if (Edge != EXTI_TRIGGER_RISING)
603 {
604 /* Get falling edge pending register address */
605 regaddr = (uint32_t *)(&EXTI->FPR1 + (EXTI_CONFIG_OFFSET * offset));
606 }
607 else
608 {
609 /* Get falling edge pending register address */
610 regaddr = (uint32_t *)(&EXTI->RPR1 + (EXTI_CONFIG_OFFSET * offset));
611 }
612
613 /* Clear Pending bit */
614 *regaddr = maskline;
615 }
616
617 /**
618 * @brief Generate a software interrupt for a dedicated line.
619 * @param hexti Exti handle.
620 * @retval None.
621 */
HAL_EXTI_GenerateSWI(EXTI_HandleTypeDef * hexti)622 void HAL_EXTI_GenerateSWI(EXTI_HandleTypeDef *hexti)
623 {
624 uint32_t *regaddr;
625 uint32_t maskline;
626 uint32_t offset;
627
628 /* Check parameter */
629 assert_param(IS_EXTI_CONFIG_LINE(hexti->Line));
630
631 /* compute line register offset and line mask */
632 offset = ((hexti->Line & EXTI_REG_MASK) >> EXTI_REG_SHIFT);
633 maskline = (1 << (hexti->Line & EXTI_PIN_MASK));
634
635 regaddr = (uint32_t *)(&EXTI->SWIER1 + (EXTI_CONFIG_OFFSET * offset));
636 *regaddr = maskline;
637 }
638
639 /**
640 * @}
641 */
642
643 /**
644 * @}
645 */
646
647 #endif /* HAL_EXTI_MODULE_ENABLED */
648 /**
649 * @}
650 */
651
652 /**
653 * @}
654 */
655