版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
实例源码
下面是 i.MX RT1050 的GPIO驱动实现源码:
/*********************************************************************************************************
**
** 中国软件开源组织
**
** 嵌入式实时操作系统
**
** SylixOS(TM) LW : long wing
**
** Copyright All Rights Reserved
**
**--------------文件信息--------------------------------------------------------------------------------
**
** 文 件 名: gpio.c
**
** 创 建 人: Hou.JinYu (侯进宇)
**
** 文件创建日期: 2017 年 12 月 13 日
**
** 描 述: GPIO 驱动,为 SylixOS 提供的功能支持.
*********************************************************************************************************/
/*********************************************************************************************************
i.MX RT1050 芯片集成 5 组通用输入输出接口(GPIO1~GPIO5),每组最多 32 个GPIO接口(pin0~pin31)
每一个 GPIO 都可以独立配置成输入口或输出口,都可作为中断输入使用。
在本驱动中将 GPIO1~GPIO5 定义为 GPIO_PORT_A~GPIO_PORT_E
驱动基于fsl_iomuxc 和 fsl_gpio 驱动
*********************************************************************************************************/
#define __SYLIXOS_KERNEL
#include "config.h"
#include "SylixOS.h"
#include <linux/compat.h>
#include "pinmux/pinmux.h"
#include "gpio/gpio.h"
#include "fsl_common.h"
#include "fsl_iomuxc.h"
#include "fsl_gpio.h"
/*********************************************************************************************************
** 函数名称: imxrt1050GpioGetBase
** 功能描述: 获取GPIO组寄存器地址
** 输 入 : uiPinGroup GPIO组号
** 输 出 : pBase GPIO组寄存器地址,失败输出 NULL
*********************************************************************************************************/
static GPIO_Type *imxrt1050GpioGetBase (UINT32 uiPinGroup)
{
GPIO_Type *pBase = NULL;
if ((uiPinGroup >= 0) && (uiPinGroup <= 3)) {
pBase = (GPIO_Type *)(GPIO1_BASE + uiPinGroup * 0x4000);
} else if (uiPinGroup == 4) {
pBase = GPIO5;
}
return (pBase);
}
/*********************************************************************************************************
** 函数名称: imxrt1050GpioRequest
** 功能描述: 实现 GPIO 管脚的 PINMUX 设置
** 输 入 : pGpioChip GPIO 芯片
** uiOffset GPIO 编号
** 输 出 : ERROR CODE
*********************************************************************************************************/
static INT imxrt1050GpioRequest (PLW_GPIO_CHIP pGpioChip, UINT uiOffset)
{
UINT32 uiPinGroup = GPIO_PORT(uiOffset);
UINT32 uiPinNum = GPIO_PIN(uiOffset);
pinmuxGPIOEnable(uiPinGroup, uiPinNum, LW_TRUE);
return (ERROR_NONE);
}
/*********************************************************************************************************
** 函数名称: imxrt1050GpioFree
** 功能描述: 释放一个正在被使用的 GPIO, 如果当前是中断模式则, 放弃中断输入功能.
** 输 入 : pGpioChip GPIO 芯片
** uiOffset GPIO 编号
** 输 出 : ERROR CODE
*********************************************************************************************************/
static VOID imxrt1050GpioFree (PLW_GPIO_CHIP pGpioChip, UINT uiOffset)
{
UINT32 uiPinGroup = GPIO_PORT(uiOffset);
UINT32 uiPinNum = GPIO_PIN(uiOffset);
GPIO_Type *pBase = imxrt1050GpioGetBase(uiPinGroup);
if (pBase == NULL) {
return;
}
GPIO_PortDisableInterrupts(pBase, 1 << uiPinNum); /* Disable pin interrupt */
GPIO_PortClearInterruptFlags(pBase, (1 << uiPinNum));
pinmuxGPIOEnable(uiPinGroup, uiPinNum, LW_FALSE);
}
/*********************************************************************************************************
** 函数名称: imxrt1050GpioGetDirection
** 功能描述: 获得指定 GPIO 方向
** 输 入 : pGpioChip GPIO 芯片
** uiOffset GPIO 编号
** 输 出 : 0:输入 1:输出 -1:错误
*********************************************************************************************************/
static INT imxrt1050GpioGetDirection (PLW_GPIO_CHIP pGpioChip, UINT uiOffset)
{
UINT32 uiValue;
UINT32 uiPinGroup = GPIO_PORT(uiOffset);
UINT32 uiPinNum = GPIO_PIN(uiOffset);
GPIO_Type *pBase = imxrt1050GpioGetBase(uiPinGroup);
if (pBase == NULL) {
return (PX_ERROR);
}
uiValue = (pBase->GDIR & (1U << uiPinNum)) ? 1 : 0;
return (uiValue);
}
/*********************************************************************************************************
** 函数名称: imxrt1050GpioDirectionInput
** 功能描述: 设置指定 GPIO 为输入模式
** 输 入 : pGpioChip GPIO 芯片
** uiOffset GPIO 编号
** 输 出 : 0: 正确 -1:错误
*********************************************************************************************************/
static INT imxrt1050GpioDirectionInput (PLW_GPIO_CHIP pGpioChip, UINT uiOffset)
{
gpio_pin_config_t config = {
.direction = kGPIO_DigitalInput,
.outputLogic = 0,
.interruptMode = kGPIO_NoIntmode,
};
UINT32 uiPinGroup = GPIO_PORT(uiOffset);
UINT32 uiPinNum = GPIO_PIN(uiOffset);
GPIO_Type *pBase = imxrt1050GpioGetBase(uiPinGroup);
if (pBase == NULL) {
return (PX_ERROR);
}
GPIO_PinInit(pBase, uiPinNum, &config);
return (ERROR_NONE);
}
/*********************************************************************************************************
** 函数名称: imxrt1050GpioGet
** 功能描述: 获得指定 GPIO 电平
** 输 入 : pGpioChip GPIO 芯片
** uiOffset GPIO 编号
** 输 出 : 0: 低电平 1:高电平 -1:错误
*********************************************************************************************************/
static INT imxrt1050GpioGet (PLW_GPIO_CHIP pGpioChip, UINT uiOffset)
{
UINT32 uiPinGroup = GPIO_PORT(uiOffset);
UINT32 uiPinNum = GPIO_PIN(uiOffset);
GPIO_Type *pBase = imxrt1050GpioGetBase(uiPinGroup);
if (pBase == NULL) {
return (PX_ERROR);
}
return (GPIO_PinRead(pBase, uiPinNum));
}
/*********************************************************************************************************
** 函数名称: imxrt1050GpioSet
** 功能描述: 设置指定 GPIO 电平
** 输 入 : pGpioChip GPIO 芯片
** uiOffset GPIO 编号
** iValue 输出电平
** 输 出 : 无
*********************************************************************************************************/
static VOID imxrt1050GpioSet (PLW_GPIO_CHIP pGpioChip, UINT uiOffset, INT iValue)
{
UINT32 uiPinGroup = GPIO_PORT(uiOffset);
UINT32 uiPinNum = GPIO_PIN(uiOffset);
GPIO_Type *pBase = imxrt1050GpioGetBase(uiPinGroup);
if (pBase == NULL) {
return;
}
GPIO_PinWrite(pBase, uiPinNum, iValue);
}
/*********************************************************************************************************
** 函数名称: imxrt1050GpioDirectionOutput
** 功能描述: 设置指定 GPIO 为输出模式
** 输 入 : pGpioChip GPIO 芯片
** uiOffset GPIO 编号
** iValue 输出电平
** 输 出 : 0: 正确 -1:错误
*********************************************************************************************************/
static INT imxrt1050GpioDirectionOutput (PLW_GPIO_CHIP pGpioChip, UINT uiOffset, INT iValue)
{
gpio_pin_config_t config = {
.direction = kGPIO_DigitalOutput,
.outputLogic = iValue,
.interruptMode = kGPIO_NoIntmode,
};
UINT32 uiPinGroup = GPIO_PORT(uiOffset);
UINT32 uiPinNum = GPIO_PIN(uiOffset);
GPIO_Type *pBase = imxrt1050GpioGetBase(uiPinGroup);
if (pBase == NULL) {
return (PX_ERROR);
}
GPIO_PinInit(pBase, uiPinNum, &config);
return (ERROR_NONE);
}
/*********************************************************************************************************
** 函数名称: imxrt1050GpioSetDebounce
** 功能描述: 设置指定 GPIO 的去抖参数
** 输 入 : pGpioChip GPIO 芯片
** uiOffset GPIO 编号
** uiDebounce 去抖参数
** 输 出 : ERROR CODE
*********************************************************************************************************/
static INT imxrt1050GpioSetDebounce (PLW_GPIO_CHIP pGpioChip, UINT uiOffset, UINT uiDebounce)
{
UINT32 uiPinGroup = GPIO_PORT(uiOffset);
UINT32 uiPinNum = GPIO_PIN(uiOffset);
UINT32 ulConfigRegister;
UINT32 ulConfigValue;
ulConfigRegister = pinmuxGPIOConfigAddrGet(uiPinGroup, uiPinNum);
if (ulConfigRegister == PX_ERROR) {
return (PX_ERROR);
}
ulConfigValue = read32(ulConfigRegister);
ulConfigValue &= ~(1 << 16);
ulConfigValue |= uiDebounce ? (1 << 16) : 0;
write32(ulConfigValue, ulConfigRegister);
return (ERROR_NONE);
}
/*********************************************************************************************************
** 函数名称: imxrt1050GpioSetPull
** 功能描述: 设置 GPIO 上拉
** 输 入 : pGpioChip GPIO 芯片
** uiOffset GPIO 编号
** uiType 上下拉类型(0 表示开路,1 表示上拉,2 表示下拉)
** 输 出 : ERROR CODE
*********************************************************************************************************/
static INT imxrt1050GpioSetPull (PLW_GPIO_CHIP pGpioChip, UINT uiOffset, UINT uiType)
{
UINT32 uiPinGroup = GPIO_PORT(uiOffset);
UINT32 uiPinNum = GPIO_PIN(uiOffset);
UINT32 ulConfigRegister;
UINT32 ulConfigValue;
ulConfigRegister = pinmuxGPIOConfigAddrGet(uiPinGroup, uiPinNum);
if (ulConfigRegister == PX_ERROR) {
return (PX_ERROR);
}
ulConfigValue = read32(ulConfigRegister);
ulConfigValue &= ~(0xf << 12);
if (uiType == 1) {
ulConfigValue |= 0xf << 12;
} else if (uiType == 2) {
ulConfigValue |= 0xc << 12;
}
write32(ulConfigValue, ulConfigRegister);
return (ERROR_NONE);
}
/*********************************************************************************************************
** 函数名称: imxrt1050GpioGetupIrq
** 功能描述: 获取指定 GPIO 中断号
** 输 入 : pGpioChip GPIO 芯片
** uiOffset GPIO 编号
** bIsLevel 是否为电平触发, 1 表示电平触发,0 表示边沿触发
** uiType 如果为电平触发, 1 表示高电平触发, 0 表示低电平触发
** 如果为边沿触发, 1 表示上升沿触发, 0 表示下降沿触发, 2 双边沿触发
** 输 出 : IRQ 向量号 -1:错误
*********************************************************************************************************/
static ULONG imxrt1050GpioGetIrq (PLW_GPIO_CHIP pGpioChip,
UINT uiOffset,
BOOL bIsLevel,
UINT uiType)
{
ULONG ulVector;
if (uiOffset <= GPIO_A_07) {
ulVector = BSP_IRQ_TO_VECTOR(GPIO1_INT0_IRQn + uiOffset);
} else if (uiOffset <= GPIO_A_15) {
ulVector = BSP_IRQ_TO_VECTOR(GPIO1_Combined_0_15_IRQn);
} else if (uiOffset <= GPIO_A_31) {
ulVector = BSP_IRQ_TO_VECTOR(GPIO1_Combined_16_31_IRQn);
} else if (uiOffset <= GPIO_B_15) {
ulVector = BSP_IRQ_TO_VECTOR(GPIO2_Combined_0_15_IRQn);
} else if (uiOffset <= GPIO_B_31) {
ulVector = BSP_IRQ_TO_VECTOR(GPIO2_Combined_16_31_IRQn);
} else if (uiOffset <= GPIO_C_15) {
ulVector = BSP_IRQ_TO_VECTOR(GPIO3_Combined_0_15_IRQn);
} else if (uiOffset <= GPIO_C_31) {
ulVector = BSP_IRQ_TO_VECTOR(GPIO3_Combined_16_31_IRQn);
} else if (uiOffset <= GPIO_D_15) {
ulVector = BSP_IRQ_TO_VECTOR(GPIO4_Combined_0_15_IRQn);
} else if (uiOffset <= GPIO_D_31) {
ulVector = BSP_IRQ_TO_VECTOR(GPIO4_Combined_16_31_IRQn);
} else if (uiOffset <= GPIO_E_15) {
ulVector = BSP_IRQ_TO_VECTOR(GPIO5_Combined_0_15_IRQn);
} else if (uiOffset <= GPIO_E_31) {
ulVector = BSP_IRQ_TO_VECTOR(GPIO5_Combined_16_31_IRQn);
} else {
return (PX_ERROR);
}
return (ulVector);
}
/*********************************************************************************************************
** 函数名称: imxrt1050GpioSetupIrq
** 功能描述: 设置指定 GPIO 为外部中断输入管脚
** 输 入 : pGpioChip GPIO 芯片
** uiOffset GPIO 编号
** bIsLevel 是否为电平触发, 1 表示电平触发,0 表示边沿触发
** uiType 如果为电平触发, 1 表示高电平触发, 0 表示低电平触发
** 如果为边沿触发, 1 表示上升沿触发, 0 表示下降沿触发, 2 双边沿触发
** 输 出 : IRQ 向量号 -1:错误
*********************************************************************************************************/
static ULONG imxrt1050GpioSetupIrq (PLW_GPIO_CHIP pGpioChip,
UINT uiOffset,
BOOL bIsLevel,
UINT uiType)
{
gpio_pin_config_t config = {
.direction = kGPIO_DigitalInput,
.outputLogic = 0,
.interruptMode = kGPIO_NoIntmode,
};
ULONG ulVector;
UINT32 uiPinGroup = GPIO_PORT(uiOffset);
UINT32 uiPinNum = GPIO_PIN(uiOffset);
GPIO_Type *pBase = imxrt1050GpioGetBase(uiPinGroup);
if (pBase == NULL) {
return (PX_ERROR);
}
if (bIsLevel) { /* 电平触发 (in Low-power mode)*/
if (uiType == 1) {
config.interruptMode = kGPIO_IntHighLevel; /* 高电平触发 */
} else if (uiType == 0) {
config.interruptMode = kGPIO_IntLowLevel; /* 低电平触发 */
}
} else { /* 边沿触发(in Normal operation*/
if (uiType == 2) {
config.interruptMode = kGPIO_IntRisingOrFallingEdge; /* 双边沿触发 */
} else {
if (uiType == 1) {
config.interruptMode = kGPIO_IntRisingEdge; /* 上升沿触发 */
} else if (uiType == 0) {
config.interruptMode = kGPIO_IntFallingEdge; /* 下降沿触发 */
}
}
}
GPIO_PinInit(pBase, uiPinNum, &config);
GPIO_PortClearInterruptFlags(pBase, (1 << uiPinNum));
GPIO_PortEnableInterrupts(pBase, 1 << uiPinNum); /* Enables pin interrupt */
ulVector = imxrt1050GpioGetIrq(pGpioChip, uiOffset, bIsLevel, uiType);
return (ulVector);
}
/*********************************************************************************************************
** 函数名称: imxrt1050GpioClearIrq
** 功能描述: 清除指定 GPIO 中断标志
** 输 入 : pGpioChip GPIO 芯片
** uiOffset GPIO 编号
** 输 出 : NONE
*********************************************************************************************************/
static VOID imxrt1050GpioClearIrq (PLW_GPIO_CHIP pGpioChip, UINT uiOffset)
{
UINT32 uiPinGroup = GPIO_PORT(uiOffset);
UINT32 uiPinNum = GPIO_PIN(uiOffset);
GPIO_Type *pBase = imxrt1050GpioGetBase(uiPinGroup);
if (pBase == NULL) {
return;
}
GPIO_PortClearInterruptFlags(pBase, (1 << uiPinNum));
}
/*********************************************************************************************************
** 函数名称: imxrt1050GpioSvrIrq
** 功能描述: 判断 GPIO 中断标志
** 输 入 : pGpioChip GPIO 芯片
** uiOffset GPIO 编号
** 输 出 : 中断返回值
*********************************************************************************************************/
static irqreturn_t imxrt1050GpioSvrIrq (PLW_GPIO_CHIP pGpioChip, UINT uiOffset)
{
UINT32 uiPinGroup = GPIO_PORT(uiOffset);
UINT32 uiPinNum = GPIO_PIN(uiOffset);
GPIO_Type *pBase = imxrt1050GpioGetBase(uiPinGroup);
if (pBase == NULL) {
return (LW_IRQ_NONE);
}
if ((1 << uiPinNum) & GPIO_PortGetInterruptFlags(pBase)) { /* 读取中断标志位 */
return (LW_IRQ_HANDLED);
}
return (LW_IRQ_NONE);
}
/*********************************************************************************************************
** 函数名称: gpioDrv
** 功能描述: 安装 GPIO 驱动
** 输 入 : NONE
** 输 出 : ERROR_CODE
*********************************************************************************************************/
INT gpioDrv (VOID)
{
static LW_GPIO_CHIP imxrt1050GpioChip = {
.GC_pcLabel = "i.MX RT1050 GPIO",
.GC_ulVerMagic = LW_GPIO_VER_MAGIC,
.GC_uiBase = 0,
.GC_uiNGpios = 32 * 5,
.GC_pfuncRequest = imxrt1050GpioRequest,
.GC_pfuncFree = imxrt1050GpioFree,
.GC_pfuncGetDirection = imxrt1050GpioGetDirection,
.GC_pfuncDirectionInput = imxrt1050GpioDirectionInput,
.GC_pfuncGet = imxrt1050GpioGet,
.GC_pfuncDirectionOutput = imxrt1050GpioDirectionOutput,
.GC_pfuncSetDebounce = imxrt1050GpioSetDebounce,
.GC_pfuncSetPull = imxrt1050GpioSetPull,
.GC_pfuncSet = imxrt1050GpioSet,
.GC_pfuncGetIrq = imxrt1050GpioGetIrq,
.GC_pfuncSetupIrq = imxrt1050GpioSetupIrq,
.GC_pfuncClearIrq = imxrt1050GpioClearIrq,
.GC_pfuncSvrIrq = imxrt1050GpioSvrIrq,
};
CLOCK_EnableClock(kCLOCK_Gpio1);
CLOCK_EnableClock(kCLOCK_Gpio2);
CLOCK_EnableClock(kCLOCK_Gpio3);
CLOCK_EnableClock(kCLOCK_Gpio4);
CLOCK_EnableClock(kCLOCK_Gpio5);
return (API_GpioChipAdd(&imxrt1050GpioChip));
}
/*********************************************************************************************************
END
*********************************************************************************************************/
源码说明
- 每个函数的参数定义和功能描述都已在注释中说明。
- 因为芯片厂家提供了外设驱动库,所以这里的回调函数通过调用驱动库函数实现而不是直接去读写GPIO寄存器。具体GPIO寄存器的操作和官方驱动库的用法不在本文说明范围,需要的可以查阅NXP官方文档。
-除了要操作GPIO寄存器外,还要调用系统时钟和引脚分配模块的功能。需要先初始化所有端口时钟,请求使用GPIO时要将相应引脚分配为GPIO功能。 - 设置好 imxrt1050GpioChip 的起始编号(GC_uiBase)和总数量(GC_uiNGpios)。系统中每一个GPIO的编号都是唯一的,所以各LW_GPIO_CHIP 的范围不能重叠。
- 一些不常用的接口可以不实现,此时其函数指针应赋值为空指针。
- 中断处理相关的函数,只存在GPIO设备自身的寄存器,不涉及中断控制器操作。如
imxrt1050GpioClearIrq
函数只清除GPIO自己的中断标志位,中断向量标志位会在驱动框架内部自动调用中断控制器接口进行清除。 - 释放GPIO时要记着清除可能的中断标志,并关闭中断使能,最后调用引脚分配函数让引脚恢复默认功能。