在驱动层使用GPIO的中断功能

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

使用情景

上一篇讲了在驱动层如何使用GPIO的API函数进行简单的GPIO输入和输出功能,这一篇讲如何在驱动层使用GPIO的中断功能。有些复杂驱动是要借助GPIO的中断功能来实现自身对系统的中断通知的。如下图所示的 FXOS8700CQ 三轴磁力计芯片的单元电路中,除了要使用一路I2C接口与CPU通信外,还有 INT1,INT2两个中断脚用于向CPU发送中断信号,主动告知CPU检测到状态有变化。这两个中断引脚就是连接到两个GPIO的,GPIO要设置为下降沿触发模式。
在这里插入图片描述

接口说明

/*********************************************************************************************************
** 函数名称: API_GpioGetIrq
** 功能描述: 根据指定 GPIO 号返回对应的 IRQ 号
** 输 入  : uiGpio        GPIO 号
**           bIsLevel      是否为电平触发
**           uiType        如果为电平触发, 1 表示高电平触发, 0 表示低电平触发
**                         如果为边沿触发, 1 表示上升沿触发, 0 表示下降沿触发, 2 表示双边沿触发
** 输 出  : IRQ 号, 错误返回 LW_VECTOR_INVALID
*********************************************************************************************************/
LW_API ULONG            API_GpioGetIrq(UINT uiGpio, BOOL bIsLevel, UINT uiType);
/*********************************************************************************************************
** 函数名称: API_GpioSetupIrq
** 功能描述: 根据指定 GPIO 号设置相应的外部中断, 并返回对应的 IRQ 号
** 输 入  : uiGpio        GPIO 号
**           bIsLevel      是否为电平触发
**           uiType        如果为电平触发, 1 表示高电平触发, 0 表示低电平触发
**                         如果为边沿触发, 1 表示上升沿触发, 0 表示下降沿触发, 2 表示双边沿触发
** 输 出  : IRQ 号, 错误返回 LW_VECTOR_INVALID
*********************************************************************************************************/
LW_API ULONG            API_GpioSetupIrq(UINT uiGpio, BOOL bIsLevel, UINT uiType);
/*********************************************************************************************************
** 函数名称: API_GpioClearIrq
** 功能描述: GPIO 为外部中断输入模式时, 在中断上下文中清除中断请求操作
** 输 入  : uiGpio        GPIO 号
** 输 出  : NONE
*********************************************************************************************************/
LW_API VOID             API_GpioClearIrq(UINT uiGpio);
/*********************************************************************************************************
** 函数名称: API_GpioSvrIrq
** 功能描述: GPIO 为外部中断输入模式时, 判断当前是否为指定的 GPIO 中断
** 输 入  : uiGpio        GPIO 号
** 输 出  : LW_IRQ_HANDLED 表示当前中断是指定 GPIO 产生的中断
**           LW_IRQ_NONE    表示当前中断不是指定 GPIO 产生的中断
*********************************************************************************************************/
LW_API irqreturn_t      API_GpioSvrIrq(UINT uiGpio);

示例程序

/*********************************************************************************************************
**
**                                    中国软件开源组织
**
**                                   嵌入式实时操作系统
**
**                                SylixOS(TM)  LW : long wing
**
**                               Copyright All Rights Reserved
**
**--------------文件信息--------------------------------------------------------------------------------
**
** 文   件   名: gpioDrvExample.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"
/*********************************************************************************************************
   引脚宏定义
 ********************************************************************************************************/
#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                uiGpioKey;
    UINT                uiGpioLed;
    UINT                uiIrqCount;
    ULONG               ulVector;
    LW_OBJECT_HANDLE    hSemBIrq;                                       /*  信号量句柄                  */
} GPIO_TEST;
/*********************************************************************************************************
** 函数名称: gpioDrvExample2Isr
** 功能描述: GPIO 中断服务函数
** 输    入: pvArg      输入参数
**           ulVector   中断向量
** 输    出: 中断返回值
*********************************************************************************************************/
static irqreturn_t  gpioDrvExample2Isr (PVOID pvArg, ULONG  ulVector)
{
    irqreturn_t  irqret;
    GPIO_TEST   *pGpioTest;

    pGpioTest = (GPIO_TEST   *)pvArg;
    irqret    = API_GpioSvrIrq(pGpioTest->uiGpioKey);                   /*  判断是否为指定的 GPIO 中断  */

    if (LW_IRQ_HANDLED == irqret) {
        pGpioTest->uiIrqCount++;
        API_GpioClearIrq(pGpioTest->uiGpioKey);                         /*  清除中断标志,防止重复触发  */
        API_SemaphoreBPost(pGpioTest->hSemBIrq);
    }

    return  (irqret);
}
/*********************************************************************************************************
** 函数名称: gpioDrvExample2
** 功能描述: gpio 中断例程
** 输    入: NONE
** 输    出: ERROR_CODE
*********************************************************************************************************/
INT  gpioDrvExample2 (VOID)
{
    GPIO_TEST    gpioTest;

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

    gpioTest.uiGpioKey  = KEY08;
    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.uiGpioKey, LW_GPIOF_IN, "KEY");
    API_GpioRequestOne(gpioTest.uiGpioLed, LW_GPIOF_OUT_INIT_LOW, "LED");
    API_GpioSetupIrq(gpioTest.uiGpioKey, 0, 0);                         /*  设置 KEY08 为下降沿触发     */

    gpioTest.ulVector = API_GpioGetIrq(gpioTest.uiGpioKey, 0, 0);       /*  获取中断号                  */
    API_InterVectorConnect(gpioTest.ulVector,                           /*  注册中断服务函数            */
                           (PINT_SVR_ROUTINE)gpioDrvExample2Isr,
                           &gpioTest,
                           "KEY_isr");
    API_InterVectorEnable(gpioTest.ulVector);                           /*  使能中断                    */

    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_GpioFree(gpioTest.uiGpioKey);
    API_GpioFree(gpioTest.uiGpioLed);

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

说明:

  • 使用GPIO中断功能,要将其先初始化为输入模式,切记不可设置为输出模式。
  • 并不是所有的GPIO都会有中断模式,所以在获取GPIO中断号时,要检查其有效性。
  • 需要借助中断控制API初始化中断及注册中断回调函数。
  • 中断回调函数中要检查中断有效性并清除中断标志,防止重复触发中断响应。
  • 实现效果和 《在应用层使用GPIO》中的 gpioExample2 例程的一样。

猜你喜欢

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