/**************************************************************************//**
  * \file     GPIO.c
  * \brief    GPIO driver file
  * \details
  * \author   Zhang Xuan
  * \version  V1.0.0
  * \date     9-Jul-2018
  * \par      History:
  *           V1.0.0 Initial release
  * \par      Copyright:
  *           (c) Heilongjiang TYW Electronics co., LTD
******************************************************************************/

/* Includes ------------------------------------------------------------------*/

#include "GPIO.h"

/* Private typedef -----------------------------------------------------------*/

/*** GPIO output data and direction registers access structure ***/
typedef struct
{
  volatile uint32_t RegPODR;
  volatile uint32_t RegDDR;
}GPIO_Reg_Access_st_t;

/*** GPIO output data and direction set /clear registers access structure ***/
typedef struct
{
  volatile uint32_t RegPOSR;
  volatile uint32_t RegPOCR;
  volatile uint32_t RegDDSR;
  volatile uint32_t RegDDCR;
}GPIO_Set_Clear_Reg_Access_t;

/*** GPIO external interrupt parameter structure ***/
typedef struct
{
  uint8_t   EINTNum;
  uint8_t   PortSel;
}GPIO_EINT_Para_st_t;

/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static const GPIO_EINT_Para_st_t GPIOEINTPara[4][32] =
{
{ { 23,   1,}, {  0,   2,}, {  1,   2,}, {  5,   2,},
  {  6,   2,}, {  7,   2,}, {  8,   2,}, { 18,   2,},
  { 19,   2,}, { 20,   2,}, { 21,   2,}, { 22,   2,},
  { 23,   2,}, {  1,   3,}, {  2,   3,}, {  2,   0,},
  {  3,   3,}, {  4,   3,}, {  5,   3,}, {  6,   3,},
  {  7,   3,}, {  8,   3,}, {  3,   0,}, {  9,   3,},
  { 10,   3,}, {  4,   0,}, {  5,   0,}, {  6,   0,},
  {  7,   0,}, { 12,   1,}, {  8,   0,}, {  9,   0,}, },

{ { 10,   0,}, { 11,   0,}, { 12,   0,}, { 19,   3,},
  { 13,   0,}, { 14,   0,}, { 14,   1,}, { 15,   0,},
  { 16,   0,}, {  9,   4,}, { 17,   0,}, { 11,   4,},
  { 18,   0,}, { 12,   4,}, { 19,   0,}, { 13,   4,},
  { 14,   4,}, { 15,   4,}, { 17,   4,}, { 18,   4,},
  { 20,   0,}, { 20,   4,}, { 21,   4,}, { 21,   0,},
  { 22,   4,}, {  0,   5,}, {  2,   5,}, {  3,   5,},
  {  4,   5,}, { 22,   0,}, {  6,   5,}, {  7,   5,}, },

{ { 23,   0,}, {  9,   5,}, {  2,   1,}, { 10,   5,},
  { 11,   5,}, { 12,   5,}, { 13,   5,}, { 14,   5,},
  { 15,   5,}, {  3,   1,}, { 16,   5,}, { 17,   5,},
  { 18,   5,}, { 19,   5,}, { 20,   5,}, { 21,   5,},
  { 22,   5,}, { 23,   5,}, {  0,   0,}, {  0,   6,},
  {  1,   6,}, {  2,   6,}, {  3,   6,}, {  0,   1,},
  {  4,   1,}, {  1,   0,}, {  5,   1,}, { 11,   1,},
  { 13,   1,}, { 15,   1,}, {255, 255,}, {255, 255,}, },

{ {  1,   1,}, {  9,   2,}, { 10,   2,}, { 11,   2,},
  { 12,   2,}, { 15,   2,}, { 16,   2,}, { 17,   2,},
  { 18,   1,}, {  6,   1,}, { 17,   3,}, {  8,   1,},
  { 21,   1,}, { 18,   3,}, {  1,   4,}, { 20,   1,},
  {  0,   4,}, { 17,   1,}, {  2,   4,}, {  3,   4,},
  { 19,   1,}, {  4,   4,}, {  5,   4,}, {  6,   4,},
  {255, 255,}, {255, 255,}, {255, 255,}, {255, 255,},
  {255, 255,}, {255, 255,}, {  7,   1,}, {  9,   1,}, },
};

GPIO_Int_Func_cb_t GPIOIntFuncCbList[16];

/* Private function prototypes -----------------------------------------------*/
static void GPIO_Default_ISR(uint8_t IntNum);

static __arm __irq void GPIO_Ext_Int0_ISR(void);
static __arm __irq void GPIO_Ext_Int1_ISR(void);
static __arm __irq void GPIO_Ext_Int2_ISR(void);
static __arm __irq void GPIO_Ext_Int3_ISR(void);
static __arm __irq void GPIO_Ext_Int4_ISR(void);
static __arm __irq void GPIO_Ext_Int5_ISR(void);
static __arm __irq void GPIO_Ext_Int6_ISR(void);
static __arm __irq void GPIO_Ext_Int7_ISR(void);
static __arm __irq void GPIO_Ext_Int8_ISR(void);
static __arm __irq void GPIO_Ext_Int9_ISR(void);
static __arm __irq void GPIO_Ext_Int10_ISR(void);
static __arm __irq void GPIO_Ext_Int11_ISR(void);
static __arm __irq void GPIO_Ext_Int12_ISR(void);
static __arm __irq void GPIO_Ext_Int13_ISR(void);
static __arm __irq void GPIO_Ext_Int14_ISR(void);
static __arm __irq void GPIO_Ext_Int15_ISR(void);

/* Private functions ---------------------------------------------------------*/

/**************************************************************************//**
  * \brief      GPIO initialization for run mode
  * \retval     None
******************************************************************************/  
void GPIO_Run_Mode_Init(void)
{
  uint16_t  i;
  
  un_gpio_keycdr_t  GPIOKey;
  un_ppc_keycdr_t   PPCKey;
  
  volatile GPIO_Reg_Access_st_t *pGPIOReg;
  volatile uint16_t             *pGPIOCfg;
  
  GPIOKey.u32Register = 0U;
  PPCKey.u32Register  = 0U;

  /*** Step 1: Release I/O-resets (3V, 3/5V domains) ***/
  SYSC0_PROTKEYR = 0x5CACCE55UL;
  SYSC0_SPECFGR_IO35RSTC = 0U;
  SYSC0_PROTKEYR = 0x5CACCE55UL;
  SYSC0_SPECFGR_IO3RSTC = 0U;
  
  /*** Step 2: Disable input ***/
  GPIOKey.stcField.u15RADR  = (uint_io32_t)(&GPIO.unPORTEN) & 0x00007FFFUL;
  GPIOKey.stcField.u2SIZE   = 0x2U;
  
  IRQ_DISABLE_LOCAL()
  GPIOKey.stcField.u2KEY    = 0x0U;
  GPIO_KEYCDR = GPIOKey.u32Register;
  GPIOKey.stcField.u2KEY    = 0x1U;
  GPIO_KEYCDR = GPIOKey.u32Register;
  GPIOKey.stcField.u2KEY    = 0x2U;
  GPIO_KEYCDR = GPIOKey.u32Register;
  GPIOKey.stcField.u2KEY    = 0x3U;
  GPIO_KEYCDR = GPIOKey.u32Register;
  
  GPIO_PORTEN = 0x00000000UL;
  IRQ_RESTORE()
  
  /*** Step 3: Set all ports to input(Hi-z) ***/
  pGPIOReg = (volatile GPIO_Reg_Access_st_t *)(&GPIO.unPODR0);
  for (i = 0U; i < GPIO_VALID_PORT_NUM; i++)
  {
    GPIOKey.stcField.u15RADR  = (uint_io32_t)(&pGPIOReg -> RegDDR) & 0x00007FFFUL;
    GPIOKey.stcField.u2SIZE   = 0x2U;
    
    IRQ_DISABLE_LOCAL()
    GPIOKey.stcField.u2KEY    = 0x0U;
    GPIO_KEYCDR = GPIOKey.u32Register;
    GPIOKey.stcField.u2KEY    = 0x1U;
    GPIO_KEYCDR = GPIOKey.u32Register;
    GPIOKey.stcField.u2KEY    = 0x2U;
    GPIO_KEYCDR = GPIOKey.u32Register;
    GPIOKey.stcField.u2KEY    = 0x3U;
    GPIO_KEYCDR = GPIOKey.u32Register;
    
    pGPIOReg -> RegDDR = 0x00000000UL;
    IRQ_RESTORE()
    
    pGPIOReg++;
  }
  
  /*** Step 4: Set port functions ***/
  for (i = 0U; i < GPIO_VALID_PIN_NUM; i++)
  {
    pGPIOCfg = (volatile uint16_t *)(&PPC.unPCFGR000 + GPIOPinCfg[i].Offset);
    
    PPCKey.stcField.u15RADR = (uint_io32_t)pGPIOCfg & 0x00007FFFUL;
    PPCKey.stcField.u2SIZE  = 0x1U;
    
    IRQ_DISABLE_LOCAL()
    PPCKey.stcField.u2KEY   = 0x0U;
    PPC_KEYCDR = PPCKey.u32Register;
    PPCKey.stcField.u2KEY   = 0x1U;
    PPC_KEYCDR = PPCKey.u32Register; 
    PPCKey.stcField.u2KEY   = 0x2U;
    PPC_KEYCDR = PPCKey.u32Register;
    PPCKey.stcField.u2KEY   = 0x3U;
    PPC_KEYCDR = PPCKey.u32Register;     

    *pGPIOCfg = GPIOPinCfg[i].RunModeCfg;
    IRQ_RESTORE()
  }
  
  /*** Step 5: Set Initial port output level and port direction ***/
  pGPIOReg = (volatile GPIO_Reg_Access_st_t *)(&GPIO.unPODR0);
  for (i = 0U; i < GPIO_VALID_PORT_NUM; i++)
  {
    pGPIOReg -> RegPODR = GPIODirDefCfg[i].RunModeDef;
    
    GPIOKey.stcField.u15RADR  = (uint_io32_t)(&pGPIOReg -> RegDDR) & 0x00007FFFUL;
    GPIOKey.stcField.u2SIZE   = 0x2U;
    
    IRQ_DISABLE_LOCAL()
    GPIOKey.stcField.u2KEY    = 0x0U;
    GPIO_KEYCDR = GPIOKey.u32Register;
    GPIOKey.stcField.u2KEY    = 0x1U;
    GPIO_KEYCDR = GPIOKey.u32Register;
    GPIOKey.stcField.u2KEY    = 0x2U;
    GPIO_KEYCDR = GPIOKey.u32Register;
    GPIOKey.stcField.u2KEY    = 0x3U;
    GPIO_KEYCDR = GPIOKey.u32Register;
    
    pGPIOReg -> RegDDR = GPIODirDefCfg[i].RunModeDir;
    IRQ_RESTORE()
    
    pGPIOReg++;
  }
  
  /*** Step 6: Enable input ***/
  GPIOKey.stcField.u15RADR  = (uint_io32_t)(&GPIO.unPORTEN) & 0x00007FFFUL;
  GPIOKey.stcField.u2SIZE   = 0x2U;
  
  IRQ_DISABLE_LOCAL()
  GPIOKey.stcField.u2KEY    = 0x0U;
  GPIO_KEYCDR = GPIOKey.u32Register;
  GPIOKey.stcField.u2KEY    = 0x1U;
  GPIO_KEYCDR = GPIOKey.u32Register;
  GPIOKey.stcField.u2KEY    = 0x2U;
  GPIO_KEYCDR = GPIOKey.u32Register;
  GPIOKey.stcField.u2KEY    = 0x3U;
  GPIO_KEYCDR = GPIOKey.u32Register;
  
  GPIO_PORTEN = 0x00000001UL;
  IRQ_RESTORE()
  
  /*** Step 8 Register default ISR ***/
  for (i = 0U; i < 16U; i++)
  {
    GPIOIntFuncCbList[i] = NULL;
  }
  
  Interrupt_IRQ_ISR_Register(INTERRUPTS_IRQ_NUMBER_24, (uint32_t)GPIO_Ext_Int0_ISR, 31U);
  Interrupt_IRQ_ISR_Register(INTERRUPTS_IRQ_NUMBER_25, (uint32_t)GPIO_Ext_Int1_ISR, 31U);
  Interrupt_IRQ_ISR_Register(INTERRUPTS_IRQ_NUMBER_26, (uint32_t)GPIO_Ext_Int2_ISR, 31U);
  Interrupt_IRQ_ISR_Register(INTERRUPTS_IRQ_NUMBER_27, (uint32_t)GPIO_Ext_Int3_ISR, 31U);
  Interrupt_IRQ_ISR_Register(INTERRUPTS_IRQ_NUMBER_28, (uint32_t)GPIO_Ext_Int4_ISR, 31U);
  Interrupt_IRQ_ISR_Register(INTERRUPTS_IRQ_NUMBER_29, (uint32_t)GPIO_Ext_Int5_ISR, 31U);
  Interrupt_IRQ_ISR_Register(INTERRUPTS_IRQ_NUMBER_30, (uint32_t)GPIO_Ext_Int6_ISR, 31U);
  Interrupt_IRQ_ISR_Register(INTERRUPTS_IRQ_NUMBER_31, (uint32_t)GPIO_Ext_Int7_ISR, 31U);
  Interrupt_IRQ_ISR_Register(INTERRUPTS_IRQ_NUMBER_32, (uint32_t)GPIO_Ext_Int8_ISR, 31U);
  Interrupt_IRQ_ISR_Register(INTERRUPTS_IRQ_NUMBER_33, (uint32_t)GPIO_Ext_Int9_ISR, 31U);
  Interrupt_IRQ_ISR_Register(INTERRUPTS_IRQ_NUMBER_34, (uint32_t)GPIO_Ext_Int10_ISR, 31U);
  Interrupt_IRQ_ISR_Register(INTERRUPTS_IRQ_NUMBER_35, (uint32_t)GPIO_Ext_Int11_ISR, 31U);
  Interrupt_IRQ_ISR_Register(INTERRUPTS_IRQ_NUMBER_36, (uint32_t)GPIO_Ext_Int12_ISR, 31U);
  Interrupt_IRQ_ISR_Register(INTERRUPTS_IRQ_NUMBER_37, (uint32_t)GPIO_Ext_Int13_ISR, 31U);
  Interrupt_IRQ_ISR_Register(INTERRUPTS_IRQ_NUMBER_38, (uint32_t)GPIO_Ext_Int14_ISR, 31U);
  Interrupt_IRQ_ISR_Register(INTERRUPTS_IRQ_NUMBER_39, (uint32_t)GPIO_Ext_Int15_ISR, 31U);
}

/**************************************************************************//**
  * \brief      GPIO initialization for sleep mode
  * \retval     None
******************************************************************************/  
void GPIO_Sleep_Mode_Init(void)
{
  uint16_t  i;
  
  un_gpio_keycdr_t  GPIOKey;
  un_ppc_keycdr_t   PPCKey;
  
  volatile GPIO_Reg_Access_st_t *pGPIOReg;
  volatile uint16_t             *pGPIOCfg;
  
  GPIOKey.u32Register = 0U;
  PPCKey.u32Register  = 0U;

  /*** Step 1: Disable input ***/
  GPIOKey.stcField.u15RADR  = (uint_io32_t)(&GPIO.unPORTEN) & 0x00007FFFUL;
  GPIOKey.stcField.u2SIZE   = 0x2U;
  
  IRQ_DISABLE_LOCAL()
  GPIOKey.stcField.u2KEY    = 0x0U;
  GPIO_KEYCDR = GPIOKey.u32Register;
  GPIOKey.stcField.u2KEY    = 0x1U;
  GPIO_KEYCDR = GPIOKey.u32Register;
  GPIOKey.stcField.u2KEY    = 0x2U;
  GPIO_KEYCDR = GPIOKey.u32Register;
  GPIOKey.stcField.u2KEY    = 0x3U;
  GPIO_KEYCDR = GPIOKey.u32Register;
  
  GPIO_PORTEN = 0x00000000UL;
  IRQ_RESTORE()
  
  /*** Step 2: Set all ports to input(Hi-z) ***/
  pGPIOReg = (volatile GPIO_Reg_Access_st_t *)(&GPIO.unPODR0);
  for (i = 0U; i < GPIO_VALID_PORT_NUM; i++)
  {
    GPIOKey.stcField.u15RADR  = (uint_io32_t)(&pGPIOReg -> RegDDR) & 0x00007FFFUL;
    GPIOKey.stcField.u2SIZE   = 0x2U;
   
    IRQ_DISABLE_LOCAL()
    GPIOKey.stcField.u2KEY    = 0x0U;
    GPIO_KEYCDR = GPIOKey.u32Register;
    GPIOKey.stcField.u2KEY    = 0x1U;
    GPIO_KEYCDR = GPIOKey.u32Register;
    GPIOKey.stcField.u2KEY    = 0x2U;
    GPIO_KEYCDR = GPIOKey.u32Register;
    GPIOKey.stcField.u2KEY    = 0x3U;
    GPIO_KEYCDR = GPIOKey.u32Register;
    
    pGPIOReg -> RegDDR = 0x00000000UL;
    IRQ_RESTORE()
    
    pGPIOReg++;
  }
  
  /*** Step 3: Set port functions ***/
  for (i = 0U; i < GPIO_VALID_PIN_NUM; i++)
  {
    pGPIOCfg = (volatile uint16_t *)(&PPC.unPCFGR000 + GPIOPinCfg[i].Offset);
    
    PPCKey.stcField.u15RADR = (uint_io32_t)pGPIOCfg & 0x00007FFFUL;
    PPCKey.stcField.u2SIZE  = 0x1U;
    
    IRQ_DISABLE_LOCAL()
    PPCKey.stcField.u2KEY   = 0x0U;
    PPC_KEYCDR = PPCKey.u32Register;
    PPCKey.stcField.u2KEY   = 0x1U;
    PPC_KEYCDR = PPCKey.u32Register; 
    PPCKey.stcField.u2KEY   = 0x2U;
    PPC_KEYCDR = PPCKey.u32Register;
    PPCKey.stcField.u2KEY   = 0x3U;
    PPC_KEYCDR = PPCKey.u32Register;     

    *pGPIOCfg = GPIOPinCfg[i].SleepModeCfg;
    IRQ_RESTORE()
  }
  
  /*** Step 4: Set Initial port output level and port direction ***/
  pGPIOReg = (volatile GPIO_Reg_Access_st_t *)(&GPIO.unPODR0);
  for (i = 0U; i < GPIO_VALID_PORT_NUM; i++)
  {
    pGPIOReg -> RegPODR = GPIODirDefCfg[i].SleepModeDef;
    
    GPIOKey.stcField.u15RADR  = (uint_io32_t)(&pGPIOReg -> RegDDR) & 0x00007FFFUL;
    GPIOKey.stcField.u2SIZE   = 0x2U;
    
    IRQ_DISABLE_LOCAL()
    GPIOKey.stcField.u2KEY    = 0x0U;
    GPIO_KEYCDR = GPIOKey.u32Register;
    GPIOKey.stcField.u2KEY    = 0x1U;
    GPIO_KEYCDR = GPIOKey.u32Register;
    GPIOKey.stcField.u2KEY    = 0x2U;
    GPIO_KEYCDR = GPIOKey.u32Register;
    GPIOKey.stcField.u2KEY    = 0x3U;
    GPIO_KEYCDR = GPIOKey.u32Register;
    
    pGPIOReg -> RegDDR = GPIODirDefCfg[i].SleepModeDir;
    IRQ_RESTORE()
    
    pGPIOReg++;
  }
  
  /*** Step 5: Enable input ***/
  GPIOKey.stcField.u15RADR  = (uint_io32_t)(&GPIO.unPORTEN) & 0x00007FFFUL;
  GPIOKey.stcField.u2SIZE   = 0x2U;
  
  IRQ_DISABLE_LOCAL()
  GPIOKey.stcField.u2KEY    = 0x0U;
  GPIO_KEYCDR = GPIOKey.u32Register;
  GPIOKey.stcField.u2KEY    = 0x1U;
  GPIO_KEYCDR = GPIOKey.u32Register;
  GPIOKey.stcField.u2KEY    = 0x2U;
  GPIO_KEYCDR = GPIOKey.u32Register;
  GPIOKey.stcField.u2KEY    = 0x3U;
  GPIO_KEYCDR = GPIOKey.u32Register;
  
  GPIO_PORTEN = 0x00000001U;
  IRQ_RESTORE()
}

/**************************************************************************//**
  * \brief      Set direction for a specified pin
  * \attention  1. If pin direction is changed after initialization, the pin  
  *                may not be accessed by the remapped pin name, use original 
  *                pin input / output register name (GPIO_PIDRx_PIDy / 
  *                GPIO_PODRx_PODy) to access the pin.
  *             2. The pin direction setting does not affect the input enable 
  *                bit (PIE) of the pin.
  * \param      PortNum: Port number(0 - 6), specify the port to set
  * \param      PinNum:  Pin number(0 - 31), specify the pin to set  
  * \param      Dir:     Desired direction
  *             This parameter can be one of the following values:
  *             \arg GPIO_DIR_IN:  Input direction
  *             \arg GPIO_DIR_OUT: Output direction
  * \retval     None
******************************************************************************/
void GPIO_Set_Pin_Direction(uint8_t PortNum, uint8_t PinNum, GPIO_Pin_Dir_en_t Dir)
{
  uint32_t          Mask;
  uint_io32_t      *pReg;
  un_gpio_keycdr_t  GPIOKey;
  volatile GPIO_Set_Clear_Reg_Access_t *pGPIOSetClr;
  
  if ((PortNum < GPIO_VALID_PORT_NUM) && (PinNum < 32U))
  {
    GPIOKey.u32Register = 0UL;
    Mask          = (uint32_t)(1UL << PinNum);
    pGPIOSetClr   = (volatile GPIO_Set_Clear_Reg_Access_t *)(&GPIO.unPOSR0);
    pGPIOSetClr  += PortNum;
    if (Dir)
    {
      pReg = (uint_io32_t *)(&pGPIOSetClr -> RegDDSR);
    }
    else
    {
      pReg = (uint_io32_t *)(&pGPIOSetClr -> RegDDCR);
    }
    
    GPIOKey.stcField.u15RADR  = (uint_io32_t)pReg;
    GPIOKey.stcField.u2SIZE   = 0x2U;
    
    IRQ_DISABLE_LOCAL()
    GPIOKey.stcField.u2KEY    = 0x0U;
    GPIO_KEYCDR = GPIOKey.u32Register;
    GPIOKey.stcField.u2KEY    = 0x1U;
    GPIO_KEYCDR = GPIOKey.u32Register;
    GPIOKey.stcField.u2KEY    = 0x2U;
    GPIO_KEYCDR = GPIOKey.u32Register;
    GPIOKey.stcField.u2KEY    = 0x3U;
    GPIO_KEYCDR = GPIOKey.u32Register;
    
    *pReg = Mask;
    IRQ_RESTORE()
  }
}

/**************************************************************************//**
  * \brief      Set pull up / down for a specified pin
  * \param      PortNum: Port number(0 - 6), specify the port to set
  * \param      PinNum:  Pin number(0 - 31), specify the pin to set  
  * \param      UpDn:    Pull up / down
  *             This parameter can be one of the following values:
  *             \arg GPIO_PULL_NONE: Neither pull up nor pulling down
  *             \arg GPIO_PULL_DOWN: Pull down
  *             \arg GPIO_PULL_UP: Pull up
  * \retval     None
******************************************************************************/
void GPIO_Set_Pin_Pull_Up_Dn(uint8_t PortNum, uint8_t PinNum, GPIO_Pin_Pull_Up_Dn_en_t UpDn)
{
  uint16_t Offset;
  
  un_ppc_pcfgrn_t     PPCReg;
  un_ppc_keycdr_t     PPCKey;
  volatile uint16_t   *pGPIOCfg;
  
  if ((PortNum < GPIO_VALID_PORT_NUM) && (PinNum < 32U))
  {
    Offset = (uint16_t)PortNum * 32U + (uint16_t)PinNum;
    pGPIOCfg = (volatile uint16_t *)(&PPC.unPCFGR000 + Offset);
    PPCReg.u16Register = *pGPIOCfg;
    
    if (UpDn == GPIO_PULL_UP)
    {
      PPCReg.stcField.u1PDE = 0U;
      PPCReg.stcField.u1PUE = 1U;
    }
    else if (UpDn == GPIO_PULL_DOWN)
    {
      PPCReg.stcField.u1PDE = 1U;
      PPCReg.stcField.u1PUE = 0U;
    }
    else
    {
      PPCReg.stcField.u1PDE = 0U;
      PPCReg.stcField.u1PUE = 0U;
    }
    
    PPCKey.stcField.u15RADR = (uint_io32_t)pGPIOCfg & 0x00007FFFUL;
    PPCKey.stcField.u2SIZE  = 0x1U;
    
    IRQ_DISABLE_LOCAL()
    PPCKey.stcField.u2KEY   = 0x0U;
    PPC_KEYCDR = PPCKey.u32Register;
    PPCKey.stcField.u2KEY   = 0x1U;
    PPC_KEYCDR = PPCKey.u32Register; 
    PPCKey.stcField.u2KEY   = 0x2U;
    PPC_KEYCDR = PPCKey.u32Register;
    PPCKey.stcField.u2KEY   = 0x3U;
    PPC_KEYCDR = PPCKey.u32Register;

    *pGPIOCfg = PPCReg.u16Register;
    IRQ_RESTORE()
  }
}

/**************************************************************************//**
  * \brief      Set configuration for a specified pin
  * \attention  Since all the GPIO pins are configured after calling the 
  *             initialization functions, this function is only used to 
  *             reconfigure the GPIO pin when the pin function changes.
  * \param      PortNum: Port number(0 - 6), specify the port to set
  * \param      PinNum:  Pin number(0 - 31), specify the pin to set  
  * \param      pCfg: pointer to a GPIO_Pin_Cfg_st_t structure that contains
  *             the configuration information for the specified pin. In this 
  *             structure, out of range parameters will be taken as 0
  * \retval     None
******************************************************************************/
void GPIO_Set_Pin_Config(uint8_t PortNum, uint8_t PinNum, GPIO_Pin_Cfg_st_t *pCfg)
{
  uint16_t Offset;
  
  un_ppc_pcfgrn_t     PPCReg;
  un_ppc_keycdr_t     PPCKey;
  volatile uint16_t   *pGPIOCfg;
  
  if ((PortNum < GPIO_VALID_PORT_NUM) && (PinNum < 32U))
  {
    Offset = (uint16_t)PortNum * 32U + (uint16_t)PinNum;
    pGPIOCfg = (volatile uint16_t *)(&PPC.unPCFGR000 + Offset);
    PPCReg.u16Register = 0x0000U;
    
    if (pCfg -> OutputFuncID < 8U)
    {
      PPCReg.stcField.u3POF = pCfg -> OutputFuncID;
    }
    
    if (pCfg -> OutputDrvCap < 4U)
    {
      PPCReg.stcField.u2ODR = pCfg -> OutputDrvCap;
    }
    
    if (pCfg -> InputEnable)
    {
      PPCReg.stcField.u1PIE = 1U;
    }
    
    if (pCfg -> InputLevel < 4U)
    {
      PPCReg.stcField.u2PIL = pCfg -> InputLevel;
    }
    
    if (pCfg -> PullUpDn == GPIO_PULL_UP)
    {
      PPCReg.stcField.u1PDE = 0U;
      PPCReg.stcField.u1PUE = 1U;
    }
    else if (pCfg -> PullUpDn == GPIO_PULL_DOWN)
    {
      PPCReg.stcField.u1PDE = 1U;
      PPCReg.stcField.u1PUE = 0U;
    }
    else
    {
      
    }

    if (pCfg -> FilterEnable)
    {
      PPCReg.stcField.u1NFE = 1U;
    }
    
    PPCKey.stcField.u15RADR = (uint_io32_t)pGPIOCfg & 0x00007FFFUL;
    PPCKey.stcField.u2SIZE  = 0x1U;
    
    IRQ_DISABLE_LOCAL()
    PPCKey.stcField.u2KEY   = 0x0U;
    PPC_KEYCDR = PPCKey.u32Register;
    PPCKey.stcField.u2KEY   = 0x1U;
    PPC_KEYCDR = PPCKey.u32Register; 
    PPCKey.stcField.u2KEY   = 0x2U;
    PPC_KEYCDR = PPCKey.u32Register;
    PPCKey.stcField.u2KEY   = 0x3U;
    PPC_KEYCDR = PPCKey.u32Register;

    *pGPIOCfg = PPCReg.u16Register;
    IRQ_RESTORE()
  }
}

void GPIO_Set_Interrupt_Mode(uint8_t PortNum, uint8_t PinNum, GPIO_Int_Mode_en_t Mode, uint8_t NoiseFilter, GPIO_Int_Func_cb_t pFuncCb)
{
  uint8_t   IntNum;
  uint32_t  IntBit;
  uint32_t  LevelBit;
  uint32_t  RegVal;
  
  volatile un_ric_resinn_t   *pResInput;
  un_ric_resinn_t             ResInputCfg;
  un_ric_keycdr_t             RICKey;
  
  if ((PortNum < GPIO_VALID_PORT_NUM) && (PinNum < 32U))
  {
    IntNum  = GPIOEINTPara[PortNum][PinNum].EINTNum;
    if (IntNum < 24U)
    {
      /*** Config resource input ***/
      ResInputCfg.u16Register = 0U;
      ResInputCfg.stcField.u4PORTSEL = GPIOEINTPara[PortNum][PinNum].PortSel;
      
      pResInput  = &RIC.unRESIN251;
      pResInput += IntNum;
      
      RICKey.u32Register = 0U;
      RICKey.stcField.u15RADR = (uint_io32_t)pResInput & 0x00007FFFUL;
      RICKey.stcField.u2SIZE  = 0x1U;
      
      IRQ_DISABLE_LOCAL()
      RICKey.stcField.u2KEY   = 0x0U;
      RIC_KEYCDR = RICKey.u32Register;
      RICKey.stcField.u2KEY   = 0x1U;
      RIC_KEYCDR = RICKey.u32Register;
      RICKey.stcField.u2KEY   = 0x2U;
      RIC_KEYCDR = RICKey.u32Register;
      RICKey.stcField.u2KEY   = 0x3U;
      RIC_KEYCDR = RICKey.u32Register;
      
      pResInput -> u16Register = ResInputCfg.u16Register;
      
      IRQ_RESTORE()
      
      /*** Config external interrupt ***/
      
      /* Disable interrupt before configuration */
      IntBit = (1U << IntNum);
      EIC00_ENICR = IntBit;
      EIC00_ENICR;
      NOP(); NOP(); NOP(); NOP(); NOP(); NOP();
      
      if (Mode != GPIO_INT_DISABLE)
      {
        /* Set specific level to ELVRx register */
        LevelBit = (uint32_t)Mode - 1U;
        
        if (IntNum < 8U)
        {
          GPIOIntFuncCbList[IntNum] = pFuncCb;
          
          LevelBit    <<= (uint8_t)(IntNum << 2U);
          RegVal        = EIC00_ELVR0;
          RegVal       &= ~(0x0000000FUL << (uint8_t)(IntNum << 2U));
          RegVal       |= LevelBit;
          EIC00_ELVR0   = RegVal;
        }
        else if (IntNum < 16U)
        {
          GPIOIntFuncCbList[IntNum] = pFuncCb;
          
          LevelBit    <<= ((IntNum - 8U) << 2U);
          RegVal        = EIC00_ELVR1;
          RegVal       &= ~(0x0000000FUL << ((IntNum - 8U) << 2U));
          RegVal       |= LevelBit;
          EIC00_ELVR1   = RegVal;
        }
        else
        {
          GPIOIntFuncCbList[IntNum - 16U] = pFuncCb;
          
          LevelBit    <<= ((IntNum - 16U) << 2U);
          RegVal        = EIC00_ELVR2;
          RegVal       &= ~(0x0000000FUL << ((IntNum - 16U) << 2U));
          RegVal       |= LevelBit;
          EIC00_ELVR2   = RegVal;
        }
        
        /* Input noise filter settting */
        if (NoiseFilter)
        {
          EIC00_NFESR = IntBit;
        }
        else
        {
          EIC00_NFECR = IntBit;
        }
            
        /* Disable DMA request */
        EIC00_DRECR = IntBit;
        
        /* Clear interrupt flag */
        EIC00_EIRCR = IntBit;
        EIC00_EIRCR;
        DMB();

        /* Activate external interrupt enable bit in register */
        EIC00_ENISR = IntBit;
      }
    }
  }
}

static void GPIO_Default_ISR(uint8_t IntNum)
{
  uint32_t IntBit;
  
  if (IntNum < 16U)
  {
    IntBit = (0x00010001UL << IntNum) & 0x00FFFFFFUL;
    
    /* Clear interrupt flag */
    EIC00_EIRCR = IntBit;
    EIC00_EIRCR;
    DMB();
    
    /* Disable interrupt */
    EIC00_ENICR = IntBit;
    EIC00_ENICR;
    NOP(); NOP(); NOP(); NOP(); NOP(); NOP();
    
    if (GPIOIntFuncCbList[IntNum] != NULL)
    {
      GPIOIntFuncCbList[IntNum]();
    }
    
    IRC0_IRQHC = INTERRUPTS_IRQ_NUMBER_24 + IntNum;
  }
}

static __arm __irq void GPIO_Ext_Int0_ISR(void)
{
  GPIO_Default_ISR(0U);
}

static __arm __irq void GPIO_Ext_Int1_ISR(void)
{
  GPIO_Default_ISR(1U);
}

static __arm __irq void GPIO_Ext_Int2_ISR(void)
{
  GPIO_Default_ISR(2U);
}

static __arm __irq void GPIO_Ext_Int3_ISR(void)
{
  GPIO_Default_ISR(3U);
}

static __arm __irq void GPIO_Ext_Int4_ISR(void)
{
  GPIO_Default_ISR(4U);
}

static __arm __irq void GPIO_Ext_Int5_ISR(void)
{
  GPIO_Default_ISR(5U);
}

static __arm __irq void GPIO_Ext_Int6_ISR(void)
{
  GPIO_Default_ISR(6U);
}

static __arm __irq void GPIO_Ext_Int7_ISR(void)
{
  GPIO_Default_ISR(7U);
}

static __arm __irq void GPIO_Ext_Int8_ISR(void)
{
  GPIO_Default_ISR(8U);
}

static __arm __irq void GPIO_Ext_Int9_ISR(void)
{
  GPIO_Default_ISR(9U);
}

static __arm __irq void GPIO_Ext_Int10_ISR(void)
{
  GPIO_Default_ISR(10U);
}

static __arm __irq void GPIO_Ext_Int11_ISR(void)
{
  GPIO_Default_ISR(11U);
}

static __arm __irq void GPIO_Ext_Int12_ISR(void)
{
  GPIO_Default_ISR(12U);
}

static __arm __irq void GPIO_Ext_Int13_ISR(void)
{
  GPIO_Default_ISR(13U);
}

static __arm __irq void GPIO_Ext_Int14_ISR(void)
{
  GPIO_Default_ISR(14U);
}

static __arm __irq void GPIO_Ext_Int15_ISR(void)
{
  GPIO_Default_ISR(15U);
}
