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中断

相关推荐
T1mzhou12 小时前
ARM64 Linux 6.10 内核驱动(12):dd.c:probe/ remove、延迟 probe
linux·服务器·c语言·arm开发·arm
Doraemomo13 小时前
IMX6ULL裸机开发——系统主频和时钟配置
arm开发·嵌入式硬件·makefile·imx6ull
T1mzhou16 小时前
ARM64 平台安全学习记录
linux·服务器·arm开发·arm
云栖梦泽18 小时前
网络设备驱动(1)
linux·arm开发·嵌入式硬件
零依赖极客2 天前
Day 9·1 KV 也量化——q8 KV 把缓存与 decode 带宽压到一半
c语言·开发语言·arm开发·人工智能·缓存·矩阵
secondyoung2 天前
I2C通信协议详解
arm开发·驱动开发·stm32·单片机·嵌入式硬件·mcu·51单片机
奔跑的架构师2 天前
[A-50]ARMv9/v8-DVFS系统架构
linux·arm开发·架构·系统架构·arm
零依赖极客3 天前
Day 8·1 自注意力机制:Q·K^T/softmax/V的在线计算
c语言·arm开发·人工智能·llama
T1mzhou3 天前
ARM64 Linux 6.10 内核驱动(14):drivers/base/platform.c:板级设备主战场
linux·c语言·开发语言·arm开发
零依赖极客4 天前
《30 天手搓 ARM 架构零依赖纯 C 推理引擎》课程介绍与大纲
c语言·开发语言·arm开发·人工智能·嵌入式硬件·ai编程