接口说明
为了简化驱动层使用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
*********************************************************************************************************/
代码效果和《在驱动层使用GPIO的中断功能》一样,但封装了对系统中断API的调用,更专注于对GPIO的操作。