MXC-A36_2024.04.18/fr3092_mcu/components/drivers/peripheral/Src/driver_gpio.c

427 lines
14 KiB
C
Raw Normal View History

2024-04-17 19:45:26 +08:00
/*
******************************************************************************
* @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++;
}
}