GPIO driver instance under SylixOS

Disclaimer: This article is a blogger original article, follow the CC 4.0 BY-SA copyright agreement, reproduced, please attach the original source link and this statement.
This link: https://blog.csdn.net/ScilogyHunter/article/details/100532124

Source code examples

Here is the i.MX RT1050 realization of GPIO driver source code:

/*********************************************************************************************************
**
**                                    中国软件开源组织
**
**                                   嵌入式实时操作系统
**
**                                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
*********************************************************************************************************/

Source Description

  • Parameter definitions and functional description of each function are described in the comments.
  • Because the chip manufacturer provides a peripheral driver library, so here it is driven by calling the callback function library routines to read and write rather than directly GPIO registers. Usage of driver library operations and official specific GPIO register is not illustrate the scope of this article, you need can be found in NXP official documents.
    - GPIO registers in addition to the operation, but also the function to call the system clock and pin assignment module. All ports need to initialize clocks, to the pin assignment request for the use of the GPIO GPIO function.
  • Imxrt1050GpioChip set the starting number (GC_uiBase) and the total number (GC_uiNGpios). Each GPIO system number is unique, so the range of each LW_GPIO_CHIP not overlap.
  • Some not commonly used interfaces may not be achieved, at which time it must be assigned the function pointer is a null pointer.
  • The interrupt handling related functions, there is only GPIO registers the device itself, the operation does not involve the interrupt controller. As imxrt1050GpioClearIrqa function of clear only GPIO own interrupt flag, interrupt vector flag will automatically call in the framework of the internal drive controller interface interrupt cleared.
  • GPIO to remember to clear the release may interrupt flag, interrupt enable and shut down, the last call to make pin assignments Pin function to restore the default function.

Guess you like

Origin blog.csdn.net/ScilogyHunter/article/details/100532124