1 /**
2   ******************************************************************************
3   * @file    stm32l0xx_hal_gpio.c
4   * @author  MCD Application Team
5   * @brief   GPIO HAL module driver.
6   *          This file provides firmware functions to manage the following
7   *          functionalities of the General Purpose Input/Output (GPIO) peripheral:
8   *           + Initialization and de-initialization functions
9   *           + IO operation functions
10   *
11   ******************************************************************************
12   * @attention
13   *
14   * Copyright (c) 2016 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                     ##### GPIO Peripheral features #####
25   ==============================================================================
26   [..]
27     (+) Each port bit of the general-purpose I/O (GPIO) ports can be individually
28   configured by software in several modes:
29         (++) Input mode
30         (++) Analog mode
31         (++) Output mode
32         (++) Alternate function mode
33         (++) External interrupt/event lines
34 
35     (+) During and just after reset, the alternate functions and external interrupt
36   lines are not active and the I/O ports are configured in input floating mode.
37 
38     (+) All GPIO pins have weak internal pull-up and pull-down resistors, which can be
39   activated or not.
40 
41     (+) In Output or Alternate mode, each IO can be configured on open-drain or push-pull
42   type and the IO speed can be selected depending on the VDD value.
43 
44     (+) The microcontroller IO pins are connected to onboard peripherals/modules through a
45         multiplexer that allows only one peripheral alternate function (AF) connected
46   to an IO pin at a time. In this way, there can be no conflict between peripherals
47   sharing the same IO pin.
48 
49     (+) All ports have external interrupt/event capability. To use external interrupt
50   lines, the port must be configured in input mode. All available GPIO pins are
51   connected to the 16 external interrupt/event lines from EXTI0 to EXTI15.
52 
53     (+) The external interrupt/event controller consists of up to 28 edge detectors
54   (16 lines are connected to GPIO) for generating event/interrupt requests (each
55   input line can be independently configured to select the type (interrupt or event)
56   and the corresponding trigger event (rising or falling or both). Each line can
57   also be masked independently.
58 
59                      ##### How to use this driver #####
60   ==============================================================================
61   [..]
62     (#) Enable the GPIO IOPORT clock using the following function: __HAL_RCC_GPIOx_CLK_ENABLE().
63 
64     (#) Configure the GPIO pin(s) using HAL_GPIO_Init().
65         (++) Configure the IO mode using "Mode" member from GPIO_InitTypeDef structure
66         (++) Activate Pull-up, Pull-down resistor using "Pull" member from GPIO_InitTypeDef
67              structure.
68         (++) In case of Output or alternate function mode selection: the speed is
69              configured through "Speed" member from GPIO_InitTypeDef structure.
70         (++) In alternate mode is selection, the alternate function connected to the IO
71              is configured through "Alternate" member from GPIO_InitTypeDef structure.
72         (++) Analog mode is required when a pin is to be used as ADC channel
73              or DAC output.
74         (++) In case of external interrupt/event selection the "Mode" member from
75              GPIO_InitTypeDef structure select the type (interrupt or event) and
76              the corresponding trigger event (rising or falling or both).
77 
78     (#) In case of external interrupt/event mode selection, configure NVIC IRQ priority
79         mapped to the EXTI line using HAL_NVIC_SetPriority() and enable it using
80         HAL_NVIC_EnableIRQ().
81 
82    (#) HAL_GPIO_DeInit allows to set register values to their reset value. This function
83        is also to be used when unconfiguring pin which was used as an external interrupt
84        or in event mode. That is the only way to reset the corresponding bit in
85        EXTI & SYSCFG registers.
86 
87     (#) To get the level of a pin configured in input mode use HAL_GPIO_ReadPin().
88 
89     (#) To set/reset the level of a pin configured in output mode use
90         HAL_GPIO_WritePin()/HAL_GPIO_TogglePin().
91 
92     (#) To lock pin configuration until next reset use HAL_GPIO_LockPin().
93 
94     (#) During and just after reset, the alternate functions are not
95         active and the GPIO pins are configured in input floating mode (except JTAG
96         pins).
97 
98     (#) The LSE oscillator pins OSC32_IN and OSC32_OUT can be used as general purpose
99         (PC14 and PC15, respectively) when the LSE oscillator is off. The LSE has
100         priority over the GPIO function.
101 
102     (#) The HSE oscillator pins OSC_IN/OSC_OUT can be used as
103         general purpose PH0 and PH1, respectively, when the HSE oscillator is off.
104         The HSE has priority over the GPIO function.
105 
106   @endverbatim
107   ******************************************************************************
108   */
109 
110 /* Includes ------------------------------------------------------------------*/
111 #include "stm32l0xx_hal.h"
112 
113 /** @addtogroup STM32L0xx_HAL_Driver
114   * @{
115   */
116 
117 #ifdef HAL_GPIO_MODULE_ENABLED
118 
119 /** @addtogroup GPIO
120   * @brief GPIO HAL module driver
121   * @{
122   */
123 
124 /* Private define ------------------------------------------------------------*/
125 /** @addtogroup GPIO_Private
126   * @{
127   */
128 #define GPIO_NUMBER           (16U)
129 /**
130   * @}
131   */
132 /** @addtogroup GPIO_Exported_Functions
133   * @{
134   */
135 
136 /** @addtogroup GPIO_Exported_Functions_Group1
137  *  @brief    Initialization and de-initialization functions
138  *
139 @verbatim
140  ===============================================================================
141               ##### Initialization and de-initialization functions #####
142  ===============================================================================
143 
144 @endverbatim
145   * @{
146   */
147 
148 /**
149   * @brief  Initializes the GPIOx peripheral according to the specified parameters in the GPIO_Init.
150   * @param  GPIOx where x can be (A..E and H) to select the GPIO peripheral for STM32L0XX family devices.
151   *                Note that GPIOE is not available on all devices.
152   * @param  GPIO_Init pointer to a GPIO_InitTypeDef structure that contains
153   *                    the configuration information for the specified GPIO peripheral.
154   * @retval None
155   */
HAL_GPIO_Init(GPIO_TypeDef * GPIOx,GPIO_InitTypeDef * GPIO_Init)156 void HAL_GPIO_Init(GPIO_TypeDef  *GPIOx, GPIO_InitTypeDef *GPIO_Init)
157 {
158   uint32_t position = 0x00U;
159   uint32_t iocurrent = 0x00U;
160   uint32_t temp = 0x00U;
161 
162   /* Check the parameters */
163   assert_param(IS_GPIO_MODE(GPIO_Init->Mode));
164   assert_param(IS_GPIO_PIN_AVAILABLE(GPIOx, (GPIO_Init->Pin)));
165 
166   /* Configure the port pins */
167   while (((GPIO_Init->Pin) >> position) != 0)
168   {
169     /* Get the IO position */
170     iocurrent = (GPIO_Init->Pin) & (1U << position);
171 
172     if (iocurrent)
173     {
174       /*--------------------- GPIO Mode Configuration ------------------------*/
175       /* In case of Output or Alternate function mode selection */
176       if (((GPIO_Init->Mode & GPIO_MODE) == MODE_OUTPUT) ||
177           ((GPIO_Init->Mode & GPIO_MODE) == MODE_AF))
178       {
179         /* Check the Speed parameter */
180         assert_param(IS_GPIO_SPEED(GPIO_Init->Speed));
181         /* Configure the IO Speed */
182         temp = GPIOx->OSPEEDR;
183         temp &= ~(GPIO_OSPEEDER_OSPEED0 << (position * 2U));
184         temp |= (GPIO_Init->Speed << (position * 2U));
185         GPIOx->OSPEEDR = temp;
186 
187         /* Configure the IO Output Type */
188         temp = GPIOx->OTYPER;
189         temp &= ~(GPIO_OTYPER_OT_0 << position) ;
190         temp |= (((GPIO_Init->Mode & OUTPUT_TYPE) >> OUTPUT_TYPE_Pos) << position);
191         GPIOx->OTYPER = temp;
192       }
193 
194       if ((GPIO_Init->Mode & GPIO_MODE) != MODE_ANALOG)
195       {
196         /* Check the Pull parameter */
197         assert_param(IS_GPIO_PULL(GPIO_Init->Pull));
198 
199         /* Activate the Pull-up or Pull down resistor for the current IO */
200         temp = GPIOx->PUPDR;
201         temp &= ~(GPIO_PUPDR_PUPD0 << (position * 2U));
202         temp |= ((GPIO_Init->Pull) << (position * 2U));
203         GPIOx->PUPDR = temp;
204       }
205 
206       /* In case of Alternate function mode selection */
207       if ((GPIO_Init->Mode & GPIO_MODE) == MODE_AF)
208       {
209         /* Check the Alternate function parameters */
210         assert_param(IS_GPIO_AF_INSTANCE(GPIOx));
211         assert_param(IS_GPIO_AF(GPIO_Init->Alternate));
212 
213         /* Configure Alternate function mapped with the current IO */
214         temp = GPIOx->AFR[position >> 3U];
215         temp &= ~(0xFUL << ((uint32_t)(position & 0x07UL) * 4U));
216         temp |= ((uint32_t)(GPIO_Init->Alternate) << (((uint32_t)position & (uint32_t)0x07U) * 4U));
217         GPIOx->AFR[position >> 3U] = temp;
218       }
219 
220       /* Configure IO Direction mode (Input, Output, Alternate or Analog) */
221       temp = GPIOx->MODER;
222       temp &= ~(GPIO_MODER_MODE0 << (position * 2U));
223       temp |= ((GPIO_Init->Mode & GPIO_MODE) << (position * 2U));
224       GPIOx->MODER = temp;
225 
226       /*--------------------- EXTI Mode Configuration ------------------------*/
227       /* Configure the External Interrupt or event for the current IO */
228       if ((GPIO_Init->Mode & EXTI_MODE) != 0x00U)
229       {
230         /* Enable SYSCFG Clock */
231         __HAL_RCC_SYSCFG_CLK_ENABLE();
232 
233         temp = SYSCFG->EXTICR[position >> 2U];
234         CLEAR_BIT(temp, (0x0FUL) << (4U * (position & 0x03U)));
235         SET_BIT(temp, (GPIO_GET_INDEX(GPIOx)) << (4 * (position & 0x03U)));
236         SYSCFG->EXTICR[position >> 2U] = temp;
237 
238         /* Clear Rising Falling edge configuration */
239         temp = EXTI->RTSR;
240         temp &= ~((uint32_t)iocurrent);
241         if ((GPIO_Init->Mode & TRIGGER_RISING) != 0x00U)
242         {
243           temp |= iocurrent;
244         }
245         EXTI->RTSR = temp;
246 
247         temp = EXTI->FTSR;
248         temp &= ~((uint32_t)iocurrent);
249         if ((GPIO_Init->Mode & TRIGGER_FALLING) != 0x00U)
250         {
251           temp |= iocurrent;
252         }
253         EXTI->FTSR = temp;
254 
255         temp = EXTI->EMR;
256         temp &= ~((uint32_t)iocurrent);
257         if ((GPIO_Init->Mode & EXTI_EVT) != 0x00U)
258         {
259           temp |= iocurrent;
260         }
261         EXTI->EMR = temp;
262 
263         /* Clear EXTI line configuration */
264         temp = EXTI->IMR;
265         temp &= ~((uint32_t)iocurrent);
266         if ((GPIO_Init->Mode & EXTI_IT) != 0x00U)
267         {
268           temp |= iocurrent;
269         }
270         EXTI->IMR = temp;
271       }
272     }
273     position++;
274   }
275 }
276 
277 /**
278   * @brief  De-initializes the GPIOx peripheral registers to their default reset values.
279   * @param  GPIOx where x can be (A..E and H) to select the GPIO peripheral for STM32L0XX family devices.
280   *                Note that GPIOE is not available on all devices.
281   * @param  GPIO_Pin specifies the port bit to be written.
282   *                   This parameter can be one of GPIO_PIN_x where x can be (0..15).
283   *                   All port bits are not necessarily available on all GPIOs.
284   * @retval None
285   */
HAL_GPIO_DeInit(GPIO_TypeDef * GPIOx,uint32_t GPIO_Pin)286 void HAL_GPIO_DeInit(GPIO_TypeDef  *GPIOx, uint32_t GPIO_Pin)
287 {
288   uint32_t position = 0x00U;
289   uint32_t iocurrent = 0x00U;
290   uint32_t tmp = 0x00U;
291 
292   /* Check the parameters */
293   assert_param(IS_GPIO_PIN_AVAILABLE(GPIOx, GPIO_Pin));
294 
295   /* Configure the port pins */
296   while ((GPIO_Pin >> position) != 0)
297   {
298     /* Get the IO position */
299     iocurrent = (GPIO_Pin) & (1U << position);
300 
301     if (iocurrent)
302     {
303       /*------------------------- EXTI Mode Configuration --------------------*/
304       /* Clear the External Interrupt or Event for the current IO */
305 
306       tmp = SYSCFG->EXTICR[position >> 2U];
307       tmp &= ((0x0FUL) << (4U * (position & 0x03U)));
308       if (tmp == (GPIO_GET_INDEX(GPIOx) << (4U * (position & 0x03U))))
309       {
310         /* Clear EXTI line configuration */
311         EXTI->IMR &= ~((uint32_t)iocurrent);
312         EXTI->EMR &= ~((uint32_t)iocurrent);
313 
314         /* Clear Rising Falling edge configuration */
315         EXTI->FTSR &= ~((uint32_t)iocurrent);
316         EXTI->RTSR &= ~((uint32_t)iocurrent);
317 
318         tmp = (0x0FUL) << (4U * (position & 0x03U));
319         SYSCFG->EXTICR[position >> 2U] &= ~tmp;
320       }
321 
322       /*------------------------- GPIO Mode Configuration --------------------*/
323       /* Configure IO Direction in Analog Mode (reset state) */
324       GPIOx->MODER |= (GPIO_MODE_ANALOG << (position * 2U));
325 
326       /* Configure the default Alternate Function in current IO */
327       GPIOx->AFR[position >> 3U] &= ~(0xFUL << ((uint32_t)(position & 0x07UL) * 4U));
328 
329       /* Deactivate the Pull-up oand Pull-down resistor for the current IO */
330       GPIOx->PUPDR &= ~(GPIO_PUPDR_PUPD0 << (position * 2U));
331 
332       /* Configure the default value IO Output Type */
333       GPIOx->OTYPER  &= ~(GPIO_OTYPER_OT_0 << position);
334 
335       /* Configure the default value for IO Speed */
336       GPIOx->OSPEEDR &= ~(GPIO_OSPEEDER_OSPEED0 << (position * 2U));
337     }
338     position++;
339   }
340 }
341 
342 /**
343   * @}
344   */
345 
346 /** @addtogroup GPIO_Exported_Functions_Group2
347  *  @brief   GPIO Read and Write
348  *
349 @verbatim
350  ===============================================================================
351                        ##### IO operation functions #####
352  ===============================================================================
353 
354 @endverbatim
355   * @{
356   */
357 
358 /**
359   * @brief  Reads the specified input port pin.
360   * @param  GPIOx where x can be (A..E and H) to select the GPIO peripheral for STM32L0xx family devices.
361   *                Note that GPIOE is not available on all devices.
362   * @param  GPIO_Pin specifies the port bit to read.
363   *                   This parameter can be GPIO_PIN_x where x can be (0..15).
364   *                   All port bits are not necessarily available on all GPIOs.
365   * @retval The input port pin value.
366   */
HAL_GPIO_ReadPin(GPIO_TypeDef * GPIOx,uint16_t GPIO_Pin)367 GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
368 {
369   GPIO_PinState bitstatus;
370 
371   /* Check the parameters */
372   assert_param(IS_GPIO_PIN_AVAILABLE(GPIOx, GPIO_Pin));
373 
374   if ((GPIOx->IDR & GPIO_Pin) != (uint32_t)GPIO_PIN_RESET)
375   {
376     bitstatus = GPIO_PIN_SET;
377   }
378   else
379   {
380     bitstatus = GPIO_PIN_RESET;
381   }
382   return bitstatus;
383 }
384 
385 /**
386   * @brief  Sets or clears the selected data port bit.
387   *
388   * @note   This function uses GPIOx_BSRR register to allow atomic read/modify
389   *         accesses. In this way, there is no risk of an IRQ occurring between
390   *         the read and the modify access.
391   *
392   * @param  GPIOx where x can be (A..E and H) to select the GPIO peripheral for STM32L0xx family devices.
393   *                Note that GPIOE is not available on all devices.
394   * @param  GPIO_Pin specifies the port bit to be written.
395   *                   This parameter can be one of GPIO_PIN_x where x can be (0..15).
396   *                   All port bits are not necessarily available on all GPIOs.
397   * @param  PinState specifies the value to be written to the selected bit.
398   *                   This parameter can be one of the GPIO_PinState enum values:
399   *                        GPIO_PIN_RESET: to clear the port pin
400   *                        GPIO_PIN_SET: to set the port pin
401   * @retval None
402   */
HAL_GPIO_WritePin(GPIO_TypeDef * GPIOx,uint16_t GPIO_Pin,GPIO_PinState PinState)403 void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)
404 {
405   /* Check the parameters */
406   assert_param(IS_GPIO_PIN_AVAILABLE(GPIOx, GPIO_Pin));
407   assert_param(IS_GPIO_PIN_ACTION(PinState));
408 
409   if (PinState != GPIO_PIN_RESET)
410   {
411     GPIOx->BSRR = GPIO_Pin;
412   }
413   else
414   {
415     GPIOx->BRR = GPIO_Pin ;
416   }
417 }
418 
419 /**
420   * @brief  Toggles the specified GPIO pins.
421   * @param  GPIOx Where x can be (A..E and H) to select the GPIO peripheral for STM32L0xx family devices.
422   *                Note that GPIOE is not available on all devices.
423   *                All port bits are not necessarily available on all GPIOs.
424   * @param  GPIO_Pin Specifies the pins to be toggled.
425   * @retval None
426   */
HAL_GPIO_TogglePin(GPIO_TypeDef * GPIOx,uint16_t GPIO_Pin)427 void HAL_GPIO_TogglePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
428 {
429   uint32_t odr;
430 
431   /* Check the parameters */
432   assert_param(IS_GPIO_PIN_AVAILABLE(GPIOx, GPIO_Pin));
433 
434   /* get current Output Data Register value */
435   odr = GPIOx->ODR;
436 
437   /* Set selected pins that were at low level, and reset ones that were high */
438   GPIOx->BSRR = ((odr & GPIO_Pin) << GPIO_NUMBER) | (~odr & GPIO_Pin);
439 }
440 
441 /**
442 * @brief  Locks GPIO Pins configuration registers.
443 * @note   The locked registers are GPIOx_MODER, GPIOx_OTYPER, GPIOx_OSPEEDR,
444 *         GPIOx_PUPDR, GPIOx_AFRL and GPIOx_AFRH.
445 * @note   The configuration of the locked GPIO pins can no longer be modified
446 *         until the next reset.
447 * @param  GPIOx where x can be (A..E and H) to select the GPIO peripheral for STM32L0xx family.
448 *                Note that GPIOE is not available on all devices.
449 * @param  GPIO_Pin specifies the port bit to be locked.
450 *         This parameter can be any combination of GPIO_Pin_x where x can be (0..15).
451 *         All port bits are not necessarily available on all GPIOs.
452 * @retval None
453 */
HAL_GPIO_LockPin(GPIO_TypeDef * GPIOx,uint16_t GPIO_Pin)454 HAL_StatusTypeDef HAL_GPIO_LockPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
455 {
456   __IO uint32_t tmp = GPIO_LCKR_LCKK;
457 
458   /* Check the parameters */
459   assert_param(IS_GPIO_PIN_AVAILABLE(GPIOx, GPIO_Pin));
460 
461   /* Apply lock key write sequence */
462   tmp |= GPIO_Pin;
463   /* Set LCKx bit(s): LCKK='1' + LCK[15-0] */
464   GPIOx->LCKR = tmp;
465   /* Reset LCKx bit(s): LCKK='0' + LCK[15-0] */
466   GPIOx->LCKR = GPIO_Pin;
467   /* Set LCKx bit(s): LCKK='1' + LCK[15-0] */
468   GPIOx->LCKR = tmp;
469   /* Read LCKK register. This read is mandatory to complete key lock sequence */
470   tmp = GPIOx->LCKR;
471 
472   /* read again in order to confirm lock is active */
473   if ((GPIOx->LCKR & GPIO_LCKR_LCKK) != RESET)
474   {
475     return HAL_OK;
476   }
477   else
478   {
479     return HAL_ERROR;
480   }
481 }
482 /**
483   * @brief  This function handles EXTI interrupt request.
484   * @param  GPIO_Pin Specifies the pins connected to the EXTI line.
485   * @retval None
486   */
HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)487 void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
488 {
489   /* EXTI line interrupt detected */
490   if (__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET)
491   {
492     __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
493     HAL_GPIO_EXTI_Callback(GPIO_Pin);
494   }
495 }
496 
497 /**
498   * @brief  EXTI line detection callbacks.
499   * @param  GPIO_Pin Specifies the pins connected to the EXTI line.
500   * @retval None
501   */
HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)502 __weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
503 {
504   /* Prevent unused argument(s) compilation warning */
505   UNUSED(GPIO_Pin);
506 
507   /* NOTE: This function Should not be modified, when the callback is needed,
508            the HAL_GPIO_EXTI_Callback could be implemented in the user file
509    */
510 }
511 
512 /**
513   * @}
514   */
515 
516 
517 /**
518   * @}
519   */
520 
521 /**
522   * @}
523   */
524 
525 #endif /* HAL_GPIO_MODULE_ENABLED */
526 
527 /**
528   * @}
529   */
530 
531 
532