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