1 /**
2 ******************************************************************************
3 * @file stm32c0xx_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 ******************************************************************************
12 * @attention
13 *
14 * Copyright (c) 2022 STMicroelectronics.
15 * All rights reserved.
16 *
17 * This software is licensed under terms that can be found in the LICENSE file
18 * in the root directory of this software component.
19 * If no LICENSE file comes with this software, it is provided AS-IS.
20 *
21 ******************************************************************************
22 @verbatim
23 ==============================================================================
24 ##### EXTI Peripheral features #####
25 ==============================================================================
26 [..]
27 (+) Each Exti line can be configured within this driver.
28
29 (+) Exti line can be configured in 3 different modes
30 (++) Interrupt
31 (++) Event
32 (++) Both of them
33
34 (+) Configurable Exti lines can be configured with 3 different triggers
35 (++) Rising
36 (++) Falling
37 (++) Both of them
38
39 (+) When set in interrupt mode, configurable Exti lines have two diffenrents
40 interrupt pending registers which allow to distinguish which transition
41 occurs:
42 (++) Rising edge pending interrupt
43 (++) Falling
44
45 (+) Exti lines 0 to 15 are linked to gpio pin number 0 to 15. Gpio port can
46 be selected through multiplexer.
47
48 ##### How to use this driver #####
49 ==============================================================================
50 [..]
51
52 (#) Configure the EXTI line using HAL_EXTI_SetConfigLine().
53 (++) Choose the interrupt line number by setting "Line" member from
54 EXTI_ConfigTypeDef structure.
55 (++) Configure the interrupt and/or event mode using "Mode" member from
56 EXTI_ConfigTypeDef structure.
57 (++) For configurable lines, configure rising and/or falling trigger
58 "Trigger" member from EXTI_ConfigTypeDef structure.
59 (++) For Exti lines linked to gpio, choose gpio port using "GPIOSel"
60 member from GPIO_InitTypeDef structure.
61
62 (#) Get current Exti configuration of a dedicated line using
63 HAL_EXTI_GetConfigLine().
64 (++) Provide exiting handle as parameter.
65 (++) Provide pointer on EXTI_ConfigTypeDef structure as second parameter.
66
67 (#) Clear Exti configuration of a dedicated line using HAL_EXTI_GetConfigLine().
68 (++) Provide exiting handle as parameter.
69
70 (#) Register callback to treat Exti interrupts using HAL_EXTI_RegisterCallback().
71 (++) Provide exiting handle as first parameter.
72 (++) Provide which callback will be registered using one value from
73 EXTI_CallbackIDTypeDef.
74 (++) Provide callback function pointer.
75
76 (#) Get interrupt pending bit using HAL_EXTI_GetPending().
77
78 (#) Clear interrupt pending bit using HAL_EXTI_GetPending().
79
80 (#) Generate software interrupt using HAL_EXTI_GenerateSWI().
81
82 @endverbatim
83 */
84
85 /* Includes ------------------------------------------------------------------*/
86 #include "stm32c0xx_hal.h"
87
88 /** @addtogroup STM32C0xx_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 /* 0x10: offset between CPU IMR/EMR registers */
104 #define EXTI_CONFIG_OFFSET 0x08u /* 0x20: offset between CPU 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 __IO 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) != 0U)
164 {
165 assert_param(IS_EXTI_TRIGGER(pExtiConfig->Trigger));
166
167 /* Configure rising trigger */
168 regaddr = (__IO uint32_t *)(&EXTI->RTSR1 + (EXTI_CONFIG_OFFSET * offset));
169 regval = *regaddr;
170
171 /* Mask or set line */
172 if ((pExtiConfig->Trigger & EXTI_TRIGGER_RISING) != 0U)
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 = (__IO uint32_t *)(&EXTI->FTSR1 + (EXTI_CONFIG_OFFSET * offset));
186 regval = *regaddr;
187
188 /* Mask or set line */
189 if ((pExtiConfig->Trigger & EXTI_TRIGGER_FALLING) != 0U)
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) & 0x03UL];
208 regval &= ~(EXTI_EXTICR1_EXTI0 << (EXTI_EXTICR1_EXTI1_Pos * (linepos & 0x03U)));
209 regval |= (pExtiConfig->GPIOSel << (EXTI_EXTICR1_EXTI1_Pos * (linepos & 0x03U)));
210 EXTI->EXTICR[(linepos >> 2U) & 0x03UL] = regval;
211 }
212 }
213
214 /* Configure interrupt mode : read current mode */
215 regaddr = (__IO uint32_t *)(&EXTI->IMR1 + (EXTI_MODE_OFFSET * offset));
216 regval = *regaddr;
217
218 /* Mask or set line */
219 if ((pExtiConfig->Mode & EXTI_MODE_INTERRUPT) != 0U)
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 = (__IO uint32_t *)(&EXTI->EMR1 + (EXTI_MODE_OFFSET * offset));
233 regval = *regaddr;
234
235 /* Mask or set line */
236 if ((pExtiConfig->Mode & EXTI_MODE_EVENT) != 0U)
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 const __IO 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 = (__IO uint32_t *)(&EXTI->IMR1 + (EXTI_MODE_OFFSET * offset));
284 regval = *regaddr;
285
286 /* Check if selected line is enable */
287 if ((regval & maskline) != 0U)
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 = (__IO uint32_t *)(&EXTI->EMR1 + (EXTI_MODE_OFFSET * offset));
298 regval = *regaddr;
299
300 /* Check if selected line is enable */
301 if ((regval & maskline) != 0U)
302 {
303 pExtiConfig->Mode |= EXTI_MODE_EVENT;
304 }
305
306 /* 2] Get trigger for configurable lines : rising */
307 if ((pExtiConfig->Line & EXTI_CONFIG) != 0U)
308 {
309 regaddr = (__IO 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) != 0U)
318 {
319 pExtiConfig->Trigger = EXTI_TRIGGER_RISING;
320 }
321
322 /* Get falling configuration */
323 regaddr = (__IO 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) != 0U)
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
337 regval = EXTI->EXTICR[(linepos >> 2U) & 0x03UL];
338 pExtiConfig->GPIOSel = (regval >> (EXTI_EXTICR1_EXTI1_Pos * (linepos & 0x03u))) & EXTI_EXTICR1_EXTI0;
339 }
340 }
341
342 return HAL_OK;
343 }
344
345 /**
346 * @brief Clear whole configuration of a dedicated Exti line.
347 * @param hexti Exti handle.
348 * @retval HAL Status.
349 */
HAL_EXTI_ClearConfigLine(const EXTI_HandleTypeDef * hexti)350 HAL_StatusTypeDef HAL_EXTI_ClearConfigLine(const EXTI_HandleTypeDef *hexti)
351 {
352 __IO uint32_t *regaddr;
353 uint32_t regval;
354 uint32_t linepos;
355 uint32_t maskline;
356 uint32_t offset;
357
358 /* Check null pointer */
359 if (hexti == NULL)
360 {
361 return HAL_ERROR;
362 }
363
364 /* Check the parameter */
365 assert_param(IS_EXTI_LINE(hexti->Line));
366
367 /* compute line register offset and line mask */
368 offset = ((hexti->Line & EXTI_REG_MASK) >> EXTI_REG_SHIFT);
369 linepos = (hexti->Line & EXTI_PIN_MASK);
370 maskline = (1UL << linepos);
371
372 /* 1] Clear interrupt mode */
373 regaddr = (__IO uint32_t *)(&EXTI->IMR1 + (EXTI_MODE_OFFSET * offset));
374 regval = (*regaddr & ~maskline);
375 *regaddr = regval;
376
377 /* 2] Clear event mode */
378 regaddr = (__IO uint32_t *)(&EXTI->EMR1 + (EXTI_MODE_OFFSET * offset));
379 regval = (*regaddr & ~maskline);
380 *regaddr = regval;
381
382 /* 3] Clear triggers in case of configurable lines */
383 if ((hexti->Line & EXTI_CONFIG) != 0U)
384 {
385 regaddr = (__IO uint32_t *)(&EXTI->RTSR1 + (EXTI_CONFIG_OFFSET * offset));
386 regval = (*regaddr & ~maskline);
387 *regaddr = regval;
388
389 regaddr = (__IO uint32_t *)(&EXTI->FTSR1 + (EXTI_CONFIG_OFFSET * offset));
390 regval = (*regaddr & ~maskline);
391 *regaddr = regval;
392
393 /* Get Gpio port selection for gpio lines */
394 if ((hexti->Line & EXTI_GPIO) == EXTI_GPIO)
395 {
396 assert_param(IS_EXTI_GPIO_PIN(linepos));
397
398 regval = EXTI->EXTICR[(linepos >> 2U) & 0x03UL];
399 regval &= ~(EXTI_EXTICR1_EXTI0 << (EXTI_EXTICR1_EXTI1_Pos * (linepos & 0x03U)));
400 EXTI->EXTICR[(linepos >> 2U) & 0x03UL] = regval;
401 }
402 }
403
404 return HAL_OK;
405 }
406
407 /**
408 * @brief Register callback for a dedicaated Exti line.
409 * @param hexti Exti handle.
410 * @param CallbackID User callback identifier.
411 * This parameter can be one of @arg @ref EXTI_CallbackIDTypeDef values.
412 * @param pPendingCbfn function pointer to be stored as callback.
413 * @retval HAL Status.
414 */
HAL_EXTI_RegisterCallback(EXTI_HandleTypeDef * hexti,EXTI_CallbackIDTypeDef CallbackID,void (* pPendingCbfn)(void))415 HAL_StatusTypeDef HAL_EXTI_RegisterCallback(EXTI_HandleTypeDef *hexti, EXTI_CallbackIDTypeDef CallbackID,
416 void (*pPendingCbfn)(void))
417 {
418 HAL_StatusTypeDef status = HAL_OK;
419
420 switch (CallbackID)
421 {
422 case HAL_EXTI_COMMON_CB_ID:
423 hexti->RisingCallback = pPendingCbfn;
424 hexti->FallingCallback = pPendingCbfn;
425 break;
426
427 case HAL_EXTI_RISING_CB_ID:
428 hexti->RisingCallback = pPendingCbfn;
429 break;
430
431 case HAL_EXTI_FALLING_CB_ID:
432 hexti->FallingCallback = pPendingCbfn;
433 break;
434
435 default:
436 status = HAL_ERROR;
437 break;
438 }
439
440 return status;
441 }
442
443 /**
444 * @brief Store line number as handle private field.
445 * @param hexti Exti handle.
446 * @param ExtiLine Exti line number.
447 * This parameter can be from 0 to @ref EXTI_LINE_NB.
448 * @retval HAL Status.
449 */
HAL_EXTI_GetHandle(EXTI_HandleTypeDef * hexti,uint32_t ExtiLine)450 HAL_StatusTypeDef HAL_EXTI_GetHandle(EXTI_HandleTypeDef *hexti, uint32_t ExtiLine)
451 {
452 /* Check the parameters */
453 assert_param(IS_EXTI_LINE(ExtiLine));
454
455 /* Check null pointer */
456 if (hexti == NULL)
457 {
458 return HAL_ERROR;
459 }
460 else
461 {
462 /* Store line number as handle private field */
463 hexti->Line = ExtiLine;
464
465 return HAL_OK;
466 }
467 }
468
469 /**
470 * @}
471 */
472
473 /** @addtogroup EXTI_Exported_Functions_Group2
474 * @brief EXTI IO functions.
475 *
476 @verbatim
477 ===============================================================================
478 ##### IO operation functions #####
479 ===============================================================================
480
481 @endverbatim
482 * @{
483 */
484
485 /**
486 * @brief Handle EXTI interrupt request.
487 * @param hexti Exti handle.
488 * @retval none.
489 */
HAL_EXTI_IRQHandler(const EXTI_HandleTypeDef * hexti)490 void HAL_EXTI_IRQHandler(const EXTI_HandleTypeDef *hexti)
491 {
492 __IO uint32_t *regaddr;
493 uint32_t regval;
494 uint32_t maskline;
495 uint32_t offset;
496
497 /* Compute line register offset and line mask */
498 offset = ((hexti->Line & EXTI_REG_MASK) >> EXTI_REG_SHIFT);
499 maskline = (1UL << (hexti->Line & EXTI_PIN_MASK));
500
501 /* Get rising edge pending bit */
502 regaddr = (__IO uint32_t *)(&EXTI->RPR1 + (EXTI_CONFIG_OFFSET * offset));
503 regval = (*regaddr & maskline);
504
505 if (regval != 0U)
506 {
507 /* Clear pending bit */
508 *regaddr = maskline;
509
510 /* Call rising callback */
511 if (hexti->RisingCallback != NULL)
512 {
513 hexti->RisingCallback();
514 }
515 }
516
517 /* Get falling edge pending bit */
518 regaddr = (__IO uint32_t *)(&EXTI->FPR1 + (EXTI_CONFIG_OFFSET * offset));
519 regval = (*regaddr & maskline);
520
521 if (regval != 0U)
522 {
523 /* Clear pending bit */
524 *regaddr = maskline;
525
526 /* Call rising callback */
527 if (hexti->FallingCallback != NULL)
528 {
529 hexti->FallingCallback();
530 }
531 }
532 }
533
534
535 /**
536 * @brief Get interrupt pending bit of a dedicated line.
537 * @param hexti Exti handle.
538 * @param Edge Specify which pending edge as to be checked.
539 * This parameter can be one of the following values:
540 * @arg @ref EXTI_TRIGGER_RISING
541 * @arg @ref EXTI_TRIGGER_FALLING
542 * @retval 1 if interrupt is pending else 0.
543 */
HAL_EXTI_GetPending(const EXTI_HandleTypeDef * hexti,uint32_t Edge)544 uint32_t HAL_EXTI_GetPending(const EXTI_HandleTypeDef *hexti, uint32_t Edge)
545 {
546 const __IO uint32_t *regaddr;
547 uint32_t regval;
548 uint32_t linepos;
549 uint32_t maskline;
550 uint32_t offset;
551
552 /* Check the parameters */
553 assert_param(IS_EXTI_LINE(hexti->Line));
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 = (1UL << linepos);
561
562 if (Edge != EXTI_TRIGGER_RISING)
563 {
564 /* Get falling edge pending bit */
565 regaddr = (__IO uint32_t *)(&EXTI->FPR1 + (EXTI_CONFIG_OFFSET * offset));
566 }
567 else
568 {
569 /* Get rising edge pending bit */
570 regaddr = (__IO 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 /**
580 * @brief Clear interrupt pending bit of a dedicated line.
581 * @param hexti Exti handle.
582 * @param Edge Specify which pending edge as to be clear.
583 * This parameter can be one of the following values:
584 * @arg @ref EXTI_TRIGGER_RISING
585 * @arg @ref EXTI_TRIGGER_FALLING
586 * @retval None.
587 */
HAL_EXTI_ClearPending(const EXTI_HandleTypeDef * hexti,uint32_t Edge)588 void HAL_EXTI_ClearPending(const EXTI_HandleTypeDef *hexti, uint32_t Edge)
589 {
590 __IO uint32_t *regaddr;
591 uint32_t maskline;
592 uint32_t offset;
593
594 /* Check the parameters */
595 assert_param(IS_EXTI_LINE(hexti->Line));
596 assert_param(IS_EXTI_CONFIG_LINE(hexti->Line));
597 assert_param(IS_EXTI_PENDING_EDGE(Edge));
598
599 /* compute line register offset and line mask */
600 offset = ((hexti->Line & EXTI_REG_MASK) >> EXTI_REG_SHIFT);
601 maskline = (1UL << (hexti->Line & EXTI_PIN_MASK));
602
603 if (Edge != EXTI_TRIGGER_RISING)
604 {
605 /* Get falling edge pending register address */
606 regaddr = (__IO uint32_t *)(&EXTI->FPR1 + (EXTI_CONFIG_OFFSET * offset));
607 }
608 else
609 {
610 /* Get falling edge pending register address */
611 regaddr = (__IO uint32_t *)(&EXTI->RPR1 + (EXTI_CONFIG_OFFSET * offset));
612 }
613
614 /* Clear Pending bit */
615 *regaddr = maskline;
616 }
617
618
619 /**
620 * @brief Generate a software interrupt for a dedicated line.
621 * @param hexti Exti handle.
622 * @retval None.
623 */
HAL_EXTI_GenerateSWI(const EXTI_HandleTypeDef * hexti)624 void HAL_EXTI_GenerateSWI(const EXTI_HandleTypeDef *hexti)
625 {
626 __IO uint32_t *regaddr;
627 uint32_t maskline;
628 uint32_t offset;
629
630 /* Check the parameters */
631 assert_param(IS_EXTI_LINE(hexti->Line));
632 assert_param(IS_EXTI_CONFIG_LINE(hexti->Line));
633
634 /* compute line register offset and line mask */
635 offset = ((hexti->Line & EXTI_REG_MASK) >> EXTI_REG_SHIFT);
636 maskline = (1UL << (hexti->Line & EXTI_PIN_MASK));
637
638 regaddr = (__IO uint32_t *)(&EXTI->SWIER1 + (EXTI_CONFIG_OFFSET * offset));
639 *regaddr = maskline;
640 }
641
642
643 /**
644 * @}
645 */
646
647 /**
648 * @}
649 */
650
651 #endif /* HAL_EXTI_MODULE_ENABLED */
652 /**
653 * @}
654 */
655
656 /**
657 * @}
658 */
659
660 /**
661 * @}
662 */
663