RK3568外部IO中断示例

外部IO中断介绍

本篇文章以万象奥科HD-RK3568-IOT评估板中GPIO30为例,介绍Linux内核中断的注册方法,使用中断的方式检测GPIO30是否出现上升沿信号。中断在linux、设备驱动开发里使用的都非常多,可以更加实时的检测GPIO30的状态。

Linux 内核提供了中断的注册接口:

  1. 注册中断

头文件 include\linux\interrupt.h

定义文件 include\linux\interrupt.h

函数原型 int request_irq(unsigned int irq, /* 做实参传递给中断服务函数第1个参数 */

Irq_handler_t handler, /* 中断服务函数指针 */

unsigned long flags,

const char *name,

void *dev_id); /* 做实参传递给中断服务函数第2个参数 */

函数功能: 向内核注册一个中断服务函数;

当发生中断号为irq的中断时,会执行handler指针函数。

函数参数:

irq: 中断编号(每个中断有唯一的编号)。

handler: 中断服务函数指针。

原型 typedef irqreturn_t(*irq_handler_t)(int, void *)。

flag: 中断的标志,用来描述本中断的基本特征的。

有固定的值,由中断源的特征决定;

比如外中断有: 上升沿,下降沿触发中断这类标志。

name: 中断名字,注册后会出现cat /proc/interrupts

dev_id: 这个参数是传递给中断服务函数。

对共享中断来说,这个参数一定有要;

当注销共享中断中的其中一个时,用这个标识要注销哪一个。

对于有唯一入口的中断,可以传递NULL;

但是一般来说都会传递一个有意义指针,在中断程序中使用,以方便编程。

返回值 0 标识成功

-EINVAL (无效参数22) 表示中断号无效。

-EBUSY (设备或者资源忙16) 表示中断已经被占用。

2) 注销中断

void free_irq(unsigned int irq, void *dev_id)

irq: 要注销的中断号

dev_id: 其实就是注册时需要使用的dev参数,在共享中断必不可少,不能传递NULL。

注意:为防止在注销时同时发生中断,调用时候,先禁掉中断。

3 中断开启与关闭

禁止中断:

void disable_irq_nosync(unsigned int irq);

void disable_irq(unsigned int irq);

参数: irq,要禁止的中断对应的编号。

注意:在中断服务程序中不能使用disable_irq这个函数,否则内核崩溃,可以使用disable_irq_nosync,

disable_irq: 函数调用后,函数不会马上返回,而等待中断程序执行完成才返回,在中断调用会导致死锁。

使能中断:

void enable_irq(unsigned int irq);

参数: irq, 要使能的中断对应的编号。

4) 获取irq 中断号

Int gpio_to_irq(unsigned int irq);

参数: irq,要使能的中断对应的编号

外部IO中断驱动编写

  1. IO原理图

图 2.1 GPIO0_D6

GPIO0_D6=0*32+(4-1)-8+6=30

    1. 驱动示例代码

#include <linux/init.h>

#include <linux/module.h>

#include <linux/gpio.h>

#include <linux/interrupt.h>

#include <linux/timer.h>

#define GPIO_PIN 30 // 替换为你的GPIO引脚

static unsigned int irq_number;

// GPIO中断处理函数

static irqreturn_t gpio_irq_handler(int irq, void *dev_id) {

printk("GPIO中断触发!\n");

return IRQ_HANDLED;

}

static int __init mymodule_init(void) {

int ret;

// 请求GPIO

ret = gpio_request(GPIO_PIN, "my_gpio");

if (ret) {

printk("无法请求GPIO %d\n", GPIO_PIN);

return ret;

}

// 配置GPIO引脚为输入

ret = gpio_direction_input(GPIO_PIN);

if (ret) {

printk("无法配置GPIO %d 为输入\n", GPIO_PIN);

gpio_free(GPIO_PIN);

return ret;

}

// 请求GPIO中断

irq_number = gpio_to_irq(GPIO_PIN);

ret = request_irq(irq_number, gpio_irq_handler, IRQF_TRIGGER_RISING, "my_gpio_irq", NULL);

/* IRQF_TRIGGER_RISING 上升沿有效 */

if (ret) {

printk("无法请求GPIO中断 %d\n", irq_number);

gpio_free(GPIO_PIN);

return ret;

}

printk("模块加载成功\n");

return 0;

}

static void __exit mymodule_exit(void) {

// 释放GPIO中断

free_irq(irq_number, NULL);

// 释放GPIO

gpio_free(GPIO_PIN);

printk("模块卸载成功\n");

}

module_init(mymodule_init);

module_exit(mymodule_exit);

MODULE_LICENSE("GPL");

MODULE_AUTHOR("zou");

MODULE_DESCRIPTION("Sample GPIO and Timer Interrupt Kernel Module");

外部IO中断验证

将驱动编译成模块,insmod加载模块后。 由于驱动检测GPIO0_D6上升沿有效,当给该引脚提供高电平时,会触发中断执行中断处理函数。

图3.1 触发IO中断

相关推荐
森焱森1 小时前
嵌入式硬件工程师应知 白银快速分析报告
linux·c语言·arm开发·嵌入式硬件·去中心化
森G14 小时前
七、04ledc-sdk--------makefile有变化
linux·c语言·arm开发·c++·ubuntu
VekiSon17 小时前
Linux内核驱动——杂项设备驱动与内核模块编译
linux·c语言·arm开发·嵌入式硬件
AI+程序员在路上18 小时前
Nand Flash与EMMC区别及ARM开发板中的应用对比
arm开发
17(无规则自律)1 天前
深入浅出 Linux 内核模块,写一个内核版的 Hello World
linux·arm开发·嵌入式硬件
梁洪飞2 天前
内核的schedule和SMP多核处理器启动协议
linux·arm开发·嵌入式硬件·arm
代码游侠2 天前
学习笔记——Linux字符设备驱动
linux·运维·arm开发·嵌入式硬件·学习·架构
syseptember2 天前
Linux网络基础
linux·网络·arm开发
代码游侠3 天前
学习笔记——Linux字符设备驱动开发
linux·arm开发·驱动开发·单片机·嵌入式硬件·学习·算法
程序猿阿伟3 天前
《Apple Silicon与Windows on ARM:引擎原生构建与模拟层底层运作深度解析》
arm开发·windows