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