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