SylixOS下的GPIO驱动实例

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/ScilogyHunter/article/details/100532124

实例源码

下面是 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时要记着清除可能的中断标志,并关闭中断使能,最后调用引脚分配函数让引脚恢复默认功能。

猜你喜欢

转载自blog.csdn.net/ScilogyHunter/article/details/100532124