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