1 /**
2 ******************************************************************************
3 * @file stm32wlxx_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 * @attention
12 *
13 * Copyright (c) 2020 STMicroelectronics.
14 * All rights reserved.
15 *
16 * This software is licensed under terms that can be found in the LICENSE file
17 * in the root directory of this software component.
18 * If no LICENSE file comes with this software, it is provided AS-IS.
19 *
20 ******************************************************************************
21 @verbatim
22 ==============================================================================
23 ##### EXTI Peripheral features #####
24 ==============================================================================
25 [..]
26 (+) Each Exti line can be configured within this driver.
27
28 (+) Exti line can be configured in 3 different modes
29 (++) Interrupt
30 (++) Event
31 (++) Both of them
32
33 (+) Configurable Exti lines can be configured with 3 different triggers
34 (++) Rising
35 (++) Falling
36 (++) Both of them
37
38 (+) When set in interrupt mode, configurable Exti lines have two diffenrents
39 interrupt pending registers which allow to distinguish which transition
40 occurs:
41 (++) Rising edge pending interrupt
42 (++) Falling
43
44 (+) Exti lines 0 to 15 are linked to gpio pin number 0 to 15. Gpio port can
45 be selected through multiplexer.
46
47 ##### How to use this driver #####
48 ==============================================================================
49 [..]
50
51 (#) Configure the EXTI line using HAL_EXTI_SetConfigLine().
52 (++) Choose the interrupt line number by setting "Line" member from
53 EXTI_ConfigTypeDef structure.
54 (++) Configure the interrupt and/or event mode using "Mode" member from
55 EXTI_ConfigTypeDef structure.
56 (++) For configurable lines, configure rising and/or falling trigger
57 "Trigger" member from EXTI_ConfigTypeDef structure.
58 (++) For Exti lines linked to gpio, choose gpio port using "GPIOSel"
59 member from GPIO_InitTypeDef structure.
60
61 (#) Get current Exti configuration of a dedicated line using
62 HAL_EXTI_GetConfigLine().
63 (++) Provide exiting handle as parameter.
64 (++) Provide pointer on EXTI_ConfigTypeDef structure as second parameter.
65
66 (#) Clear Exti configuration of a dedicated line using HAL_EXTI_GetConfigLine().
67 (++) Provide exiting handle as parameter.
68
69 (#) Register callback to treat Exti interrupts using HAL_EXTI_RegisterCallback().
70 (++) Provide exiting handle as first parameter.
71 (++) Provide which callback will be registered using one value from
72 EXTI_CallbackIDTypeDef.
73 (++) Provide callback function pointer.
74
75 (#) Get interrupt pending bit using HAL_EXTI_GetPending().
76
77 (#) Clear interrupt pending bit using HAL_EXTI_GetPending().
78
79 (#) Generate software interrupt using HAL_EXTI_GenerateSWI().
80
81 @endverbatim
82 ******************************************************************************
83 */
84
85 /* Includes ------------------------------------------------------------------*/
86 #include "stm32wlxx_hal.h"
87
88 /** @addtogroup STM32WLxx_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 0x04u /* 0x10: 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->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 #if defined(DUAL_CORE) && defined(CORE_CM0PLUS)
223 regaddr = (&EXTI->C2IMR1 + (EXTI_MODE_OFFSET * offset));
224 #else
225 regaddr = (&EXTI->IMR1 + (EXTI_MODE_OFFSET * offset));
226 #endif /* DUAL_CORE && CORE_CM0PLUS */
227 regval = *regaddr;
228
229 /* Mask or set line */
230 if ((pExtiConfig->Mode & EXTI_MODE_INTERRUPT) != 0x00u)
231 {
232 regval |= maskline;
233 }
234 else
235 {
236 regval &= ~maskline;
237 }
238
239 /* Store interrupt mode */
240 *regaddr = regval;
241
242 /* Configure event mode : read current mode */
243 #if defined(DUAL_CORE) && defined(CORE_CM0PLUS)
244 regaddr = (&EXTI->C2EMR1 + (EXTI_MODE_OFFSET * offset));
245 #else
246 regaddr = (&EXTI->EMR1 + (EXTI_MODE_OFFSET * offset));
247 #endif /* DUAL_CORE && CORE_CM0PLUS */
248 regval = *regaddr;
249
250 /* Mask or set line */
251 if ((pExtiConfig->Mode & EXTI_MODE_EVENT) != 0x00u)
252 {
253 /* The event mode cannot be configured if the line does not support it */
254 assert_param(IS_EXTI_EVENT_PRESENT(pExtiConfig->Line));
255 regval |= maskline;
256 }
257 else
258 {
259 regval &= ~maskline;
260 }
261
262 /* Store event mode */
263 *regaddr = regval;
264
265 return HAL_OK;
266 }
267
268
269 /**
270 * @brief Get configuration of a dedicated Exti line.
271 * @param hexti Exti handle.
272 * @param pExtiConfig Pointer on structure to store Exti configuration.
273 * @retval HAL Status.
274 */
HAL_EXTI_GetConfigLine(EXTI_HandleTypeDef * hexti,EXTI_ConfigTypeDef * pExtiConfig)275 HAL_StatusTypeDef HAL_EXTI_GetConfigLine(EXTI_HandleTypeDef *hexti, EXTI_ConfigTypeDef *pExtiConfig)
276 {
277 __IO uint32_t *regaddr;
278 uint32_t regval;
279 uint32_t linepos;
280 uint32_t maskline;
281 uint32_t offset;
282
283 /* Check null pointer */
284 if ((hexti == NULL) || (pExtiConfig == NULL))
285 {
286 return HAL_ERROR;
287 }
288
289 /* Check the parameter */
290 assert_param(IS_EXTI_LINE(hexti->Line));
291
292 /* Store handle line number to configuration structure */
293 pExtiConfig->Line = hexti->Line;
294
295 /* compute line register offset and line mask */
296 offset = ((pExtiConfig->Line & EXTI_REG_MASK) >> EXTI_REG_SHIFT);
297 linepos = (pExtiConfig->Line & EXTI_PIN_MASK);
298 maskline = (1uL << linepos);
299
300 /* 1] Get core mode : interrupt */
301 #if defined(DUAL_CORE) && defined(CORE_CM0PLUS)
302 regaddr = (&EXTI->C2IMR1 + (EXTI_MODE_OFFSET * offset));
303 #else
304 regaddr = (&EXTI->IMR1 + (EXTI_MODE_OFFSET * offset));
305 #endif /* DUAL_CORE && CORE_CM0PLUS */
306 regval = *regaddr;
307
308 /* Check if selected line is enable */
309 if ((regval & maskline) != 0x00u)
310 {
311 pExtiConfig->Mode = EXTI_MODE_INTERRUPT;
312 }
313 else
314 {
315 pExtiConfig->Mode = EXTI_MODE_NONE;
316 }
317
318 /* Get event mode */
319 #if defined(DUAL_CORE) && defined(CORE_CM0PLUS)
320 regaddr = (&EXTI->C2EMR1 + (EXTI_MODE_OFFSET * offset));
321 #else
322 regaddr = (&EXTI->EMR1 + (EXTI_MODE_OFFSET * offset));
323 #endif /* DUAL_CORE && CORE_CM0PLUS */
324 regval = *regaddr;
325
326 /* Check if selected line is enable */
327 if ((regval & maskline) != 0x00u)
328 {
329 pExtiConfig->Mode |= EXTI_MODE_EVENT;
330 }
331
332 /* Get default Trigger and GPIOSel configuration */
333 pExtiConfig->Trigger = EXTI_TRIGGER_NONE;
334 pExtiConfig->GPIOSel = 0x00u;
335
336 /* 2] Get trigger for configurable lines : rising */
337 if ((pExtiConfig->Line & EXTI_CONFIG) != 0x00u)
338 {
339 regaddr = (&EXTI->RTSR1 + (EXTI_CONFIG_OFFSET * offset));
340 regval = *regaddr;
341
342 /* Check if configuration of selected line is enable */
343 if ((regval & maskline) != 0x00u)
344 {
345 pExtiConfig->Trigger = EXTI_TRIGGER_RISING;
346 }
347
348 /* Get falling configuration */
349 regaddr = (&EXTI->FTSR1 + (EXTI_CONFIG_OFFSET * offset));
350 regval = *regaddr;
351
352 /* Check if configuration of selected line is enable */
353 if ((regval & maskline) != 0x00u)
354 {
355 pExtiConfig->Trigger |= EXTI_TRIGGER_FALLING;
356 }
357
358 /* Get Gpio port selection for gpio lines */
359 if ((pExtiConfig->Line & EXTI_GPIO) == EXTI_GPIO)
360 {
361 regval = SYSCFG->EXTICR[linepos >> 2u];
362 pExtiConfig->GPIOSel = (regval >> (SYSCFG_EXTICR1_EXTI1_Pos * (linepos & 0x03u))) & SYSCFG_EXTICR1_EXTI0;
363 }
364 }
365
366 return HAL_OK;
367 }
368
369
370 /**
371 * @brief Clear whole configuration of a dedicated Exti line.
372 * @param hexti Exti handle.
373 * @retval HAL Status.
374 */
HAL_EXTI_ClearConfigLine(EXTI_HandleTypeDef * hexti)375 HAL_StatusTypeDef HAL_EXTI_ClearConfigLine(EXTI_HandleTypeDef *hexti)
376 {
377 __IO uint32_t *regaddr;
378 uint32_t regval;
379 uint32_t linepos;
380 uint32_t maskline;
381 uint32_t offset;
382
383 /* Check null pointer */
384 if (hexti == NULL)
385 {
386 return HAL_ERROR;
387 }
388
389 /* Check the parameter */
390 assert_param(IS_EXTI_LINE(hexti->Line));
391
392 /* compute line register offset and line mask */
393 offset = ((hexti->Line & EXTI_REG_MASK) >> EXTI_REG_SHIFT);
394 linepos = (hexti->Line & EXTI_PIN_MASK);
395 maskline = (1uL << linepos);
396
397 /* 1] Clear interrupt mode */
398 #if defined(DUAL_CORE) && defined(CORE_CM0PLUS)
399 regaddr = (&EXTI->C2IMR1 + (EXTI_MODE_OFFSET * offset));
400 #else
401 regaddr = (&EXTI->IMR1 + (EXTI_MODE_OFFSET * offset));
402 #endif /* DUAL_CORE && CORE_CM0PLUS */
403 regval = (*regaddr & ~maskline);
404 *regaddr = regval;
405
406 /* 2] Clear event mode */
407 #if defined(DUAL_CORE) && defined(CORE_CM0PLUS)
408 regaddr = (&EXTI->C2EMR1 + (EXTI_MODE_OFFSET * offset));
409 #else
410 regaddr = (&EXTI->EMR1 + (EXTI_MODE_OFFSET * offset));
411 #endif /* DUAL_CORE && CORE_CM0PLUS */
412 regval = (*regaddr & ~maskline);
413 *regaddr = regval;
414
415 /* 3] Clear triggers in case of configurable lines */
416 if ((hexti->Line & EXTI_CONFIG) != 0x00u)
417 {
418 regaddr = (&EXTI->RTSR1 + (EXTI_CONFIG_OFFSET * offset));
419 regval = (*regaddr & ~maskline);
420 *regaddr = regval;
421
422 regaddr = (&EXTI->FTSR1 + (EXTI_CONFIG_OFFSET * offset));
423 regval = (*regaddr & ~maskline);
424 *regaddr = regval;
425
426 /* Get Gpio port selection for gpio lines */
427 if ((hexti->Line & EXTI_GPIO) == EXTI_GPIO)
428 {
429 regval = SYSCFG->EXTICR[linepos >> 2u];
430 regval &= ~(SYSCFG_EXTICR1_EXTI0 << (SYSCFG_EXTICR1_EXTI1_Pos * (linepos & 0x03u)));
431 SYSCFG->EXTICR[linepos >> 2u] = regval;
432 }
433 }
434
435 return HAL_OK;
436 }
437
438
439 /**
440 * @brief Register callback for a dedicaated Exti line.
441 * @param hexti Exti handle.
442 * @param CallbackID User callback identifier.
443 * This parameter can be one of @arg @ref EXTI_CallbackIDTypeDef values.
444 * @param pPendingCbfn function pointer to be stored as callback.
445 * @retval HAL Status.
446 */
HAL_EXTI_RegisterCallback(EXTI_HandleTypeDef * hexti,EXTI_CallbackIDTypeDef CallbackID,void (* pPendingCbfn)(void))447 HAL_StatusTypeDef HAL_EXTI_RegisterCallback(EXTI_HandleTypeDef *hexti, EXTI_CallbackIDTypeDef CallbackID, void (*pPendingCbfn)(void))
448 {
449 HAL_StatusTypeDef status = HAL_OK;
450
451 switch (CallbackID)
452 {
453 case HAL_EXTI_COMMON_CB_ID:
454 hexti->PendingCallback = pPendingCbfn;
455 break;
456
457 default:
458 status = HAL_ERROR;
459 break;
460 }
461
462 return status;
463 }
464
465
466 /**
467 * @brief Store line number as handle private field.
468 * @param hexti Exti handle.
469 * @param ExtiLine Exti line number.
470 * This parameter can be from 0 to @ref EXTI_LINE_NB.
471 * @retval HAL Status.
472 */
HAL_EXTI_GetHandle(EXTI_HandleTypeDef * hexti,uint32_t ExtiLine)473 HAL_StatusTypeDef HAL_EXTI_GetHandle(EXTI_HandleTypeDef *hexti, uint32_t ExtiLine)
474 {
475 /* Check the parameters */
476 assert_param(IS_EXTI_LINE(ExtiLine));
477
478 /* Check null pointer */
479 if (hexti == NULL)
480 {
481 return HAL_ERROR;
482 }
483 else
484 {
485 /* Store line number as handle private field */
486 hexti->Line = ExtiLine;
487
488 return HAL_OK;
489 }
490 }
491
492
493 /**
494 * @}
495 */
496
497 /** @addtogroup EXTI_Exported_Functions_Group2
498 * @brief EXTI IO functions.
499 *
500 @verbatim
501 ===============================================================================
502 ##### IO operation functions #####
503 ===============================================================================
504
505 @endverbatim
506 * @{
507 */
508
509 /**
510 * @brief Handle EXTI interrupt request.
511 * @param hexti Exti handle.
512 * @retval none.
513 */
HAL_EXTI_IRQHandler(EXTI_HandleTypeDef * hexti)514 void HAL_EXTI_IRQHandler(EXTI_HandleTypeDef *hexti)
515 {
516 __IO uint32_t *regaddr;
517 uint32_t regval;
518 uint32_t maskline;
519 uint32_t offset;
520
521 /* Compute line register offset and line mask */
522 offset = ((hexti->Line & EXTI_REG_MASK) >> EXTI_REG_SHIFT);
523 maskline = (1uL << (hexti->Line & EXTI_PIN_MASK));
524
525 /* Get pending bit */
526 regaddr = (&EXTI->PR1 + (EXTI_CONFIG_OFFSET * offset));
527 regval = (*regaddr & maskline);
528
529 if (regval != 0x00u)
530 {
531 /* Clear pending bit */
532 *regaddr = maskline;
533
534 /* Call callback */
535 if (hexti->PendingCallback != NULL)
536 {
537 hexti->PendingCallback();
538 }
539 }
540 }
541
542
543 /**
544 * @brief Get interrupt pending bit of a dedicated line.
545 * @param hexti Exti handle.
546 * @param Edge Specify which pending edge as to be checked.
547 * This parameter can be one of the following values:
548 * @arg @ref EXTI_TRIGGER_RISING_FALLING
549 * This parameter is kept for compatibility with other series.
550 * @retval 1 if interrupt is pending else 0.
551 */
HAL_EXTI_GetPending(EXTI_HandleTypeDef * hexti,uint32_t Edge)552 uint32_t HAL_EXTI_GetPending(EXTI_HandleTypeDef *hexti, uint32_t Edge)
553 {
554 __IO uint32_t *regaddr;
555 uint32_t regval;
556 uint32_t linepos;
557 uint32_t maskline;
558 uint32_t offset;
559
560 /* Check parameters */
561 assert_param(IS_EXTI_LINE(hexti->Line));
562 assert_param(IS_EXTI_CONFIG_LINE(hexti->Line));
563 assert_param(IS_EXTI_PENDING_EDGE(Edge));
564
565 /* compute line register offset and line mask */
566 offset = ((hexti->Line & EXTI_REG_MASK) >> EXTI_REG_SHIFT);
567 linepos = (hexti->Line & EXTI_PIN_MASK);
568 maskline = (1uL << linepos);
569
570 /* Get pending bit */
571 regaddr = (&EXTI->PR1 + (EXTI_CONFIG_OFFSET * offset));
572
573 /* return 1 if bit is set else 0 */
574 regval = ((*regaddr & maskline) >> linepos);
575 return regval;
576 }
577
578
579 /**
580 * @brief Clear interrupt pending bit of a dedicated line.
581 * @param hexti Exti handle.
582 * @param Edge Specify which pending edge as to be clear.
583 * This parameter can be one of the following values:
584 * @arg @ref EXTI_TRIGGER_RISING_FALLING
585 * This parameter is kept for compatibility with other series.
586 * @retval None.
587 */
HAL_EXTI_ClearPending(EXTI_HandleTypeDef * hexti,uint32_t Edge)588 void HAL_EXTI_ClearPending(EXTI_HandleTypeDef *hexti, uint32_t Edge)
589 {
590 __IO uint32_t *regaddr;
591 uint32_t maskline;
592 uint32_t offset;
593
594 /* Check parameters */
595 assert_param(IS_EXTI_LINE(hexti->Line));
596 assert_param(IS_EXTI_CONFIG_LINE(hexti->Line));
597 assert_param(IS_EXTI_PENDING_EDGE(Edge));
598
599 /* compute line register offset and line mask */
600 offset = ((hexti->Line & EXTI_REG_MASK) >> EXTI_REG_SHIFT);
601 maskline = (1uL << (hexti->Line & EXTI_PIN_MASK));
602
603 /* Get pending register address */
604 regaddr = (&EXTI->PR1 + (EXTI_CONFIG_OFFSET * offset));
605
606 /* Clear Pending bit */
607 *regaddr = maskline;
608 }
609
610 /**
611 * @brief Generate a software interrupt for a dedicated line.
612 * @param hexti Exti handle.
613 * @retval None.
614 */
HAL_EXTI_GenerateSWI(EXTI_HandleTypeDef * hexti)615 void HAL_EXTI_GenerateSWI(EXTI_HandleTypeDef *hexti)
616 {
617 __IO uint32_t *regaddr;
618 uint32_t maskline;
619 uint32_t offset;
620
621 /* Check parameters */
622 assert_param(IS_EXTI_LINE(hexti->Line));
623 assert_param(IS_EXTI_CONFIG_LINE(hexti->Line));
624
625 /* compute line register offset and line mask */
626 offset = ((hexti->Line & EXTI_REG_MASK) >> EXTI_REG_SHIFT);
627 maskline = (1uL << (hexti->Line & EXTI_PIN_MASK));
628
629 regaddr = (&EXTI->SWIER1 + (EXTI_CONFIG_OFFSET * offset));
630 *regaddr = maskline;
631 }
632
633
634 /**
635 * @}
636 */
637
638 /**
639 * @}
640 */
641
642 #endif /* HAL_EXTI_MODULE_ENABLED */
643 /**
644 * @}
645 */
646
647 /**
648 * @}
649 */
650