1 /**
2 ******************************************************************************
3 * @file stm32f3xx_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 * + Initialization and de-initialization functions
9 * + IO operation functions
10 *
11 ******************************************************************************
12 * @attention
13 *
14 * Copyright (c) 2019 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 /* Includes ------------------------------------------------------------------*/
86 #include "stm32f3xx_hal.h"
87
88 /** @addtogroup STM32F3xx_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 0x08u /* 0x20: 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->RTSR + (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->FTSR + (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 = SYSCFG->EXTICR[linepos >> 2u];
215 regval &= ~(SYSCFG_EXTICR1_EXTI0 << (SYSCFG_EXTICR1_EXTI1_Pos * (linepos & 0x03u)));
216 regval |= (pExtiConfig->GPIOSel << (SYSCFG_EXTICR1_EXTI1_Pos * (linepos & 0x03u)));
217 SYSCFG->EXTICR[linepos >> 2u] = regval;
218 }
219 }
220
221 /* Configure interrupt mode : read current mode */
222 regaddr = (&EXTI->IMR + (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->EMR + (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 * @brief Get configuration of a dedicated Exti line.
260 * @param hexti Exti handle.
261 * @param pExtiConfig Pointer on structure to store Exti configuration.
262 * @retval HAL Status.
263 */
HAL_EXTI_GetConfigLine(EXTI_HandleTypeDef * hexti,EXTI_ConfigTypeDef * pExtiConfig)264 HAL_StatusTypeDef HAL_EXTI_GetConfigLine(EXTI_HandleTypeDef *hexti, EXTI_ConfigTypeDef *pExtiConfig)
265 {
266 __IO uint32_t *regaddr;
267 uint32_t regval;
268 uint32_t linepos;
269 uint32_t maskline;
270 uint32_t offset;
271
272 /* Check null pointer */
273 if ((hexti == NULL) || (pExtiConfig == NULL))
274 {
275 return HAL_ERROR;
276 }
277
278 /* Check the parameter */
279 assert_param(IS_EXTI_LINE(hexti->Line));
280
281 /* Store handle line number to configuration structure */
282 pExtiConfig->Line = hexti->Line;
283
284 /* compute line register offset and line mask */
285 offset = ((pExtiConfig->Line & EXTI_REG_MASK) >> EXTI_REG_SHIFT);
286 linepos = (pExtiConfig->Line & EXTI_PIN_MASK);
287 maskline = (1uL << linepos);
288
289 /* 1] Get core mode : interrupt */
290 regaddr = (&EXTI->IMR + (EXTI_MODE_OFFSET * offset));
291 regval = *regaddr;
292
293 /* Check if selected line is enable */
294 if ((regval & maskline) != 0x00u)
295 {
296 pExtiConfig->Mode = EXTI_MODE_INTERRUPT;
297 }
298 else
299 {
300 pExtiConfig->Mode = EXTI_MODE_NONE;
301 }
302
303 /* Get event mode */
304 regaddr = (&EXTI->EMR + (EXTI_MODE_OFFSET * offset));
305 regval = *regaddr;
306
307 /* Check if selected line is enable */
308 if ((regval & maskline) != 0x00u)
309 {
310 pExtiConfig->Mode |= EXTI_MODE_EVENT;
311 }
312
313 /* Get default Trigger and GPIOSel configuration */
314 pExtiConfig->Trigger = EXTI_TRIGGER_NONE;
315 pExtiConfig->GPIOSel = 0x00u;
316
317 /* 2] Get trigger for configurable lines : rising */
318 if ((pExtiConfig->Line & EXTI_CONFIG) != 0x00u)
319 {
320 regaddr = (&EXTI->RTSR + (EXTI_CONFIG_OFFSET * offset));
321 regval = *regaddr;
322
323 /* Check if configuration of selected line is enable */
324 if ((regval & maskline) != 0x00u)
325 {
326 pExtiConfig->Trigger = EXTI_TRIGGER_RISING;
327 }
328
329 /* Get falling configuration */
330 regaddr = (&EXTI->FTSR + (EXTI_CONFIG_OFFSET * offset));
331 regval = *regaddr;
332
333 /* Check if configuration of selected line is enable */
334 if ((regval & maskline) != 0x00u)
335 {
336 pExtiConfig->Trigger |= EXTI_TRIGGER_FALLING;
337 }
338
339 /* Get Gpio port selection for gpio lines */
340 if ((pExtiConfig->Line & EXTI_GPIO) == EXTI_GPIO)
341 {
342 assert_param(IS_EXTI_GPIO_PIN(linepos));
343
344 regval = SYSCFG->EXTICR[linepos >> 2u];
345 pExtiConfig->GPIOSel = (regval >> (SYSCFG_EXTICR1_EXTI1_Pos * (linepos & 0x03u))) & SYSCFG_EXTICR1_EXTI0;
346 }
347 }
348
349 return HAL_OK;
350 }
351
352 /**
353 * @brief Clear whole configuration of a dedicated Exti line.
354 * @param hexti Exti handle.
355 * @retval HAL Status.
356 */
HAL_EXTI_ClearConfigLine(EXTI_HandleTypeDef * hexti)357 HAL_StatusTypeDef HAL_EXTI_ClearConfigLine(EXTI_HandleTypeDef *hexti)
358 {
359 __IO uint32_t *regaddr;
360 uint32_t regval;
361 uint32_t linepos;
362 uint32_t maskline;
363 uint32_t offset;
364
365 /* Check null pointer */
366 if (hexti == NULL)
367 {
368 return HAL_ERROR;
369 }
370
371 /* Check the parameter */
372 assert_param(IS_EXTI_LINE(hexti->Line));
373
374 /* compute line register offset and line mask */
375 offset = ((hexti->Line & EXTI_REG_MASK) >> EXTI_REG_SHIFT);
376 linepos = (hexti->Line & EXTI_PIN_MASK);
377 maskline = (1uL << linepos);
378
379 /* 1] Clear interrupt mode */
380 regaddr = (&EXTI->IMR + (EXTI_MODE_OFFSET * offset));
381 regval = (*regaddr & ~maskline);
382 *regaddr = regval;
383
384 /* 2] Clear event mode */
385 regaddr = (&EXTI->EMR + (EXTI_MODE_OFFSET * offset));
386 regval = (*regaddr & ~maskline);
387 *regaddr = regval;
388
389 /* 3] Clear triggers in case of configurable lines */
390 if ((hexti->Line & EXTI_CONFIG) != 0x00u)
391 {
392 regaddr = (&EXTI->RTSR + (EXTI_CONFIG_OFFSET * offset));
393 regval = (*regaddr & ~maskline);
394 *regaddr = regval;
395
396 regaddr = (&EXTI->FTSR + (EXTI_CONFIG_OFFSET * offset));
397 regval = (*regaddr & ~maskline);
398 *regaddr = regval;
399
400 /* Get Gpio port selection for gpio lines */
401 if ((hexti->Line & EXTI_GPIO) == EXTI_GPIO)
402 {
403 assert_param(IS_EXTI_GPIO_PIN(linepos));
404
405 regval = SYSCFG->EXTICR[linepos >> 2u];
406 regval &= ~(SYSCFG_EXTICR1_EXTI0 << (SYSCFG_EXTICR1_EXTI1_Pos * (linepos & 0x03u)));
407 SYSCFG->EXTICR[linepos >> 2u] = regval;
408 }
409 }
410
411 return HAL_OK;
412 }
413
414 /**
415 * @brief Register callback for a dedicated Exti line.
416 * @param hexti Exti handle.
417 * @param CallbackID User callback identifier.
418 * This parameter can be one of @arg @ref EXTI_CallbackIDTypeDef values.
419 * @param pPendingCbfn function pointer to be stored as callback.
420 * @retval HAL Status.
421 */
HAL_EXTI_RegisterCallback(EXTI_HandleTypeDef * hexti,EXTI_CallbackIDTypeDef CallbackID,void (* pPendingCbfn)(void))422 HAL_StatusTypeDef HAL_EXTI_RegisterCallback(EXTI_HandleTypeDef *hexti, EXTI_CallbackIDTypeDef CallbackID, void (*pPendingCbfn)(void))
423 {
424 HAL_StatusTypeDef status = HAL_OK;
425
426 switch (CallbackID)
427 {
428 case HAL_EXTI_COMMON_CB_ID:
429 hexti->PendingCallback = pPendingCbfn;
430 break;
431
432 default:
433 status = HAL_ERROR;
434 break;
435 }
436
437 return status;
438 }
439
440 /**
441 * @brief Store line number as handle private field.
442 * @param hexti Exti handle.
443 * @param ExtiLine Exti line number.
444 * This parameter can be from 0 to @ref EXTI_LINE_NB.
445 * @retval HAL Status.
446 */
HAL_EXTI_GetHandle(EXTI_HandleTypeDef * hexti,uint32_t ExtiLine)447 HAL_StatusTypeDef HAL_EXTI_GetHandle(EXTI_HandleTypeDef *hexti, uint32_t ExtiLine)
448 {
449 /* Check the parameters */
450 assert_param(IS_EXTI_LINE(ExtiLine));
451
452 /* Check null pointer */
453 if (hexti == NULL)
454 {
455 return HAL_ERROR;
456 }
457 else
458 {
459 /* Store line number as handle private field */
460 hexti->Line = ExtiLine;
461
462 return HAL_OK;
463 }
464 }
465
466 /**
467 * @}
468 */
469
470 /** @addtogroup EXTI_Exported_Functions_Group2
471 * @brief EXTI IO functions.
472 *
473 @verbatim
474 ===============================================================================
475 ##### IO operation functions #####
476 ===============================================================================
477
478 @endverbatim
479 * @{
480 */
481
482 /**
483 * @brief Handle EXTI interrupt request.
484 * @param hexti Exti handle.
485 * @retval none.
486 */
HAL_EXTI_IRQHandler(EXTI_HandleTypeDef * hexti)487 void HAL_EXTI_IRQHandler(EXTI_HandleTypeDef *hexti)
488 {
489 __IO uint32_t *regaddr;
490 uint32_t regval;
491 uint32_t maskline;
492 uint32_t offset;
493
494 /* Compute line register offset and line mask */
495 offset = ((hexti->Line & EXTI_REG_MASK) >> EXTI_REG_SHIFT);
496 maskline = (1uL << (hexti->Line & EXTI_PIN_MASK));
497
498 /* Get pending bit */
499 regaddr = (&EXTI->PR + (EXTI_CONFIG_OFFSET * offset));
500 regval = (*regaddr & maskline);
501
502 if (regval != 0x00u)
503 {
504 /* Clear pending bit */
505 EXTI->PR = maskline;
506
507 /* Call callback */
508 if (hexti->PendingCallback != NULL)
509 {
510 hexti->PendingCallback();
511 }
512 }
513 }
514
515 /**
516 * @brief Get interrupt pending bit of a dedicated line.
517 * @param hexti Exti handle.
518 * @param Edge Specify which pending edge as to be checked.
519 * This parameter can be one of the following values:
520 * @arg @ref EXTI_TRIGGER_RISING_FALLING
521 * This parameter is kept for compatibility with other series.
522 * @retval 1 if interrupt is pending else 0.
523 */
HAL_EXTI_GetPending(EXTI_HandleTypeDef * hexti,uint32_t Edge)524 uint32_t HAL_EXTI_GetPending(EXTI_HandleTypeDef *hexti, uint32_t Edge)
525 {
526 __IO uint32_t *regaddr;
527 uint32_t regval;
528 uint32_t linepos;
529 uint32_t maskline;
530 uint32_t offset;
531
532 /* Check parameters */
533 assert_param(IS_EXTI_LINE(hexti->Line));
534 assert_param(IS_EXTI_CONFIG_LINE(hexti->Line));
535 assert_param(IS_EXTI_PENDING_EDGE(Edge));
536
537 /* compute line register offset and line mask */
538 offset = ((hexti->Line & EXTI_REG_MASK) >> EXTI_REG_SHIFT);
539 linepos = (hexti->Line & EXTI_PIN_MASK);
540 maskline = (1uL << linepos);
541
542 /* Get pending bit */
543 regaddr = (&EXTI->PR + (EXTI_CONFIG_OFFSET * offset));
544 /* return 1 if bit is set else 0 */
545 regval = ((*regaddr & maskline) >> linepos);
546 return regval;
547 }
548
549 /**
550 * @brief Clear interrupt pending bit of a dedicated line.
551 * @param hexti Exti handle.
552 * @param Edge Specify which pending edge as to be clear.
553 * This parameter can be one of the following values:
554 * @arg @ref EXTI_TRIGGER_RISING_FALLING
555 * This parameter is kept for compatibility with other series.
556 * @retval None.
557 */
HAL_EXTI_ClearPending(EXTI_HandleTypeDef * hexti,uint32_t Edge)558 void HAL_EXTI_ClearPending(EXTI_HandleTypeDef *hexti, uint32_t Edge)
559 {
560 __IO uint32_t *regaddr;
561 uint32_t maskline;
562 uint32_t offset;
563
564 /* Check parameters */
565 assert_param(IS_EXTI_LINE(hexti->Line));
566 assert_param(IS_EXTI_CONFIG_LINE(hexti->Line));
567 assert_param(IS_EXTI_PENDING_EDGE(Edge));
568
569 /* compute line register offset and line mask */
570 offset = ((hexti->Line & EXTI_REG_MASK) >> EXTI_REG_SHIFT);
571 maskline = (1uL << (hexti->Line & EXTI_PIN_MASK));
572
573 /* Get pending bit */
574 regaddr = (&EXTI->PR + (EXTI_CONFIG_OFFSET * offset));
575
576 /* Clear Pending bit */
577 *regaddr = maskline;
578 }
579
580 /**
581 * @brief Generate a software interrupt for a dedicated line.
582 * @param hexti Exti handle.
583 * @retval None.
584 */
HAL_EXTI_GenerateSWI(EXTI_HandleTypeDef * hexti)585 void HAL_EXTI_GenerateSWI(EXTI_HandleTypeDef *hexti)
586 {
587 __IO uint32_t *regaddr;
588 uint32_t maskline;
589 uint32_t offset;
590
591 /* Check parameters */
592 assert_param(IS_EXTI_LINE(hexti->Line));
593 assert_param(IS_EXTI_CONFIG_LINE(hexti->Line));
594
595 /* compute line register offset and line mask */
596 offset = ((hexti->Line & EXTI_REG_MASK) >> EXTI_REG_SHIFT);
597 maskline = (1uL << (hexti->Line & EXTI_PIN_MASK));
598
599 regaddr = (&EXTI->SWIER + (EXTI_CONFIG_OFFSET * offset));
600 *regaddr = maskline;
601 }
602
603 /**
604 * @}
605 */
606
607 /**
608 * @}
609 */
610
611 #endif /* HAL_EXTI_MODULE_ENABLED */
612 /**
613 * @}
614 */
615
616 /**
617 * @}
618 */
619
620