/* ****************************************************************************** * @file driver_gpio.c * @author FreqChip Firmware Team * @version V1.0.0 * @date 2021 * @brief GPIO module driver. * This file provides firmware functions to manage the * General Purpose Input/Output (GPIO) peripheral ****************************************************************************** * @attention * * Copyright (c) 2021 FreqChip. * All rights reserved. ****************************************************************************** */ #include "fr30xx.h" /************************************************************************************ * @fn gpio_init * * @brief Initializes the GPIOx peripheral according to the specified * parameters in the GPIO_Init * * @param fe_GPIO: to select the GPIO peripheral. * GPIO_Init: pointer to a GPIO_InitTypeDef structure that contains the * configuration information for the specified GPIO peripheral. */ __RAM_CODE void gpio_init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init) { uint32_t lu32_Position = 0; uint32_t lu32_Current_Pin; volatile uint32_t *GPIO_Pull_EN; volatile uint32_t *GPIO_Pull_Select; volatile uint32_t *GPIO_FuncMuxL; volatile uint32_t *GPIO_FuncMuxH; /* Select the group register */ if (GPIOx == GPIOA) { GPIO_Pull_EN = &(SYSTEM->PortA_PullEN); GPIO_Pull_Select = &(SYSTEM->PortA_PullSelect); GPIO_FuncMuxL = &(SYSTEM->PortA_L_FuncMux); GPIO_FuncMuxH = &(SYSTEM->PortA_H_FuncMux); } else if (GPIOx == GPIOB) { GPIO_Pull_EN = &(SYSTEM->PortB_PullEN); GPIO_Pull_Select = &(SYSTEM->PortB_PullSelect); GPIO_FuncMuxL = &(SYSTEM->PortB_L_FuncMux); GPIO_FuncMuxH = &(SYSTEM->PortB_H_FuncMux); } else if (GPIOx == GPIOC) { GPIO_Pull_EN = &(SYSTEM->PortC_PullEN); GPIO_Pull_Select = &(SYSTEM->PortC_PullSelect); GPIO_FuncMuxL = &(SYSTEM->PortC_L_FuncMux); GPIO_FuncMuxH = &(SYSTEM->PortC_H_FuncMux); } else if (GPIOx == GPIOD) { GPIO_Pull_EN = &(SYSTEM->PortD_PullEN); GPIO_Pull_Select = &(SYSTEM->PortD_PullSelect); GPIO_FuncMuxL = &(SYSTEM->PortD_L_FuncMux); GPIO_FuncMuxH = &(SYSTEM->PortD_H_FuncMux); } /* Configure Select pins */ while ((GPIO_Init->Pin) >> lu32_Position != 0) { /* Get current pin position */ lu32_Current_Pin = (GPIO_Init->Pin) & (1uL << lu32_Position); if (lu32_Current_Pin) { switch (GPIO_Init->Mode) { case GPIO_MODE_INPUT: { GPIOx->GPIO_OutputEN |= lu32_Current_Pin; GPIOx->EXTI_EN &= ~lu32_Current_Pin; GPIOx->EXTI_INT_EN &= ~lu32_Current_Pin; }break; case GPIO_MODE_INPUT_HRS: { GPIOx->GPIO_OutputEN |= lu32_Current_Pin; GPIOx->EXTI_EN &= ~lu32_Current_Pin; GPIOx->EXTI_INT_EN &= ~lu32_Current_Pin; /* High Resistance Mode does not pull up or down */ GPIO_Init->Pull = GPIO_NOPULL; }break; case GPIO_MODE_OUTPUT_PP: { GPIOx->GPIO_OutputEN &= ~lu32_Current_Pin; GPIOx->EXTI_EN &= ~lu32_Current_Pin; GPIOx->EXTI_INT_EN &= ~lu32_Current_Pin; }break; case GPIO_MODE_AF_PP: { /* Port 0 ~ 7 */ if (lu32_Position < 8) { *GPIO_FuncMuxL = (*GPIO_FuncMuxL & ~(0xF << (lu32_Position * 4))) | (GPIO_Init->Alternate << (lu32_Position * 4)); } /* Port 8 ~ 15 */ else { *GPIO_FuncMuxH = (*GPIO_FuncMuxH & ~(0xF << ((lu32_Position - 8) * 4))) | (GPIO_Init->Alternate << ((lu32_Position - 8) * 4)); } }break; case GPIO_MODE_EXTI_IT_RISING: case GPIO_MODE_EXTI_IT_FALLING: case GPIO_MODE_EXTI_IT_HIGH_LEVEL: case GPIO_MODE_EXTI_IT_LOW_LEVEL: { GPIOx->EXTI_TYPE = (GPIOx->EXTI_TYPE & ~(0x3 << (lu32_Position * 2))) | ((GPIO_Init->Mode & 0x3) << (lu32_Position * 2)); GPIOx->GPIO_OutputEN |= lu32_Current_Pin; GPIOx->EXTI_EN |= lu32_Current_Pin; GPIOx->EXTI_INT_EN &= ~lu32_Current_Pin; }break; default: break; } /* GPIO Function */ if (GPIO_Init->Mode & GPIO_MODE_IO_MASK) { /* Port 0 ~ 7 */ if (lu32_Position < 8) { *GPIO_FuncMuxL = *GPIO_FuncMuxL & ~(0xF << (lu32_Position * 4)); } /* Port 8 ~ 15 */ else { *GPIO_FuncMuxH = *GPIO_FuncMuxH & ~(0xF << ((lu32_Position - 8) * 4)); } } /* Set Pull UP/DOWN or NO Pull */ if (GPIO_Init->Pull == GPIO_NOPULL) { *GPIO_Pull_EN &= ~lu32_Current_Pin; } else if (GPIO_Init->Pull == GPIO_PULLUP) { *GPIO_Pull_EN |= lu32_Current_Pin; *GPIO_Pull_Select |= lu32_Current_Pin; } else if (GPIO_Init->Pull == GPIO_PULLDOWN) { *GPIO_Pull_EN |= lu32_Current_Pin; *GPIO_Pull_Select &= ~lu32_Current_Pin; } } lu32_Position++; } } /************************************************************************************ * @fn gpio_set_portpull * * @brief set port pull * * @param GPIOx: where x can be (GPIOA ~ GPIOB) to select the GPIO peripheral. * @param fu16_Pin: to select the Pin (1bit ~ 1Pin). @ref GPIO_pins * @param fe_Pull: pull up/pull down/no pull @ref enum_Pull_t * @return pin status. */ void gpio_set_portpull(GPIO_TypeDef *GPIOx, uint16_t fu16_Pin, enum_Pull_t fe_Pull) { uint32_t lu32_Position = 0; uint32_t lu32_Current_Pin; volatile uint32_t *GPIO_Pull_EN; volatile uint32_t *GPIO_Pull_Select; /* Select the group register */ if (GPIOx == GPIOA) { GPIO_Pull_EN = &(SYSTEM->PortA_PullEN); GPIO_Pull_Select = &(SYSTEM->PortA_PullSelect); } else if (GPIOx == GPIOB) { GPIO_Pull_EN = &(SYSTEM->PortB_PullEN); GPIO_Pull_Select = &(SYSTEM->PortB_PullSelect); } else if (GPIOx == GPIOC) { GPIO_Pull_EN = &(SYSTEM->PortC_PullEN); GPIO_Pull_Select = &(SYSTEM->PortC_PullSelect); } else if (GPIOx == GPIOD) { GPIO_Pull_EN = &(SYSTEM->PortD_PullEN); GPIO_Pull_Select = &(SYSTEM->PortD_PullSelect); } /* Configure Select pins */ while (fu16_Pin >> lu32_Position != 0) { /* Get current pin position */ lu32_Current_Pin = fu16_Pin & (1uL << lu32_Position); if (lu32_Current_Pin) { /* Set Pull UP or DOWN or NO */ if (fe_Pull == GPIO_NOPULL) { *GPIO_Pull_EN &= ~lu32_Current_Pin; } else if (fe_Pull == GPIO_PULLUP) { *GPIO_Pull_EN |= lu32_Current_Pin; *GPIO_Pull_Select |= lu32_Current_Pin; } else if (fe_Pull == GPIO_PULLDOWN) { *GPIO_Pull_EN |= lu32_Current_Pin; *GPIO_Pull_Select &= ~lu32_Current_Pin; } } lu32_Position++; } } /************************************************************************************ * @fn gpio_write_group * * @brief write gpio status, The unit is group. * * @param GPIOx: where x can be (GPIOA ~ GPIOD) to select the GPIO peripheral. * @param fu16_GroupStatus: Group Status.(1bit ~ 1Pin) */ void gpio_write_group(GPIO_TypeDef *GPIOx, uint16_t fu16_GroupStatus) { GPIOx->GPIO_OUT_DATA = fu16_GroupStatus; } /************************************************************************************ * @fn gpio_write_pin * * @brief write gpio status, The unit is pin. * * @param GPIOx: where x can be (GPIOA ~ GPIOD) to select the GPIO peripheral. * @param fu16_Pin: to select the Pin (1bit ~ 1Pin). @ref GPIO_pins * @param fe_PinStatus: pin Status. @ref enum_PinStatus_t */ void gpio_write_pin(GPIO_TypeDef *GPIOx, uint16_t fu16_Pin, enum_PinStatus_t fe_PinStatus) { if (fe_PinStatus) { GPIOx->GPIO_BIT_SET = fu16_Pin; } else { GPIOx->GPIO_BIT_CLEAR = fu16_Pin; } } /************************************************************************************ * @fn gpio_read_group * * @brief read gpio status, The unit is group. * * @param GPIOx: where x can be (GPIOA ~ GPIOD) to select the GPIO peripheral. * @return group status.(1bit ~ 1Pin) */ uint16_t gpio_read_group(GPIO_TypeDef *GPIOx) { return GPIOx->GPIO_IN_DATA; } /************************************************************************************ * @fn gpio_read_pin * * @brief read gpio status, The unit is pin. * * @param GPIOx: where x can be (GPIOA ~ GPIOD) to select the GPIO peripheral. * @param fu16_Pin: to select the Pin (1bit ~ 1Pin). @ref GPIO_pins * @return pin status. */ enum_PinStatus_t gpio_read_pin(GPIO_TypeDef *GPIOx, uint16_t fu16_Pin) { enum_PinStatus_t le_PinStatus; le_PinStatus = (GPIOx->GPIO_IN_DATA & fu16_Pin) ? GPIO_PIN_SET : GPIO_PIN_CLEAR; return le_PinStatus; } /************************************************************************************ * @fn gpio_drive_current_config * * @brief gpio drive current config. * * @param GPIOx: where x can be (GPIOA ~ GPIOD) to select the GPIO peripheral. * @param fu16_Pin: to select the Pin (1bit ~ 1Pin). @ref GPIO_pins * @param fe_GPIO_Drive: Drive Current. @ref enum_GPIO_Drive_Current_t */ void gpio_drive_current_config(GPIO_TypeDef *GPIOx, uint16_t fu16_Pin, enum_GPIO_Drive_Current_t fe_GPIO_Drive) { uint32_t lu32_Position = 0; uint32_t lu32_Current_Pin; /* Configure Select pins */ while (fu16_Pin >> lu32_Position != 0) { /* Get current pin position */ lu32_Current_Pin = fu16_Pin & (1uL << lu32_Position); if (lu32_Current_Pin) { if (GPIOx == GPIOA) SYSTEM->PortA_DriveCfg = (SYSTEM->PortA_DriveCfg & ~(0x3 << (lu32_Position * 2))) | (fe_GPIO_Drive << (lu32_Position * 2)); else if (GPIOx == GPIOB) SYSTEM->PortB_DriveCfg = (SYSTEM->PortB_DriveCfg & ~(0x3 << (lu32_Position * 2))) | (fe_GPIO_Drive << (lu32_Position * 2)); else if (GPIOx == GPIOC) SYSTEM->PortC_DriveCfg = (SYSTEM->PortC_DriveCfg & ~(0x3 << (lu32_Position * 2))) | (fe_GPIO_Drive << (lu32_Position * 2)); else if (GPIOx == GPIOD) SYSTEM->PortD_DriveCfg = (SYSTEM->PortD_DriveCfg & ~(0x3 << (lu32_Position * 2))) | (fe_GPIO_Drive << (lu32_Position * 2)); } lu32_Position++; } } /************************************************************************************ * @fn exti_interrupt_enable * * @brief exti line interrupt enable. * * @param GPIOx: where x can be (GPIOA ~ GPIOD) to select the GPIO peripheral. * @param fu16_EXTI_Line: to select the EXTI line.(1bit ~ 1Pin) */ void exti_interrupt_enable(GPIO_TypeDef *GPIOx, uint16_t fu16_EXTI_Line) { GPIOx->EXTI_INT_EN |= fu16_EXTI_Line; } /************************************************************************************ * @fn exti_interrupt_disable * * @brief exti line interrupt disable. * * @param GPIOx: where x can be (GPIOA ~ GPIOD) to select the GPIO peripheral. * @param fu16_EXTI_Line: to select the EXTI line (1bit ~ 1Pin). @ref EXTI_line_index */ void exti_interrupt_disable(GPIO_TypeDef *GPIOx, uint16_t fu16_EXTI_Line) { GPIOx->EXTI_INT_EN &= ~fu16_EXTI_Line; } /************************************************************************************ * @fn exti_get_LineStatus * * @brief get exti line interrupt status. * * @param GPIOx: where x can be (GPIOA ~ GPIOD) to select the GPIO peripheral. * @param fu8_EXTI_Line: to select the EXTI line (1bit ~ 1Pin). @ref EXTI_line_index * @return true: interrupt activate * false: interrupt inactivate */ bool exti_get_LineStatus(GPIO_TypeDef *GPIOx, uint16_t fu16_EXTI_Line) { bool lb_EXTIStatus; lb_EXTIStatus = (GPIOx->EXTI_INT_STATUS & fu16_EXTI_Line) ? true : false; return lb_EXTIStatus; } /************************************************************************************ * @fn exti_clear_LineStatus * * @brief clear exti line interrupt status. * * @param GPIOx: where x can be (GPIOA ~ GPIOD) to select the GPIO peripheral. * @param fu8_EXTI_Line: to select the EXTI line (1bit ~ 1Pin). @ref EXTI_line_index */ void exti_clear_LineStatus(GPIO_TypeDef *GPIOx, uint16_t fu16_EXTI_Line) { GPIOx->EXTI_INT_STATUS |= fu16_EXTI_Line; } /************************************************************************************ * @fn exti_set_FilterCNT * * @brief set exti line filer. * * @param GPIOx: where x can be (GPIOA ~ GPIOD) to select the GPIO peripheral. * @param fu16_EXTI_Line: to select the EXTI line (1bit ~ 1Pin). @ref EXTI_line_index * @param fu8_DIV: filter clock divider. (can be a 4-bit value) * @param fu16_CNT: filter count. (can be a 12-bit value) */ void exti_set_Filter(GPIO_TypeDef *GPIOx, uint16_t fu16_EXTI_Line, uint8_t fu8_DIV, uint16_t fu16_CNT) { uint32_t lu32_Position = 0; uint32_t lu32_Current_Pin; /* Init write value */ uint32_t lu32_WriteValue = fu8_DIV << 12 | fu16_CNT; /* Configure Select pins */ while (fu16_EXTI_Line >> lu32_Position != 0) { /* Get current pin position */ lu32_Current_Pin = fu16_EXTI_Line & (1uL << lu32_Position); if (lu32_Current_Pin) { GPIOx->EXTI_CNT[lu32_Position] = lu32_WriteValue; } lu32_Position++; } }