1 /**
2 ******************************************************************************
3 * @file stm32g0xx_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) 2018 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 "stm32g0xx_hal.h"
87
88 /** @addtogroup STM32G0xx_HAL_Driver
89 * @{
90 */
91
92 /** @addtogroup EXTI
93 * @{
94 */
95 /** MISRA C:2012 deviation rule has been granted for following rule:
96 * Rule-18.1_b - Medium: Array `EXTICR' 1st subscript interval [0,7] may be out
97 * of bounds [0,3] in following API :
98 * HAL_EXTI_SetConfigLine
99 * HAL_EXTI_GetConfigLine
100 * HAL_EXTI_ClearConfigLine
101 */
102
103 #ifdef HAL_EXTI_MODULE_ENABLED
104
105 /* Private typedef -----------------------------------------------------------*/
106 /* Private defines ------------------------------------------------------------*/
107 /** @defgroup EXTI_Private_Constants EXTI Private Constants
108 * @{
109 */
110 #define EXTI_MODE_OFFSET 0x04u /* 0x10: offset between CPU IMR/EMR registers */
111 #define EXTI_CONFIG_OFFSET 0x08u /* 0x20: offset between CPU Rising/Falling configuration registers */
112 /**
113 * @}
114 */
115
116 /* Private macros ------------------------------------------------------------*/
117 /* Private variables ---------------------------------------------------------*/
118 /* Private function prototypes -----------------------------------------------*/
119 /* Exported functions --------------------------------------------------------*/
120
121 /** @addtogroup EXTI_Exported_Functions
122 * @{
123 */
124
125 /** @addtogroup EXTI_Exported_Functions_Group1
126 * @brief Configuration functions
127 *
128 @verbatim
129 ===============================================================================
130 ##### Configuration functions #####
131 ===============================================================================
132
133 @endverbatim
134 * @{
135 */
136
137 /**
138 * @brief Set configuration of a dedicated Exti line.
139 * @param hexti Exti handle.
140 * @param pExtiConfig Pointer on EXTI configuration to be set.
141 * @retval HAL Status.
142 */
HAL_EXTI_SetConfigLine(EXTI_HandleTypeDef * hexti,EXTI_ConfigTypeDef * pExtiConfig)143 HAL_StatusTypeDef HAL_EXTI_SetConfigLine(EXTI_HandleTypeDef *hexti, EXTI_ConfigTypeDef *pExtiConfig)
144 {
145 __IO uint32_t *regaddr;
146 uint32_t regval;
147 uint32_t linepos;
148 uint32_t maskline;
149 uint32_t offset;
150
151 /* Check null pointer */
152 if ((hexti == NULL) || (pExtiConfig == NULL))
153 {
154 return HAL_ERROR;
155 }
156
157 /* Check parameters */
158 assert_param(IS_EXTI_LINE(pExtiConfig->Line));
159 assert_param(IS_EXTI_MODE(pExtiConfig->Mode));
160
161 /* Assign line number to handle */
162 hexti->Line = pExtiConfig->Line;
163
164 /* compute line register offset and line mask */
165 offset = ((pExtiConfig->Line & EXTI_REG_MASK) >> EXTI_REG_SHIFT);
166 linepos = (pExtiConfig->Line & EXTI_PIN_MASK);
167 maskline = (1uL << linepos);
168
169 /* Configure triggers for configurable lines */
170 if ((pExtiConfig->Line & EXTI_CONFIG) != 0x00u)
171 {
172 assert_param(IS_EXTI_TRIGGER(pExtiConfig->Trigger));
173
174 /* Configure rising trigger */
175 regaddr = (&EXTI->RTSR1 + (EXTI_CONFIG_OFFSET * offset));
176 regval = *regaddr;
177
178 /* Mask or set line */
179 if ((pExtiConfig->Trigger & EXTI_TRIGGER_RISING) != 0x00u)
180 {
181 regval |= maskline;
182 }
183 else
184 {
185 regval &= ~maskline;
186 }
187
188 /* Store rising trigger mode */
189 *regaddr = regval;
190
191 /* Configure falling trigger */
192 regaddr = (&EXTI->FTSR1 + (EXTI_CONFIG_OFFSET * offset));
193 regval = *regaddr;
194
195 /* Mask or set line */
196 if ((pExtiConfig->Trigger & EXTI_TRIGGER_FALLING) != 0x00u)
197 {
198 regval |= maskline;
199 }
200 else
201 {
202 regval &= ~maskline;
203 }
204
205 /* Store falling trigger mode */
206 *regaddr = regval;
207
208 /* Configure gpio port selection in case of gpio exti line */
209 if ((pExtiConfig->Line & EXTI_GPIO) == EXTI_GPIO)
210 {
211 assert_param(IS_EXTI_GPIO_PORT(pExtiConfig->GPIOSel));
212 assert_param(IS_EXTI_GPIO_PIN(linepos));
213
214 regval = EXTI->EXTICR[linepos >> 2u];
215 regval &= ~(EXTI_EXTICR1_EXTI0 << (EXTI_EXTICR1_EXTI1_Pos * (linepos & 0x03u)));
216 regval |= (pExtiConfig->GPIOSel << (EXTI_EXTICR1_EXTI1_Pos * (linepos & 0x03u)));
217 EXTI->EXTICR[linepos >> 2u] = regval;
218 }
219 }
220
221 /* Configure interrupt mode : read current mode */
222 regaddr = (&EXTI->IMR1 + (EXTI_MODE_OFFSET * offset));
223 regval = *regaddr;
224
225 /* Mask or set line */
226 if ((pExtiConfig->Mode & EXTI_MODE_INTERRUPT) != 0x00u)
227 {
228 regval |= maskline;
229 }
230 else
231 {
232 regval &= ~maskline;
233 }
234
235 /* Store interrupt mode */
236 *regaddr = regval;
237
238 /* Configure event mode : read current mode */
239 regaddr = (&EXTI->EMR1 + (EXTI_MODE_OFFSET * offset));
240 regval = *regaddr;
241
242 /* Mask or set line */
243 if ((pExtiConfig->Mode & EXTI_MODE_EVENT) != 0x00u)
244 {
245 regval |= maskline;
246 }
247 else
248 {
249 regval &= ~maskline;
250 }
251
252 /* Store event mode */
253 *regaddr = regval;
254
255 return HAL_OK;
256 }
257
258
259 /**
260 * @brief Get configuration of a dedicated Exti line.
261 * @param hexti Exti handle.
262 * @param pExtiConfig Pointer on structure to store Exti configuration.
263 * @retval HAL Status.
264 */
HAL_EXTI_GetConfigLine(EXTI_HandleTypeDef * hexti,EXTI_ConfigTypeDef * pExtiConfig)265 HAL_StatusTypeDef HAL_EXTI_GetConfigLine(EXTI_HandleTypeDef *hexti, EXTI_ConfigTypeDef *pExtiConfig)
266 {
267 __IO uint32_t *regaddr;
268 uint32_t regval;
269 uint32_t linepos;
270 uint32_t maskline;
271 uint32_t offset;
272
273 /* Check null pointer */
274 if ((hexti == NULL) || (pExtiConfig == NULL))
275 {
276 return HAL_ERROR;
277 }
278
279 /* Check the parameter */
280 assert_param(IS_EXTI_LINE(hexti->Line));
281
282 /* Store handle line number to configiguration structure */
283 pExtiConfig->Line = hexti->Line;
284
285 /* compute line register offset and line mask */
286 offset = ((pExtiConfig->Line & EXTI_REG_MASK) >> EXTI_REG_SHIFT);
287 linepos = (pExtiConfig->Line & EXTI_PIN_MASK);
288 maskline = (1uL << linepos);
289
290 /* 1] Get core mode : interrupt */
291 regaddr = (&EXTI->IMR1 + (EXTI_MODE_OFFSET * offset));
292 regval = *regaddr;
293
294 /* Check if selected line is enable */
295 if ((regval & maskline) != 0x00u)
296 {
297 pExtiConfig->Mode = EXTI_MODE_INTERRUPT;
298 }
299 else
300 {
301 pExtiConfig->Mode = EXTI_MODE_NONE;
302 }
303
304 /* Get event mode */
305 regaddr = (&EXTI->EMR1 + (EXTI_MODE_OFFSET * offset));
306 regval = *regaddr;
307
308 /* Check if selected line is enable */
309 if ((regval & maskline) != 0x00u)
310 {
311 pExtiConfig->Mode |= EXTI_MODE_EVENT;
312 }
313
314 /* Get default Trigger and GPIOSel configuration */
315 pExtiConfig->Trigger = EXTI_TRIGGER_NONE;
316 pExtiConfig->GPIOSel = 0x00u;
317
318 /* 2] Get trigger for configurable lines : rising */
319 if ((pExtiConfig->Line & EXTI_CONFIG) != 0x00u)
320 {
321 regaddr = (&EXTI->RTSR1 + (EXTI_CONFIG_OFFSET * offset));
322 regval = *regaddr;
323
324 /* Check if configuration of selected line is enable */
325 if ((regval & maskline) != 0x00u)
326 {
327 pExtiConfig->Trigger = EXTI_TRIGGER_RISING;
328 }
329
330 /* Get falling configuration */
331 regaddr = (&EXTI->FTSR1 + (EXTI_CONFIG_OFFSET * offset));
332 regval = *regaddr;
333
334 /* Check if configuration of selected line is enable */
335 if ((regval & maskline) != 0x00u)
336 {
337 pExtiConfig->Trigger |= EXTI_TRIGGER_FALLING;
338 }
339
340 /* Get Gpio port selection for gpio lines */
341 if ((pExtiConfig->Line & EXTI_GPIO) == EXTI_GPIO)
342 {
343 assert_param(IS_EXTI_GPIO_PIN(linepos));
344
345 regval = EXTI->EXTICR[linepos >> 2u];
346 pExtiConfig->GPIOSel = ((regval << (EXTI_EXTICR1_EXTI1_Pos * (3uL - (linepos & 0x03u)))) >> 24);
347 }
348 }
349
350 return HAL_OK;
351 }
352
353
354 /**
355 * @brief Clear whole configuration of a dedicated Exti line.
356 * @param hexti Exti handle.
357 * @retval HAL Status.
358 */
HAL_EXTI_ClearConfigLine(EXTI_HandleTypeDef * hexti)359 HAL_StatusTypeDef HAL_EXTI_ClearConfigLine(EXTI_HandleTypeDef *hexti)
360 {
361 __IO uint32_t *regaddr;
362 uint32_t regval;
363 uint32_t linepos;
364 uint32_t maskline;
365 uint32_t offset;
366
367 /* Check null pointer */
368 if (hexti == NULL)
369 {
370 return HAL_ERROR;
371 }
372
373 /* Check the parameter */
374 assert_param(IS_EXTI_LINE(hexti->Line));
375
376 /* compute line register offset and line mask */
377 offset = ((hexti->Line & EXTI_REG_MASK) >> EXTI_REG_SHIFT);
378 linepos = (hexti->Line & EXTI_PIN_MASK);
379 maskline = (1uL << linepos);
380
381 /* 1] Clear interrupt mode */
382 regaddr = (&EXTI->IMR1 + (EXTI_MODE_OFFSET * offset));
383 regval = (*regaddr & ~maskline);
384 *regaddr = regval;
385
386 /* 2] Clear event mode */
387 regaddr = (&EXTI->EMR1 + (EXTI_MODE_OFFSET * offset));
388 regval = (*regaddr & ~maskline);
389 *regaddr = regval;
390
391 /* 3] Clear triggers in case of configurable lines */
392 if ((hexti->Line & EXTI_CONFIG) != 0x00u)
393 {
394 regaddr = (&EXTI->RTSR1 + (EXTI_CONFIG_OFFSET * offset));
395 regval = (*regaddr & ~maskline);
396 *regaddr = regval;
397
398 regaddr = (&EXTI->FTSR1 + (EXTI_CONFIG_OFFSET * offset));
399 regval = (*regaddr & ~maskline);
400 *regaddr = regval;
401
402 /* Get Gpio port selection for gpio lines */
403 if ((hexti->Line & EXTI_GPIO) == EXTI_GPIO)
404 {
405 assert_param(IS_EXTI_GPIO_PIN(linepos));
406
407 regval = EXTI->EXTICR[linepos >> 2u];
408 regval &= ~(EXTI_EXTICR1_EXTI0 << (EXTI_EXTICR1_EXTI1_Pos * (linepos & 0x03u)));
409 EXTI->EXTICR[linepos >> 2u] = regval;
410 }
411 }
412
413 return HAL_OK;
414 }
415
416
417 /**
418 * @brief Register callback for a dedicaated Exti line.
419 * @param hexti Exti handle.
420 * @param CallbackID User callback identifier.
421 * This parameter can be one of @arg @ref EXTI_CallbackIDTypeDef values.
422 * @param pPendingCbfn function pointer to be stored as callback.
423 * @retval HAL Status.
424 */
HAL_EXTI_RegisterCallback(EXTI_HandleTypeDef * hexti,EXTI_CallbackIDTypeDef CallbackID,void (* pPendingCbfn)(void))425 HAL_StatusTypeDef HAL_EXTI_RegisterCallback(EXTI_HandleTypeDef *hexti, EXTI_CallbackIDTypeDef CallbackID, void (*pPendingCbfn)(void))
426 {
427 HAL_StatusTypeDef status = HAL_OK;
428
429 switch (CallbackID)
430 {
431 case HAL_EXTI_COMMON_CB_ID:
432 hexti->RisingCallback = pPendingCbfn;
433 hexti->FallingCallback = pPendingCbfn;
434 break;
435
436 case HAL_EXTI_RISING_CB_ID:
437 hexti->RisingCallback = pPendingCbfn;
438 break;
439
440 case HAL_EXTI_FALLING_CB_ID:
441 hexti->FallingCallback = pPendingCbfn;
442 break;
443
444 default:
445 status = HAL_ERROR;
446 break;
447 }
448
449 return status;
450 }
451
452
453 /**
454 * @brief Store line number as handle private field.
455 * @param hexti Exti handle.
456 * @param ExtiLine Exti line number.
457 * This parameter can be from 0 to @ref EXTI_LINE_NB.
458 * @retval HAL Status.
459 */
HAL_EXTI_GetHandle(EXTI_HandleTypeDef * hexti,uint32_t ExtiLine)460 HAL_StatusTypeDef HAL_EXTI_GetHandle(EXTI_HandleTypeDef *hexti, uint32_t ExtiLine)
461 {
462 /* Check the parameters */
463 assert_param(IS_EXTI_LINE(ExtiLine));
464
465 /* Check null pointer */
466 if (hexti == NULL)
467 {
468 return HAL_ERROR;
469 }
470 else
471 {
472 /* Store line number as handle private field */
473 hexti->Line = ExtiLine;
474
475 return HAL_OK;
476 }
477 }
478
479
480 /**
481 * @}
482 */
483
484 /** @addtogroup EXTI_Exported_Functions_Group2
485 * @brief EXTI IO functions.
486 *
487 @verbatim
488 ===============================================================================
489 ##### IO operation functions #####
490 ===============================================================================
491
492 @endverbatim
493 * @{
494 */
495
496 /**
497 * @brief Handle EXTI interrupt request.
498 * @param hexti Exti handle.
499 * @retval none.
500 */
HAL_EXTI_IRQHandler(EXTI_HandleTypeDef * hexti)501 void HAL_EXTI_IRQHandler(EXTI_HandleTypeDef *hexti)
502 {
503 __IO uint32_t *regaddr;
504 uint32_t regval;
505 uint32_t maskline;
506 uint32_t offset;
507
508 /* Compute line register offset and line mask */
509 offset = ((hexti->Line & EXTI_REG_MASK) >> EXTI_REG_SHIFT);
510 maskline = (1uL << (hexti->Line & EXTI_PIN_MASK));
511
512 /* Get rising edge pending bit */
513 regaddr = (&EXTI->RPR1 + (EXTI_CONFIG_OFFSET * offset));
514 regval = (*regaddr & maskline);
515
516 if (regval != 0x00u)
517 {
518 /* Clear pending bit */
519 *regaddr = maskline;
520
521 /* Call rising callback */
522 if (hexti->RisingCallback != NULL)
523 {
524 hexti->RisingCallback();
525 }
526 }
527
528 /* Get falling edge pending bit */
529 regaddr = (&EXTI->FPR1 + (EXTI_CONFIG_OFFSET * offset));
530 regval = (*regaddr & maskline);
531
532 if (regval != 0x00u)
533 {
534 /* Clear pending bit */
535 *regaddr = maskline;
536
537 /* Call rising callback */
538 if (hexti->FallingCallback != NULL)
539 {
540 hexti->FallingCallback();
541 }
542 }
543 }
544
545
546 /**
547 * @brief Get interrupt pending bit of a dedicated line.
548 * @param hexti Exti handle.
549 * @param Edge Specify which pending edge as to be checked.
550 * This parameter can be one of the following values:
551 * @arg @ref EXTI_TRIGGER_RISING
552 * @arg @ref EXTI_TRIGGER_FALLING
553 * @retval 1 if interrupt is pending else 0.
554 */
HAL_EXTI_GetPending(EXTI_HandleTypeDef * hexti,uint32_t Edge)555 uint32_t HAL_EXTI_GetPending(EXTI_HandleTypeDef *hexti, uint32_t Edge)
556 {
557 __IO uint32_t *regaddr;
558 uint32_t regval;
559 uint32_t linepos;
560 uint32_t maskline;
561 uint32_t offset;
562
563 /* Check parameters */
564 assert_param(IS_EXTI_LINE(hexti->Line));
565 assert_param(IS_EXTI_CONFIG_LINE(hexti->Line));
566 assert_param(IS_EXTI_PENDING_EDGE(Edge));
567
568 /* compute line register offset and line mask */
569 offset = ((hexti->Line & EXTI_REG_MASK) >> EXTI_REG_SHIFT);
570 linepos = (hexti->Line & EXTI_PIN_MASK);
571 maskline = (1uL << linepos);
572
573 if (Edge != EXTI_TRIGGER_RISING)
574 {
575 /* Get falling edge pending bit */
576 regaddr = (&EXTI->FPR1 + (EXTI_CONFIG_OFFSET * offset));
577 }
578 else
579 {
580 /* Get rising edge pending bit */
581 regaddr = (&EXTI->RPR1 + (EXTI_CONFIG_OFFSET * offset));
582 }
583
584 /* return 1 if bit is set else 0 */
585 regval = ((*regaddr & maskline) >> linepos);
586 return regval;
587 }
588
589
590 /**
591 * @brief Clear interrupt pending bit of a dedicated line.
592 * @param hexti Exti handle.
593 * @param Edge Specify which pending edge as to be clear.
594 * This parameter can be one of the following values:
595 * @arg @ref EXTI_TRIGGER_RISING
596 * @arg @ref EXTI_TRIGGER_FALLING
597 * @retval None.
598 */
HAL_EXTI_ClearPending(EXTI_HandleTypeDef * hexti,uint32_t Edge)599 void HAL_EXTI_ClearPending(EXTI_HandleTypeDef *hexti, uint32_t Edge)
600 {
601 __IO uint32_t *regaddr;
602 uint32_t maskline;
603 uint32_t offset;
604
605 /* Check parameters */
606 assert_param(IS_EXTI_LINE(hexti->Line));
607 assert_param(IS_EXTI_CONFIG_LINE(hexti->Line));
608 assert_param(IS_EXTI_PENDING_EDGE(Edge));
609
610 /* compute line register offset and line mask */
611 offset = ((hexti->Line & EXTI_REG_MASK) >> EXTI_REG_SHIFT);
612 maskline = (1uL << (hexti->Line & EXTI_PIN_MASK));
613
614 if (Edge != EXTI_TRIGGER_RISING)
615 {
616 /* Get falling edge pending register address */
617 regaddr = (&EXTI->FPR1 + (EXTI_CONFIG_OFFSET * offset));
618 }
619 else
620 {
621 /* Get falling edge pending register address */
622 regaddr = (&EXTI->RPR1 + (EXTI_CONFIG_OFFSET * offset));
623 }
624
625 /* Clear Pending bit */
626 *regaddr = maskline;
627 }
628
629
630 /**
631 * @brief Generate a software interrupt for a dedicated line.
632 * @param hexti Exti handle.
633 * @retval None.
634 */
HAL_EXTI_GenerateSWI(EXTI_HandleTypeDef * hexti)635 void HAL_EXTI_GenerateSWI(EXTI_HandleTypeDef *hexti)
636 {
637 __IO uint32_t *regaddr;
638 uint32_t maskline;
639 uint32_t offset;
640
641 /* Check parameterd */
642 assert_param(IS_EXTI_LINE(hexti->Line));
643 assert_param(IS_EXTI_CONFIG_LINE(hexti->Line));
644
645 /* compute line register offset and line mask */
646 offset = ((hexti->Line & EXTI_REG_MASK) >> EXTI_REG_SHIFT);
647 maskline = (1uL << (hexti->Line & EXTI_PIN_MASK));
648
649 regaddr = (&EXTI->SWIER1 + (EXTI_CONFIG_OFFSET * offset));
650 *regaddr = maskline;
651 }
652
653
654 /**
655 * @}
656 */
657
658 /**
659 * @}
660 */
661
662 #endif /* HAL_EXTI_MODULE_ENABLED */
663 /**
664 * @}
665 */
666
667 /**
668 * @}
669 */
670
671