text: /**
  ******************************************************************************
  * @file  HAL_gpio.c
  * @author  AE team
  * @version V1.0.0
  * @date    16/3/2017
  * @brief  This file provides all the GPIO firmware functions.
  ******************************************************************************
  * @copy
  *
  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
  * TIME. AS A RESULT, MindMotion SHALL NOT BE HELD LIABLE FOR ANY
  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
  *
  * <h2><center>&copy; COPYRIGHT 2017 MindMotion</center></h2>
  */ 
  
  /* Includes ------------------------------------------------------------------*/
  #include "HAL_gpio.h"
  #include "HAL_rcc.h"
  
  /** @addtogroup StdPeriph_Driver
  * @{
  */
  
  /** @defgroup GPIO 
  * @brief GPIO driver modules
  * @{
  */ 
  
  /** @defgroup GPIO_Private_TypesDefinitions
  * @{
  */
  
  /**
  * @}
  */
  
  /** @defgroup GPIO_Private_Defines
  * @{
  */
  
  /* ------------ RCC registers bit address in the alias region ----------------*/
  #define AFIO_OFFSET                 (AFIO_BASE - PERIPH_BASE)
  
  /* --- EVENTCR Register -----*/
  
  /* Alias word address of EVOE bit */
  #define EVCR_OFFSET                 (AFIO_OFFSET + 0x00)
  #define EVOE_BitNumber              ((uint8_t)0x07)
  #define EVCR_EVOE_BB                (PERIPH_BB_BASE + (EVCR_OFFSET * 32) + (EVOE_BitNumber * 4))
  #define EVCR_PORTPINCONFIG_MASK     ((uint16_t)0xFF80)
  #define LSB_MASK                    ((uint16_t)0xFFFF)
  #define DBGAFR_POSITION_MASK        ((uint32_t)0x000F0000)
  #define DBGAFR_SWJCFG_MASK          ((uint32_t)0xFFFFFFFF)
  #define DBGAFR_LOCATION_MASK        ((uint32_t)0x00200000)
  #define DBGAFR_NUMBITS_MASK         ((uint32_t)0x00100000)
  
  /**
  * @}
  */
  
  /** @defgroup GPIO_Private_Macros
  * @{
  */
  
  /**
  * @}
  */
  
  /** @defgroup GPIO_Private_Variables
  * @{
  */
  
  /**
  * @}
  */
  
  /** @defgroup GPIO_Private_FunctionPrototypes
  * @{
  */
  
  /**
  * @}
  */
  
  /** @defgroup GPIO_Private_Functions
  * @{
  */
  
  /**
  * @brief  Deinitializes the GPIOx peripheral registers to their default
  *   reset values.
  * @param GPIOx: where x can be (A..G) to select the GPIO peripheral.
  * @retval : None
  */
  void GPIO_DeInit(GPIO_TypeDef* GPIOx)
  {
    /* Check the parameters */
    assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
    
    switch (*(uint32_t*)&GPIOx)
    {
    case GPIOA_BASE:
      RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOA, ENABLE);
      RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOA, DISABLE);
      break;
    case GPIOB_BASE:
      RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOB, ENABLE);
      RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOB, DISABLE);
      break;
    case GPIOC_BASE:
      RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOC, ENABLE);
      RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOC, DISABLE);
      break;
    case GPIOD_BASE:
      RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOD, ENABLE);
      RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOD, DISABLE);
      break;
      
      default:
        break;
    }
  }
  
  /**
  * @brief  Deinitializes the Alternate Functions (remap, event control
  *   and EXTI configuration) registers to their default reset
  *   values.
  * @param  None
  * @retval : None
  */
  void GPIO_AFIODeInit(void)
  {
    RCC_APB2PeriphResetCmd(RCC_APB2Periph_AFIO, ENABLE);
    RCC_APB2PeriphResetCmd(RCC_APB2Periph_AFIO, DISABLE);
  }
  
  /**
  * @brief  Initializes the GPIOx peripheral according to the specified
  *   parameters in the GPIO_InitStruct.
  * @param GPIOx: where x can be (A..G) to select the GPIO peripheral.
  * @param GPIO_InitStruct: pointer to a GPIO_InitTypeDef structure that
  *   contains the configuration information for the specified GPIO
  *   peripheral.
  * @retval : None
  */
  void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
  {
    uint32_t currentmode = 0x00, currentpin = 0x00, pinpos = 0x00, pos = 0x00;
    uint32_t tmpreg = 0x00, pinmask = 0x00;
    /* Check the parameters */
    assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
    assert_param(IS_GPIO_MODE(GPIO_InitStruct->GPIO_Mode));
    assert_param(IS_GPIO_PIN(GPIO_InitStruct->GPIO_Pin));  
    
    /*---------------------------- GPIO Mode Configuration -----------------------*/
    currentmode = ((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x0F);
    if ((((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x10)) != 0x00)
    { 
      /* Check the parameters */
      assert_param(IS_GPIO_SPEED(GPIO_InitStruct->GPIO_Speed));
      /* Output mode */
      currentmode |= (uint32_t)GPIO_InitStruct->GPIO_Speed;
    }
    /*---------------------------- GPIO CRL Configuration ------------------------*/
    /* Configure the eight low port pins */
    if (((uint32_t)GPIO_InitStruct->GPIO_Pin & ((uint32_t)0x00FF)) != 0x00)
    {
      tmpreg = GPIOx->CRL;
      for (pinpos = 0x00; pinpos < 0x08; pinpos++)
      {
        pos = ((uint32_t)0x01) << pinpos;
        /* Get the port pins position */
        currentpin = (GPIO_InitStruct->GPIO_Pin) & pos;
        if (currentpin == pos)
        {
          pos = pinpos << 2;
          /* Clear the corresponding low control register bits */
          pinmask = ((uint32_t)0x0F) << pos;
          tmpreg &= ~pinmask;
          /* Write the mode configuration in the corresponding bits */
          tmpreg |= (currentmode << pos);
          /* Reset the corresponding ODR bit */
          if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
          {
            GPIOx->BRR = (((uint32_t)0x01) << pinpos);
          }
          else
          {
            /* Set the corresponding ODR bit */
            if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
            {
              GPIOx->BSRR = (((uint32_t)0x01) << pinpos);
            }
          }
        }
      }
      GPIOx->CRL = tmpreg;
    }
    /*---------------------------- GPIO CRH Configuration ------------------------*/
    /* Configure the eight high port pins */
    if (GPIO_InitStruct->GPIO_Pin > 0x00FF)
    {
      tmpreg = GPIOx->CRH;
      for (pinpos = 0x00; pinpos < 0x08; pinpos++)
      {
        pos = (((uint32_t)0x01) << (pinpos + 0x08));
        /* Get the port pins position */
        currentpin = ((GPIO_InitStruct->GPIO_Pin) & pos);
        if (currentpin == pos)
        {
          pos = pinpos << 2;
          /* Clear the corresponding high control register bits */
          pinmask = ((uint32_t)0x0F) << pos;
          tmpreg &= ~pinmask;
          /* Write the mode configuration in the corresponding bits */
          tmpreg |= (currentmode << pos);
          /* Reset the corresponding ODR bit */
          if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
          {
            GPIOx->BRR = (((uint32_t)0x01) << (pinpos + 0x08));
          }
          /* Set the corresponding ODR bit */
          if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
          {
            GPIOx->BSRR = (((uint32_t)0x01) << (pinpos + 0x08));
          }
        }
      }
      GPIOx->CRH = tmpreg;
    }
  }
  
  /**
  * @brief  Fills each GPIO_InitStruct member with its default value.
  * @param GPIO_InitStruct : pointer to a GPIO_InitTypeDef structure
  *   which will be initialized.
  * @retval : None
  */
  void GPIO_StructInit(GPIO_InitTypeDef* GPIO_InitStruct)
  {
    /* Reset GPIO init structure parameters values */
    GPIO_InitStruct->GPIO_Pin  = GPIO_Pin_All;
    GPIO_InitStruct->GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_InitStruct->GPIO_Mode = GPIO_Mode_IN_FLOATING;
  }
  
  /**
  * @brief  Reads the specified input port pin.
  * @param GPIOx: where x can be (A..G) to select the GPIO peripheral.
  * @param GPIO_Pin:  specifies the port bit to read.
  *   This parameter can be GPIO_Pin_x where x can be (0..15).
  * @retval : The input port pin value.
  */
  uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
  {
    uint8_t bitstatus = 0x00;
    
    /* Check the parameters */
    assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
    assert_param(IS_GET_GPIO_PIN(GPIO_Pin)); 
    
    if ((GPIOx->IDR & GPIO_Pin) != (uint32_t)Bit_RESET)
    {
      bitstatus = (uint8_t)Bit_SET;
    }
    else
    {
      bitstatus = (uint8_t)Bit_RESET;
    }
    return bitstatus;
  }
  
  /**
  * @brief  Reads the specified GPIO input data port.
  * @param GPIOx: where x can be (A..G) to select the GPIO peripheral.
  * @retval : GPIO input data port value.
  */
  uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx)
  {
    /* Check the parameters */
    assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
    
    return ((uint16_t)GPIOx->IDR);
  }
  
  /**
  * @brief  Reads the specified output data port bit.
  * @param GPIOx: where x can be (A..G) to select the GPIO peripheral.
  * @param GPIO_Pin:  specifies the port bit to read.
  *   This parameter can be GPIO_Pin_x where x can be (0..15).
  * @retval : The output port pin value.
  */
  uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
  {
    uint8_t bitstatus = 0x00;
    /* Check the parameters */
    assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
    assert_param(IS_GET_GPIO_PIN(GPIO_Pin)); 
    
    if ((GPIOx->ODR & GPIO_Pin) != (uint32_t)Bit_RESET)
    {
      bitstatus = (uint8_t)Bit_SET;
    }
    else
    {
      bitstatus = (uint8_t)Bit_RESET;
    }
    return bitstatus;
  }
  
  /**
  * @brief  Reads the specified GPIO output data port.
  * @param GPIOx: where x can be (A..G) to select the GPIO peripheral.
  * @retval : GPIO output data port value.
  */
  uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx)
  {
    /* Check the parameters */
    assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
    
    return ((uint16_t)GPIOx->ODR);
  }
  
  /**
  * @brief  Sets the selected data port bits.
  * @param GPIOx: where x can be (A..G) to select the GPIO peripheral.
  * @param GPIO_Pin: specifies the port bits to be written.
  *   This parameter can be any combination of GPIO_Pin_x where 
  *   x can be (0..15).
  * @retval : None
  */
  void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
  {
    /* Check the parameters */
    assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
    assert_param(IS_GPIO_PIN(GPIO_Pin));
    
    GPIOx->BSRR = GPIO_Pin;
  }
  
  /**
  * @brief  Clears the selected data port bits.
  * @param GPIOx: where x can be (A..G) to select the GPIO peripheral.
  * @param GPIO_Pin: specifies the port bits to be written.
  *   This parameter can be any combination of GPIO_Pin_x where 
  *   x can be (0..15).
  * @retval : None
  */
  void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
  {
    /* Check the parameters */
    assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
    assert_param(IS_GPIO_PIN(GPIO_Pin));
    
    GPIOx->BRR = GPIO_Pin;
  }
  
  /**
  * @brief  Sets or clears the selected data port bit.
  * @param GPIOx: where x can be (A..G) to select the GPIO peripheral.
  * @param GPIO_Pin: specifies the port bit to be written.
  *   This parameter can be one of GPIO_Pin_x where x can be (0..15).
  * @param BitVal: specifies the value to be written to the selected bit.
  *   This parameter can be one of the BitAction enum values:
  * @arg Bit_RESET: to clear the port pin
  * @arg Bit_SET: to set the port pin
  * @retval : None
  */
  void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal)
  {
    /* Check the parameters */
    assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
    assert_param(IS_GET_GPIO_PIN(GPIO_Pin));
    assert_param(IS_GPIO_BIT_ACTION(BitVal)); 
    
    if (BitVal != Bit_RESET)
    {
      GPIOx->BSRR = GPIO_Pin;
    }
    else
    {
      GPIOx->BRR = GPIO_Pin;
    }
  }
  
  /**
  * @brief  Writes data to the specified GPIO data port.
  * @param GPIOx: where x can be (A..G) to select the GPIO peripheral.
  * @param PortVal: specifies the value to be written to the port output
  *   data register.
  * @retval : None
  */
  void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal)
  {
    /* Check the parameters */
    assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
    
    GPIOx->ODR = PortVal;
  }
  
  /**
  * @brief  Locks GPIO Pins configuration registers.
  * @param GPIOx: where x can be (A..G) to select the GPIO peripheral.
  * @param GPIO_Pin: specifies the port bit to be written.
  *   This parameter can be any combination of GPIO_Pin_x where 
  *   x can be (0..15).
  * @retval : None
  */
  void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
  {
    uint32_t tmp = 0x00010000;
    
    /* Check the parameters */
    assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
    assert_param(IS_GPIO_PIN(GPIO_Pin));
    
    tmp |= GPIO_Pin;
    /* Set LCKK bit */
    GPIOx->LCKR = tmp;
    /* Reset LCKK bit */
    GPIOx->LCKR =  GPIO_Pin;
    /* Set LCKK bit */
    GPIOx->LCKR = tmp;
    /* Read LCKK bit*/
    tmp = GPIOx->LCKR;
    /* Read LCKK bit*/
    tmp = GPIOx->LCKR;
  }
  
  /**
  * @brief  Selects the GPIO pin used as Event output.
  * @param GPIO_PortSource: selects the GPIO port to be used as source
  *   for Event output.
  *   This parameter can be GPIO_PortSourceGPIOx where x can be
  *   (A..E).
  * @param GPIO_PinSource: specifies the pin for the Event output.
  *   This parameter can be GPIO_PinSourcex where x can be (0..15).
  * @retval : None
  */
  void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)
  {
    uint32_t tmpreg = 0x00;
    /* Check the parameters */
    assert_param(IS_GPIO_EVENTOUT_PORT_SOURCE(GPIO_PortSource));
    assert_param(IS_GPIO_PIN_SOURCE(GPIO_PinSource));
    
    tmpreg = AFIO->EVCR;
    /* Clear the PORT[6:4] and PIN[3:0] bits */
    tmpreg &= EVCR_PORTPINCONFIG_MASK;
    tmpreg |= (uint32_t)GPIO_PortSource << 0x04;
    tmpreg |= GPIO_PinSource;
    AFIO->EVCR = tmpreg;
  }
  
  /**
  * @brief  Enables or disables the Event Output.
  * @param NewState: new state of the Event output.
  *   This parameter can be: ENABLE or DISABLE.
  * @retval : None
  */
  void GPIO_EventOutputCmd(FunctionalState NewState)
  {
    /* Check the parameters */
    assert_param(IS_FUNCTIONAL_STATE(NewState));
    
    *(__IO uint32_t *) EVCR_EVOE_BB = (uint32_t)NewState;
  }
  
  /**
  * @brief  Changes the mapping of the specified pin.
  * @param GPIO_Remap: selects the pin to remap.
  *   This parameter can be one of the following values:
  * @arg GPIO_Remap_SPI1
  * @arg GPIO_Remap_I2C1
  * @arg GPIO_Remap_UART1
  * @arg GPIO_Remap_UART2
  * @arg GPIO_PartialRemap_UART3
  * @arg GPIO_FullRemap_UART3
  * @arg GPIO_PartialRemap_TIM1
  * @arg GPIO_FullRemap_TIM1
  * @arg GPIO_PartialRemap1_TIM2
  * @arg GPIO_PartialRemap2_TIM2
  * @arg GPIO_FullRemap_TIM2
  * @arg GPIO_PartialRemap_TIM3
  * @arg GPIO_FullRemap_TIM3
  * @arg GPIO_Remap_TIM4
  * @arg GPIO_Remap1_CAN1
  * @arg GPIO_Remap2_CAN1
  * @arg GPIO_Remap_PD01
  * @arg GPIO_Remap_TIM5CH4_LSI
  * @arg GPIO_Remap_ADC1_ETRGINJ
  * @arg GPIO_Remap_ADC1_ETRGREG
  * @arg GPIO_Remap_ADC2_ETRGINJ
  * @arg GPIO_Remap_ADC2_ETRGREG
  * @arg GPIO_Remap_SWJ_NoJTRST
  * @arg GPIO_Remap_SWJ_JTAGDisable
  * @arg GPIO_Remap_SWJ_Disable
  * @param NewState: new state of the port pin remapping.
  *   This parameter can be: ENABLE or DISABLE.
  * @retval : None
  */
  void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState)
  {
    uint32_t tmp = 0x00, tmp1 = 0x00, tmpreg = 0x00, tmpmask = 0x00;
    /* Check the parameters */
    assert_param(IS_GPIO_REMAP(GPIO_Remap));
    assert_param(IS_FUNCTIONAL_STATE(NewState));  
    
    tmpreg = AFIO->MAPR;
    tmpmask = (GPIO_Remap & DBGAFR_POSITION_MASK) >> 0x10;
    tmp = GPIO_Remap & LSB_MASK;
    if ((GPIO_Remap & (DBGAFR_LOCATION_MASK | DBGAFR_NUMBITS_MASK)) == (DBGAFR_LOCATION_MASK | DBGAFR_NUMBITS_MASK))
    {
      tmpreg &= DBGAFR_SWJCFG_MASK;
      AFIO->MAPR &= DBGAFR_SWJCFG_MASK;
    }
    else if ((GPIO_Remap & DBGAFR_NUMBITS_MASK) == DBGAFR_NUMBITS_MASK)
    {
      tmp1 = ((uint32_t)0x03) << tmpmask;
      tmpreg &= ~tmp1;
      tmpreg |= ~DBGAFR_SWJCFG_MASK;
    }
    else
    {
      tmpreg &= ~(tmp << ((GPIO_Remap >> 0x15)*0x10));
      tmpreg |= ~DBGAFR_SWJCFG_MASK;
    }
    if (NewState != DISABLE)
    {
      tmpreg |= (tmp << ((GPIO_Remap >> 0x15)*0x10));
    }
    AFIO->MAPR = tmpreg;
  }
  
  /**
  * @brief  Selects the GPIO pin used as EXTI Line.
  * @param GPIO_PortSource: selects the GPIO port to be used as
  *   source for EXTI lines.
  *   This parameter can be GPIO_PortSourceGPIOx where x can be
  *   (A..G).
  * @param GPIO_PinSource: specifies the EXTI line to be configured.
  *   This parameter can be GPIO_PinSourcex where x can be (0..15).
  * @retval : None
  */
  void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)
  {
    uint32_t tmp = 0x00;
    /* Check the parameters */
    assert_param(IS_GPIO_EXTI_PORT_SOURCE(GPIO_PortSource));
    assert_param(IS_GPIO_PIN_SOURCE(GPIO_PinSource));
    
    tmp = ((uint32_t)0x0F) << (0x04 * (GPIO_PinSource & (uint8_t)0x03));
    AFIO->EXTICR[GPIO_PinSource >> 0x02] &= ~tmp;
    AFIO->EXTICR[GPIO_PinSource >> 0x02] |= (((uint32_t)GPIO_PortSource) << (0x04 * (GPIO_PinSource & (uint8_t)0x03)));
  }
  
  /**
  * @}
  */
  
  /**
  * @}
  */
  
  /**
  * @}
  */
  
  /*-------------------------(C) COPYRIGHT 2017 MindMotion ----------------------*/
  