在驱动层使用GPIO的中断功能的简化接口

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

接口说明

为了简化驱动层使用GPIO中断功能的复杂性,我将其封装成了两个接口,类似于系统提供的API标准接口,使用GPIO中断功能时直接请求一个中断模式GPIO即可,用完后再调用相应的释放函数。这两个函数封装了GPIO的中断处理接口、中断API函数和一些必要的流程及异常处理。如下面所示:

/*********************************************************************************************************
  GPIO_IRQ 对象结构体
*********************************************************************************************************/
typedef struct {
    UINT    uiGpio;                                                     /*  GPIO 编号                   */
    ULONG   ulFlags;                                                    /*  GPIO 配置参数               */

    VOID  (*pFunc)(PVOID);                                              /*  中断回调函数                */
    PVOID   pvArg;                                                      /*  回调函数参数                */
    CPCHAR  pcLabel;                                                    /*  GPIO 标签名称               */
    CPCHAR  pcIrqName;                                                  /*  GPIO 中断名称               */

    ULONG   ulVector;                                                   /*  GPIO 中断号                 */
} GPIO_IRQ;
/*********************************************************************************************************
** 函数名称: API_GpioIrqRequest
** 功能描述: 请求使用一个中断模式的 GPIO
** 输 入  : pGpioIrq      中断GPIO对象
** 输 出  : ERROR_CODE
*********************************************************************************************************/
static  INT  API_GpioIrqRequest (GPIO_IRQ  *pGpioIrq);
/*********************************************************************************************************
** 函数名称: API_GpioIrqFree
** 功能描述: 释放一个中断模式的 GPIO
** 输 入  : pGpioIrq      中断GPIO对象
** 输 出  : ERROR_CODE
*********************************************************************************************************/
static  INT  API_GpioIrqFree (GPIO_IRQ  *pGpioIrq);

实现代码

/*********************************************************************************************************
**
**                                    中国软件开源组织
**
**                                   嵌入式实时操作系统
**
**                                SylixOS(TM)  LW : long wing
**
**                               Copyright All Rights Reserved
**
**--------------文件信息--------------------------------------------------------------------------------
**
** 文   件   名: gpioIrqLib.h
**
** 创   建   人: Hou.JinYu (侯进宇)
**
** 文件创建日期: 2017 年 12 月 13 日
**
** 描        述: GPIO 中断模式简化接口
*********************************************************************************************************/
#define __SYLIXOS_KERNEL
#include "SylixOS.h"
/*********************************************************************************************************
  GPIO_IRQ 对象结构体
*********************************************************************************************************/
typedef struct {
    UINT    uiGpio;                                                     /*  GPIO 编号                   */
    ULONG   ulFlags;                                                    /*  GPIO 配置参数               */

    VOID  (*pFunc)(PVOID);                                              /*  中断回调函数                */
    PVOID   pvArg;                                                      /*  回调函数参数                */
    CPCHAR  pcLabel;                                                    /*  GPIO 标签名称               */
    CPCHAR  pcIrqName;                                                  /*  GPIO 中断名称               */

    ULONG   ulVector;                                                   /*  GPIO 中断号                 */
} GPIO_IRQ;
/*********************************************************************************************************
** 函数名称: __gpioIsr
** 功能描述: GPIO 中断服务函数
** 输    入: pvArg      输入参数
**           ulVector   中断向量
** 输    出: 中断返回值
*********************************************************************************************************/
static irqreturn_t  __gpioIsr (PVOID pvArg, ULONG  ulVector)
{
    irqreturn_t  irqret;
    GPIO_IRQ    *pGpioIrq;

    pGpioIrq = (GPIO_IRQ   *)pvArg;
    if (pGpioIrq == NULL) {
        return  (LW_IRQ_NONE);
    }
    irqret = API_GpioSvrIrq(pGpioIrq->uiGpio);

    if (LW_IRQ_HANDLED == irqret) {
        API_GpioClearIrq(pGpioIrq->uiGpio);
        if (pGpioIrq->pFunc) {
            pGpioIrq->pFunc(pGpioIrq->pvArg);
        }
    }

    return  (irqret);
}
/*********************************************************************************************************
** 函数名称: API_GpioIrqRequest
** 功能描述: 请求使用一个中断模式的 GPIO
** 输 入  : pGpioIrq      中断GPIO对象
** 输 出  : ERROR_CODE
*********************************************************************************************************/
static  INT  API_GpioIrqRequest (GPIO_IRQ  *pGpioIrq)
{
    INT  iRet;

    if (pGpioIrq == NULL) {
        return  (PX_ERROR);
    }

    iRet = API_GpioRequestOne(pGpioIrq->uiGpio, LW_GPIOF_DIR_IN, pGpioIrq->pcLabel);
    if (iRet != ERROR_NONE) {
        return  (PX_ERROR);
    }

    pGpioIrq->ulVector = API_GpioGetIrq(pGpioIrq->uiGpio, 0, 0);
    if (pGpioIrq->ulVector < 0) {
        return  (PX_ERROR);
    }

    if (pGpioIrq->ulFlags & LW_GPIODF_TRIG_LEVEL) {
        if (pGpioIrq->ulFlags & LW_GPIODF_TRIG_FALL) {                  /*  设置为低电平触发            */
            iRet = API_GpioSetupIrq(pGpioIrq->uiGpio, 1, 0);

        } else if (pGpioIrq->ulFlags & LW_GPIODF_TRIG_RISE) {           /*  设置为高电平触发            */
            iRet = API_GpioSetupIrq(pGpioIrq->uiGpio, 1, 1);
        }
    } else {
        if ((pGpioIrq->ulFlags & LW_GPIODF_TRIG_FALL) &&
            (pGpioIrq->ulFlags & LW_GPIODF_TRIG_RISE)) {                /*  设置为双边沿触发            */
            iRet = API_GpioSetupIrq(pGpioIrq->uiGpio, 0, 2);

        } else if (pGpioIrq->ulFlags & LW_GPIODF_TRIG_FALL) {           /*  设置为下降沿触发            */
            iRet = API_GpioSetupIrq(pGpioIrq->uiGpio, 0, 0);

        } else if (pGpioIrq->ulFlags & LW_GPIODF_TRIG_RISE) {           /*  设置为上升沿触发            */
            iRet = API_GpioSetupIrq(pGpioIrq->uiGpio, 0, 1);
        }
    }
    if (iRet == LW_VECTOR_INVALID) {
        return  (PX_ERROR);
    }

    API_InterVectorConnect(pGpioIrq->ulVector,                          /*  注册中断服务函数            */
                           (PINT_SVR_ROUTINE)__gpioIsr,
                           pGpioIrq,
                           pGpioIrq->pcIrqName);
    API_InterVectorEnable(pGpioIrq->ulVector);

    return  (ERROR_NONE);
}
/*********************************************************************************************************
** 函数名称: API_GpioIrqFree
** 功能描述: 释放一个中断模式的 GPIO
** 输 入  : pGpioIrq      中断GPIO对象
** 输 出  : ERROR_CODE
*********************************************************************************************************/
static  INT  API_GpioIrqFree (GPIO_IRQ  *pGpioIrq)
{
    API_InterVectorDisable(pGpioIrq->ulVector);
    API_InterVectorDisconnect(pGpioIrq->ulVector,                       /*  注册中断服务函数            */
                             (PINT_SVR_ROUTINE)__gpioIsr,
                              pGpioIrq);
    API_GpioFree(pGpioIrq->uiGpio);

    return  (ERROR_NONE);
}
/*********************************************************************************************************
  END
*********************************************************************************************************/

使用例程

/*********************************************************************************************************
**
**                                    中国软件开源组织
**
**                                   嵌入式实时操作系统
**
**                                SylixOS(TM)  LW : long wing
**
**                               Copyright All Rights Reserved
**
**--------------文件信息--------------------------------------------------------------------------------
**
** 文   件   名: gpioDrvExample3.c
**
** 创   建   人: Hou.JinYu (侯进宇)
**
** 文件创建日期: 2017 年 12 月 13 日
**
** 描        述: gpio 在驱动中的调用例程,针对NXP i.MX-RT1050 EVK开发版。
**               因为连接板载 LED01 的引脚同时也连接了 enet 的复位脚,硬件冲突故不能使用。
**               LED02 只是一个空闲的gpio(为J22.7),需要用户连接LED或万用表来检测电平变化。
*********************************************************************************************************/
#define __SYLIXOS_KERNEL
#include "stdio.h"
#include "SylixOS.h"
#include "gpio/gpio.h"
#include "gpioIrqLib.h"
/*********************************************************************************************************
   引脚宏定义
 ********************************************************************************************************/
#define KEY08        GPIO_E_00                                          /*  GPIO5--00                   */
#define LED01        GPIO_A_09                                          /*  GPIO1--09                   */
#define LED02        GPIO_A_18                                          /*  GPIO1--18                   */
/*********************************************************************************************************
  GPIO_TEST 对象结构体
*********************************************************************************************************/
typedef struct {
    UINT                uiGpioLed;                                      /*  GPIO编号                   */
    UINT                uiIrqCount;                                     /*  中断计数值                 */
    LW_OBJECT_HANDLE    hSemBIrq;                                       /*  信号量句柄                 */
} GPIO_TEST;
/*********************************************************************************************************
** 函数名称: gpioDrvExample3CallBack
** 功能描述: GPIO 中断回调函数
** 输    入: pvArg      输入参数
** 输    出: 无
*********************************************************************************************************/
static VOID  gpioDrvExample3CallBack (PVOID pvArg)
{
    GPIO_TEST  *pGpioTest = (GPIO_TEST  *)pvArg;

    pGpioTest->uiIrqCount++;
    API_SemaphoreBPost(pGpioTest->hSemBIrq);
}
/*********************************************************************************************************
** 函数名称: gpioDrvExample3
** 功能描述: gpio 中断例程
** 输    入: NONE
** 输    出: ERROR_CODE
*********************************************************************************************************/
INT  gpioDrvExample3 (VOID)
{
    INT          iRet;
    GPIO_TEST    gpioTest;
    GPIO_IRQ     gpioIrq;

    printf("Gpio interrupt example. Waiting press the key SW8.\n");

    gpioIrq.uiGpio    = KEY08;
    gpioIrq.ulFlags   = LW_GPIODF_TRIG_FALL;
    gpioIrq.pFunc     = gpioDrvExample3CallBack;
    gpioIrq.pvArg     = (PVOID)&gpioTest;
    gpioIrq.pcLabel   = "key";
    gpioIrq.pcIrqName = "key_isr";
    iRet = API_GpioIrqRequest(&gpioIrq);
    if (iRet != ERROR_NONE) {
        return  (PX_ERROR);
    }

    gpioTest.uiGpioLed  = LED02;
    gpioTest.uiIrqCount = 0;
    gpioTest.hSemBIrq   = API_SemaphoreBCreate("gpioTest",
                                               LW_FALSE,
                                               LW_OPTION_OBJECT_LOCAL |
                                               LW_OPTION_WAIT_PRIORITY,
                                               LW_NULL);

    API_GpioRequestOne(gpioTest.uiGpioLed, LW_GPIOF_OUT_INIT_LOW, "LED");

    while (1) {
        API_SemaphoreBPend(gpioTest.hSemBIrq, LW_OPTION_WAIT_INFINITE);

        printf("The key effective, uiIrqCount = %d\n", gpioTest.uiIrqCount);
        API_GpioSetValue(gpioTest.uiGpioLed, gpioTest.uiIrqCount & 0x01);
    }

    API_GpioIrqFree(&gpioIrq);
    API_GpioFree(gpioTest.uiGpioLed);

    return  (ERROR_NONE);
}
/*********************************************************************************************************
  END
*********************************************************************************************************/

猜你喜欢

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