text: /**
    **************************************************************************
    * @file     at32f413_gpio.c
    * @version  v2.0.5
    * @date     2022-05-20
    * @brief    contains all the functions for the gpio firmware library
    **************************************************************************
    *                       Copyright notice & Disclaimer
    *
    * The software Board Support Package (BSP) that is made available to
    * download from Artery official website is the copyrighted work of Artery.
    * Artery authorizes customers to use, copy, and distribute the BSP
    * software and its related documentation for the purpose of design and
    * development in conjunction with Artery microcontrollers. Use of the
    * software is governed by this copyright notice and the following disclaimer.
    *
    * THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES,
    * GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS,
    * TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR
    * STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS,
    * INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
    * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
    *
    **************************************************************************
    */
  
  #include "at32f413_conf.h"
  
  /** @addtogroup AT32F413_periph_driver
    * @{
    */
  
  /** @defgroup GPIO
    * @brief GPIO driver modules
    * @{
    */
  
  #ifdef GPIO_MODULE_ENABLED
  
  /** @defgroup GPIO_private_functions
    * @{
    */
  
  /**
    * @brief  reset the gpio register
    * @param  gpio_x: to select the gpio peripheral.
    *         this parameter can be one of the following values:
    *         GPIOA, GPIOB, GPIOC, GPIOD, GPIOF.
    * @retval none
    */
  void gpio_reset(gpio_type *gpio_x)
  {
    if(gpio_x == GPIOA)
    {
      crm_periph_reset(CRM_GPIOA_PERIPH_RESET, TRUE);
      crm_periph_reset(CRM_GPIOA_PERIPH_RESET, FALSE);
    }
    else if(gpio_x == GPIOB)
    {
      crm_periph_reset(CRM_GPIOB_PERIPH_RESET, TRUE);
      crm_periph_reset(CRM_GPIOB_PERIPH_RESET, FALSE);
    }
    else if(gpio_x == GPIOC)
    {
      crm_periph_reset(CRM_GPIOC_PERIPH_RESET, TRUE);
      crm_periph_reset(CRM_GPIOC_PERIPH_RESET, FALSE);
    }
    else if(gpio_x == GPIOD)
    {
      crm_periph_reset(CRM_GPIOD_PERIPH_RESET, TRUE);
      crm_periph_reset(CRM_GPIOD_PERIPH_RESET, FALSE);
    }
    else if(gpio_x == GPIOF)
    {
      crm_periph_reset(CRM_GPIOF_PERIPH_RESET, TRUE);
      crm_periph_reset(CRM_GPIOF_PERIPH_RESET, FALSE);
    }
  }
  
  /**
    * @brief  reset the mux functions (remap, event control
              and exint configuration) registers to their default values.
    * @param  none
    * @retval none
    */
  void gpio_iomux_reset(void)
  {
    crm_periph_reset(CRM_IOMUX_PERIPH_RESET, TRUE);
    crm_periph_reset(CRM_IOMUX_PERIPH_RESET, FALSE);
  }
  
  /**
    * @brief  initialize the gpio peripheral.
    * @param  gpio_x: to select the gpio peripheral.
    *         this parameter can be one of the following values:
    *         GPIOA, GPIOB, GPIOC, GPIOD, GPIOF.
    * @param  gpio_init_struct: pointer to gpio init structure.
    * @retval none
    */
  void gpio_init(gpio_type *gpio_x, gpio_init_type *gpio_init_struct)
  {
    uint32_t temp;
    uint16_t pinx_value, pin_index;
  
    pin_index = (uint16_t)gpio_init_struct->gpio_pins;
  
    /* pinx_value indecate pin grounp bit[3:0] from modey[1:0] confy[1:0] */
  
    /* pin input analog config */
    if(gpio_init_struct->gpio_mode == GPIO_MODE_ANALOG)
    {
      pinx_value = 0x00;
    }
    /* pin input config */
    else if(gpio_init_struct->gpio_mode == GPIO_MODE_INPUT)
    {
      pinx_value = gpio_init_struct->gpio_pull & 0x0F;
  
      if(gpio_init_struct->gpio_pull == GPIO_PULL_UP)
      {
        gpio_x->scr = pin_index;
      }
      else if(gpio_init_struct->gpio_pull == GPIO_PULL_DOWN)
      {
        gpio_x->clr = pin_index;
      }
    }
    else
    {
      pinx_value = (gpio_init_struct->gpio_mode & 0x08) | (gpio_init_struct->gpio_out_type & 0x04) | \
                   (gpio_init_struct->gpio_drive_strength & 0x03);
    }
  
    /* pin 0~7 config */
    if(((uint32_t)pin_index & ((uint32_t)0x00FF)) != 0x00)
    {
      for(temp = 0; temp < 0x08; temp++)
      {
        if((1 << temp) & pin_index)
        {
          gpio_x->cfglr &= (uint32_t)~(0x0F << (temp * 4));
          gpio_x->cfglr |= (uint32_t)(pinx_value << (temp * 4));
        }
      }
    }
  
    /* pin 8~15 config */
    if(pin_index > 0x00ff)
    {
      pin_index = pin_index >> 8;
  
      for(temp = 0; temp < 0x8; temp++)
      {
        if((1 << temp) & pin_index)
        {
          gpio_x->cfghr &= (uint32_t)~(0xf << (temp * 4));
          gpio_x->cfghr |= (uint32_t)(pinx_value << (temp * 4));
        }
      }
    }
  }
  
  /**
    * @brief  fill each gpio_init_type member with its default value.
    * @param  gpio_init_struct : pointer to a gpio_init_type structure which will be initialized.
    * @retval none
    */
  void gpio_default_para_init(gpio_init_type *gpio_init_struct)
  {
    /* reset gpio init structure parameters values */
    gpio_init_struct->gpio_pins  = GPIO_PINS_ALL;
    gpio_init_struct->gpio_mode = GPIO_MODE_INPUT;
    gpio_init_struct->gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
    gpio_init_struct->gpio_pull = GPIO_PULL_NONE;
    gpio_init_struct->gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  }
  
  /**
    * @brief  read the specified input port pin.
    * @param  gpio_x: to select the gpio peripheral.
    *         this parameter can be one of the following values:
    *         GPIOA, GPIOB, GPIOC, GPIOD, GPIOF.
    * @param  pins: gpio pin number
    *         this parameter can be one of the following values:
    *         - GPIO_PINS_0
    *         - GPIO_PINS_1
    *         - GPIO_PINS_2
    *         - GPIO_PINS_3
    *         - GPIO_PINS_4
    *         - GPIO_PINS_5
    *         - GPIO_PINS_6
    *         - GPIO_PINS_7
    *         - GPIO_PINS_8
    *         - GPIO_PINS_9
    *         - GPIO_PINS_10
    *         - GPIO_PINS_11
    *         - GPIO_PINS_12
    *         - GPIO_PINS_13
    *         - GPIO_PINS_14
    *         - GPIO_PINS_15
    * @retval flag_status (SET or RESET)
    */
  flag_status gpio_input_data_bit_read(gpio_type *gpio_x, uint16_t pins)
  {
    flag_status status = RESET;
  
    if(pins != (pins & gpio_x->idt))
    {
      status = RESET;
    }
    else
    {
      status = SET;
    }
  
    return status;
  }
  
  /**
    * @brief  read the specified gpio input data port.
    * @param  gpio_x: to select the gpio peripheral.
    *         this parameter can be one of the following values:
    *         GPIOA, GPIOB, GPIOC, GPIOD, GPIOF.
    * @retval gpio input data port value.
    */
  uint16_t gpio_input_data_read(gpio_type *gpio_x)
  {
    return ((uint16_t)(gpio_x->idt));
  }
  
  /**
    * @brief  read the specified output port pin.
    * @param  gpio_x: to select the gpio peripheral.
    *         this parameter can be one of the following values:
    *         GPIOA, GPIOB, GPIOC, GPIOD, GPIOF.
    * @param  pins: gpio pin number
    *         this parameter can be one of the following values:
    *         - GPIO_PINS_0
    *         - GPIO_PINS_1
    *         - GPIO_PINS_2
    *         - GPIO_PINS_3
    *         - GPIO_PINS_4
    *         - GPIO_PINS_5
    *         - GPIO_PINS_6
    *         - GPIO_PINS_7
    *         - GPIO_PINS_8
    *         - GPIO_PINS_9
    *         - GPIO_PINS_10
    *         - GPIO_PINS_11
    *         - GPIO_PINS_12
    *         - GPIO_PINS_13
    *         - GPIO_PINS_14
    *         - GPIO_PINS_15
    * @retval flag_status (SET or RESET)
    */
  flag_status gpio_output_data_bit_read(gpio_type *gpio_x, uint16_t pins)
  {
    flag_status status = RESET;
  
    if((gpio_x->odt & pins) != RESET)
    {
      status = SET;
    }
    else
    {
      status = RESET;
    }
  
    return status;
  }
  
  /**
    * @brief  read the specified gpio ouput data port.
    * @param  gpio_x: to select the gpio peripheral.
    *         this parameter can be one of the following values:
    *         GPIOA, GPIOB, GPIOC, GPIOD, GPIOF.
    * @retval gpio input data port value.
    */
  uint16_t gpio_output_data_read(gpio_type *gpio_x)
  {
    return ((uint16_t)(gpio_x->odt));
  }
  
  /**
    * @brief  set the selected data port bits.
    * @param  gpio_x: to select the gpio peripheral.
    *         this parameter can be one of the following values:
    *         GPIOA, GPIOB, GPIOC, GPIOD, GPIOF.
    * @param  pins: gpio pin number
    *         parameter can be any combination of gpio_pin_x, gpio_pin_x as following values:
    *         - GPIO_PINS_0
    *         - GPIO_PINS_1
    *         - GPIO_PINS_2
    *         - GPIO_PINS_3
    *         - GPIO_PINS_4
    *         - GPIO_PINS_5
    *         - GPIO_PINS_6
    *         - GPIO_PINS_7
    *         - GPIO_PINS_8
    *         - GPIO_PINS_9
    *         - GPIO_PINS_10
    *         - GPIO_PINS_11
    *         - GPIO_PINS_12
    *         - GPIO_PINS_13
    *         - GPIO_PINS_14
    *         - GPIO_PINS_15
    *         - GPIO_PINS_ALL
    * @retval none
    */
  void gpio_bits_set(gpio_type *gpio_x, uint16_t pins)
  {
    gpio_x->scr = pins;
  }
  
  /**
    * @brief  clear the selected data port bits.
    * @param  gpio_x: to select the gpio peripheral.
    *         this parameter can be one of the following values:
    *         GPIOA, GPIOB, GPIOC, GPIOD, GPIOF.
    * @param  pins: gpio pin number
    *         parameter can be any combination of gpio_pin_x, gpio_pin_x as following values:
    *         - GPIO_PINS_0
    *         - GPIO_PINS_1
    *         - GPIO_PINS_2
    *         - GPIO_PINS_3
    *         - GPIO_PINS_4
    *         - GPIO_PINS_5
    *         - GPIO_PINS_6
    *         - GPIO_PINS_7
    *         - GPIO_PINS_8
    *         - GPIO_PINS_9
    *         - GPIO_PINS_10
    *         - GPIO_PINS_11
    *         - GPIO_PINS_12
    *         - GPIO_PINS_13
    *         - GPIO_PINS_14
    *         - GPIO_PINS_15
    *         - GPIO_PINS_ALL
    * @retval none
    */
  void gpio_bits_reset(gpio_type *gpio_x, uint16_t pins)
  {
    gpio_x->clr = pins;
  }
  
  /**
    * @brief  set or clear the selected data port bit.
    * @param  gpio_x: to select the gpio peripheral.
    *         this parameter can be one of the following values:
    *         GPIOA, GPIOB, GPIOC, GPIOD, GPIOF.
    * @param  pins: gpio pin number
    *         parameter can be any combination of gpio_pin_x, gpio_pin_x as following values:
    *         - GPIO_PINS_0
    *         - GPIO_PINS_1
    *         - GPIO_PINS_2
    *         - GPIO_PINS_3
    *         - GPIO_PINS_4
    *         - GPIO_PINS_5
    *         - GPIO_PINS_6
    *         - GPIO_PINS_7
    *         - GPIO_PINS_8
    *         - GPIO_PINS_9
    *         - GPIO_PINS_10
    *         - GPIO_PINS_11
    *         - GPIO_PINS_12
    *         - GPIO_PINS_13
    *         - GPIO_PINS_14
    *         - GPIO_PINS_15
    *         - GPIO_PINS_ALL
    * @param  bit_state: specifies the value to be written to the selected bit (TRUE or FALSE).
    * @retval none
    */
  void gpio_bits_write(gpio_type *gpio_x, uint16_t pins, confirm_state bit_state)
  {
    if(bit_state != FALSE)
    {
      gpio_x->scr = pins;
    }
    else
    {
      gpio_x->clr = pins;
    }
  }
  
  /**
    * @brief  write data to the specified gpio data port.
    * @param  gpio_x: to select the gpio peripheral.
    *         this parameter can be one of the following values:
    *         GPIOA, GPIOB, GPIOC, GPIOD, GPIOF.
    * @param  port_value: specifies the value to be written to the port output data register.
    * @retval none
    */
  void gpio_port_wirte(gpio_type *gpio_x, uint16_t port_value)
  {
    gpio_x->odt = port_value;
  }
  
  /**
    * @brief  write protect gpio pins configuration registers.
    * @param  gpio_x: to select the gpio peripheral.
    *         this parameter can be one of the following values:
    *         GPIOA, GPIOB, GPIOC, GPIOD, GPIOF.
    * @param  pins: gpio pin number
    *         this parameter can be any combination of the following:
    *         - GPIO_PINS_0
    *         - GPIO_PINS_1
    *         - GPIO_PINS_2
    *         - GPIO_PINS_3
    *         - GPIO_PINS_4
    *         - GPIO_PINS_5
    *         - GPIO_PINS_6
    *         - GPIO_PINS_7
    *         - GPIO_PINS_8
    *         - GPIO_PINS_9
    *         - GPIO_PINS_10
    *         - GPIO_PINS_11
    *         - GPIO_PINS_12
    *         - GPIO_PINS_13
    *         - GPIO_PINS_14
    *         - GPIO_PINS_15
    *         - GPIO_PINS_ALL
    * @retval none
    */
  void gpio_pin_wp_config(gpio_type *gpio_x, uint16_t pins)
  {
    uint32_t temp = 0x00010000;
  
    temp |= pins;
    /* set wpen bit */
    gpio_x->wpr = temp;
    /* reset wpen bit */
    gpio_x->wpr =  pins;
    /* set wpen bit */
    gpio_x->wpr = temp;
    /* read wpen bit*/
    temp = gpio_x->wpr;
    /* read wpen bit*/
    temp = gpio_x->wpr;
  }
  
  /**
    * @brief  select the gpio pin used as event output.
    * @param  gpio_port_source: select the gpio port to be used as source
    *         for event output.
    *         this parameter can be one of the following values:
    *         - GPIO_PORT_SOURCE_GPIOA
    *         - GPIO_PORT_SOURCE_GPIOB
    *         - GPIO_PORT_SOURCE_GPIOC
    *         - GPIO_PORT_SOURCE_GPIOD
    *         - GPIO_PORT_SOURCE_GPIOF
    * @param  gpio_pin_source: specifies the pin for the event output.
    *         this parameter can be one of the following values:
    *         - GPIO_PINS_SOURCE0
    *         - GPIO_PINS_SOURCE1
    *         - GPIO_PINS_SOURCE2
    *         - GPIO_PINS_SOURCE3
    *         - GPIO_PINS_SOURCE4
    *         - GPIO_PINS_SOURCE5
    *         - GPIO_PINS_SOURCE6
    *         - GPIO_PINS_SOURCE7
    *         - GPIO_PINS_SOURCE8
    *         - GPIO_PINS_SOURCE9
    *         - GPIO_PINS_SOURCE10
    *         - GPIO_PINS_SOURCE11
    *         - GPIO_PINS_SOURCE12
    *         - GPIO_PINS_SOURCE13
    *         - GPIO_PINS_SOURCE14
    *         - GPIO_PINS_SOURCE15
    * @retval none
    */
  void gpio_event_output_config(gpio_port_source_type gpio_port_source, gpio_pins_source_type gpio_pin_source)
  {
    uint32_t tmpreg = 0x00;
  
    tmpreg = IOMUX->evtout;
  
    /* clear the port[6:4] and pin[3:0] bits */
    tmpreg &= 0x80;
    tmpreg |= (uint32_t)gpio_port_source << 0x04;
    tmpreg |= gpio_pin_source;
    IOMUX->evtout = tmpreg;
  }
  
  /**
    * @brief  enable or disable the event output.
    * @param  confirm_state: new state of the event output.
    *         this parameter can be: TRUE or FALSE.
    * @retval none
    */
  void gpio_event_output_enable(confirm_state new_state)
  {
    IOMUX->evtout_bit.evoen = new_state;
  }
  
  /**
    * @brief  iomux remap and debug i/o configuration.
    * @param  gpio_remap: select the pin to remap.
    *         this parameter can be one of the following values:
    *         - SPI1_MUX_01                   - I2C1_MUX                      - USART1_MUX                   - USART3_MUX_01
    *         - TMR1_MUX_01                   - TMR2_MUX_01                   - TMR2_MUX_10                  - TMR2_MUX_11
    *         - TMR3_MUX_10                   - TMR3_MUX_11                   - CAN_MUX_10                   - PD01_MUX
    *         - TMR5CH4_MUX                   - ADC1_EXTRGPRE_MUX             - ADC1_EXTRGORD_MUX            - ADC2_EXTRGPRE_MUX
    *         - ADC2_EXTRGORD_MUX             - SWJTAG_CONF_001               - SWJTAG_CONF_010              - SWJTAG_CONF_100
    *         - EXT_SPIM_EN_MUX               - TMR9_GMUX                     - TMR10_GMUX                   - TMR11_GMUX
    *         - TMR1_GMUX_0001                - TMR2_GMUX_001                 - TMR2_GMUX_010                - TMR2_GMUX_011
    *         - TMR2ITR1_GMUX                 - TMR3_GMUX_0010                - TMR3_GMUX_0011               - TMR5_GMUX_001
    *         - TMR5CH4_GMUX                  - I2C1_GMUX_0001                - I2C1_GMUX_0011               - I2C2_GMUX_0001
    *         - I2C2_GMUX_0010                - I2C2_GMUX_0011                - SPI1_GMUX_0001               - SPI2_GMUX_0001
    *         - CAN1_GMUX_0010                - CAN2_GMUX_0001                - SDIO1_GMUX_0100              - SDIO1_GMUX_0101
    *         - SDIO1_GMUX_0110               - SDIO1_GMUX_0111               - USART1_GMUX_0001             - USART3_GMUX_0001
    *         - UART4_GMUX_0001               - EXT_SPIM_GMUX_1000            - EXT_SPIM_GMUX_1001           - ADC1_ETP_GMUX
    *         - ADC1_ETO_GMUX                 - ADC2_ETP_GMUX                 - ADC2_ETO_GMUX                - SWJTAG_GMUX_001
    *         - SWJTAG_GMUX_010               - SWJTAG_GMUX_100               - PD01_GMUX
    * @param  new_state: (TRUE or FALSE)
    * @retval none
    */
  void gpio_pin_remap_config(uint32_t gpio_remap, confirm_state new_state)
  {
    uint32_t reg_addr, remap_mask;
    uint8_t bit_offset, bit_num, bit_val;
  
    /* get register address, bit offset, bit number and remap value */
    reg_addr = IOMUX_BASE + (gpio_remap >> 24);
    bit_offset = (gpio_remap >> 16) & 0xFF;
    bit_num = (gpio_remap >> 8) & 0xFF;
    bit_val = gpio_remap & 0xFF;
  
    /* get remap mask value */
    remap_mask = 0xFFFFFFFF << (32 - bit_num - bit_offset);
    remap_mask = remap_mask >> (32 - bit_num - bit_offset);
    remap_mask = remap_mask >> bit_offset;
    remap_mask = remap_mask << bit_offset;
  
    /* clear remap value */
    *(uint32_t*)reg_addr &= ~remap_mask;
  
    if(new_state != FALSE)
    {
      /* set remap value */
      *(uint32_t*)reg_addr |= (uint32_t)(bit_val << bit_offset);
    }
  }
  
  /**
    * @brief  select the gpio pin used as exint line.
    * @param  gpio_port_source: select the gpio port to be used as source for exint.
    *         this parameter can be one of the following values:
    *         - GPIO_PORT_SOURCE_GPIOA
    *         - GPIO_PORT_SOURCE_GPIOB
    *         - GPIO_PORT_SOURCE_GPIOC
    *         - GPIO_PORT_SOURCE_GPIOD
    *         - GPIO_PORT_SOURCE_GPIOF
    * @param  gpio_pin_source: specifies the pin for the event output.
    *         this parameter can be one of the following values:
    *         - GPIO_PINS_SOURCE0
    *         - GPIO_PINS_SOURCE1
    *         - GPIO_PINS_SOURCE2
    *         - GPIO_PINS_SOURCE3
    *         - GPIO_PINS_SOURCE4
    *         - GPIO_PINS_SOURCE5
    *         - GPIO_PINS_SOURCE6
    *         - GPIO_PINS_SOURCE7
    *         - GPIO_PINS_SOURCE8
    *         - GPIO_PINS_SOURCE9
    *         - GPIO_PINS_SOURCE10
    *         - GPIO_PINS_SOURCE11
    *         - GPIO_PINS_SOURCE12
    *         - GPIO_PINS_SOURCE13
    *         - GPIO_PINS_SOURCE14
    *         - GPIO_PINS_SOURCE15
    * @retval none
    */
  void gpio_exint_line_config(gpio_port_source_type gpio_port_source, gpio_pins_source_type gpio_pin_source)
  {
    uint32_t tmp = 0x00;
    tmp = ((uint32_t)0x0F) << (0x04 * (gpio_pin_source & (uint8_t)0x03));
  
    switch (gpio_pin_source >> 0x02)
    {
      case 0:
        IOMUX->exintc1 &= ~tmp;
        IOMUX->exintc1 |= (((uint32_t)gpio_port_source) << (0x04 * (gpio_pin_source & (uint8_t)0x03)));
        break;
      case 1:
        IOMUX->exintc2 &= ~tmp;
        IOMUX->exintc2 |= (((uint32_t)gpio_port_source) << (0x04 * (gpio_pin_source & (uint8_t)0x03)));
        break;
      case 2:
        IOMUX->exintc3 &= ~tmp;
        IOMUX->exintc3 |= (((uint32_t)gpio_port_source) << (0x04 * (gpio_pin_source & (uint8_t)0x03)));
        break;
      case 3:
        IOMUX->exintc4 &= ~tmp;
        IOMUX->exintc4 |= (((uint32_t)gpio_port_source) << (0x04 * (gpio_pin_source & (uint8_t)0x03)));
        break;
      default:
        break;
    }
  }
  
  /**
    * @}
    */
  
  #endif
  
  /**
    * @}
    */
  
  /**
    * @}
    */
  