Linux驱动学习之中断与等待队列

本篇分为设备树部分和API接口部分

设备树

想要使用中断,设备树中需要有两个属性:

interrupts                   // 表示要使用哪一个中断, 中断的触发类型等等。

interrupt-parent         // 这个中断要接到哪一个设备去? 即父中断控制器是谁

父中断控制器有两种指定方法:

  • 只有一个父中断设备
  • 有多个父中断设备

1)、只有一个父中断设备

interrupt-parent = <&父设备标号>;

 interrupts = <... ...>, <... ...>;

2)、有多个父设备节点

interrupts-extended = <&父设备标号 .....>, <... ... ...>;

通过不断往里跳可以发现 设备树查找有这两种方式

方法一

此方法中,由于查看父节点是靠 interrupt-parent实现的,所以此属性不可少. 

方法二 

不断跳就会发现这个循环

此方法中是通过属性中第一个元素找出的父节点,所以无需指定中断父节点 

上述属性用多少个u32表示

由它的父中断控制器来描述,在父中断控制器中, 至少有2个属性:

interrupt-controller; // 表示自己是一个中断控制器

#interrupt-cells // 表示自己的子设备里应该用几个U32的数据来描述中断

如此图,此节点是父节点中断控制器,他的子节点用2个u32 描述中断。

如何找到一个节点的父中断控制器

一般在描述子中断节点中都会有一个属性interrupt-parent,由此属性描述。

如果子中断节点中没有此属性,需要查看此节点的父节点,一级一级往上直到父节点中出现interrupt-parent。

API函数

获取中断号

int platform_get_irq(struct platform_device *dev, unsigned int num)

参数一:平台设备,

参数二:设备树里第几个中断引脚,一般给0

返回值:中断号

ps:需要在设备树里指定。

int gpio_to_irq(unsigned gpio)

参数:io口号

返回值:中断号

ps:此函数无需在设备树里指定中断信息,直接调用可直接在根目录下的gpio中断控制器里申请返回一个中断号,一旦在设备树里指定,也可获得中断号,不过与不指定的中断号可能存在差异,不过不影响,都可以实现中断。

注册中断 

int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,const char *name, void *dev)

参数一:中断号

参数二:中断回调函数

参数三:在什么边沿触发

参数四:标签,可随意

参数五:中断回调函数传入的参数

int 
devm_request_irq(struct device *dev, unsigned int irq, irq_handler_t handler,unsigned long irqflags, const char *devname, void *dev_id)

此函数也可以注册中断,建议使用这个,参数跟上面函数大差不差不在重复介绍。

devm_request_irq和request_irq区别在于前者是申请的内核“managed”资源,不需要自己手动释放,会自动回收资源,而后者需要手动调用free_irq来释放中断资源 

中断回调函数类型

flag类型

注销函数

const void *free_irq(unsigned int irq, void *dev_id)

参数一:中断号

参数二:与注册函数传入参数一致。

void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id)

 参数与上述函数一致,注意配套使用

使用中断后,我们就可以在按下按键后就可以收到一次消息,但是由于上层函数在while循环里一直执行,每调用一次read就会调用底层内核的read,不会阻塞,所以cpu占用率百分之百,此时这就是个病毒驱动。但是我们在学习系统编程的时候,read是一个阻塞函数,当然那时内核实现的他的阻塞,所以我们就需要在内核里把read阻塞,当按键按下进入中断再让read解除阻塞,减少cpu的占用率。

等待队列

等待队列是目前内核最常用的阻塞同步机制之一
        可以在内核层产生一个阻塞( 等于放弃 CPU 的! )
        while(1); ->这种叫死等 -> 效率最低 占用 CPU 最高一种等待机制
        所有的系统的等待机制都绝非死等-> 都是放弃 CPU ,后续被换唤醒机制!
        在 FreeRTOS 大家应该接触过类似的概念
等待队列非常类似之前大家在系统层面学习 线程的同步和互斥:条件变量!
        等待队列除了创建之外就两个函数,也是两个功能:
                一个功能叫做: 阻塞 -> 调用后立刻产生挂起
                wait_event
                唤醒->调用会唤醒之前挂起进程 / 程序
                wake_up
  内核层的阻塞会引起上层的阻塞!
        举个例子:我在 open-> 调用 阻塞 ” -> 上层 open 也会阻塞
                我在 read->调用 阻塞 ” –> 上层 read 也会阻塞

 等待队列的创建:(宏定义函数->用空间换时间)

DECLARE_WAIT_QUEUE_HEAD(name);
#define DECLARE_WAIT_QUEUE_HEAD(name)                                          \struct wait_queue_head name = __WAIT_QUEUE_HEAD_INITIALIZER(name)// Expands to
struct wait_queue_head queue = { . lock = ( spinlock_t ) { { . rlock = { . raw_lock = { { . val = { ( 0 ) } } } , } } } , . head = { & ( queue ) . head , & ( queue ) . head } }

此函数为宏函数, 声明的时候已经帮我们初始化好了,括号里面是我们创建的变量名字

阻塞函数 

 wait_event_interruptible(wq_head, condition)

此函数也也为宏函数,可以看出,当condition为1时,不阻塞,为0时阻塞,另外第二个参数必须为变量,如果填0,则当唤醒函数执行后不会解除阻塞。wait_event_interruptible(以及wait_event打头的其他变体)是Linux的wait queue机制提供的线程同步接口(应先cond=0,把cond传进去)另外也可以看出,参数一直接传入变量名即可

唤醒函数

wake_up_interruptible(x)

此函数也为宏函数, 跳进去可发现,参数传入变量名地址。调用完该函数cond设置为1.

整体代码

#include "linux/cdev.h"
#include "linux/device.h"
#include "linux/device/class.h"
#include "linux/export.h"
#include "linux/fs.h"
#include "linux/gpio.h"
#include "linux/interrupt.h"
#include "linux/irq.h"
#include "linux/module.h"
#include "linux/of_device.h"
#include "linux/of_gpio.h"
#include "linux/platform_device.h"
#include "linux/printk.h"
#include "linux/types.h"
#include "linux/uaccess.h"
#include "linux/wait.h"
#include "linux/zconf.h"
uint32_t pin;
dev_t dev_num;
struct cdev *cdev;
struct class *cls;
struct device * dev;
uint8_t cond;
DECLARE_WAIT_QUEUE_HEAD(queue);
uint8_t val;
irqreturn_t fun(int i, void * a)
{val=gpio_get_value(pin);printk("%d\r\n",val);wake_up_interruptible(&queue);cond=1;return 0;
}
static ssize_t read(struct file *f, char __user *b, size_t s, loff_t *offt)
{cond=0;wait_event_interruptible(queue,cond);int a=copy_to_user(b,&val,1);if(a){}return 0;
}
static int open(struct inode *i, struct file *f)
{int ret=devm_request_irq(dev, gpio_to_irq(pin),fun,IRQ_TYPE_EDGE_FALLING,"key", NULL);printk("%d\r\n",ret);return ret;
}
static int close(struct inode *i, struct file *f)
{devm_free_irq(dev,gpio_to_irq(pin),NULL);return 0;
}
struct file_operations fops={.owner=THIS_MODULE,.read=read,.open=open,.release=close,
};int probe(struct platform_device *d)
{// DECLARE_WAIT_QUEUE_HEAD(name);// wait_event_interruptible(,);// wake_up_interruptible(x)platform_get_irq();//free_irq();// devm_free_irq();dev=&d->dev;pin=of_get_named_gpio(d->dev.of_node,"key_pin",0);printk("%d\r\n",pin);printk("%d\r\n", platform_get_irq(d,0));printk("irq_num=%d", gpio_to_irq(pin));gpio_request(pin,"key");gpio_direction_input(pin);// devm_request_irq(&d->dev, gpio_to_irq(pin),fun,IRQ_TYPE_EDGE_FALLING,"key", NULL);alloc_chrdev_region(&dev_num, 0, 1,"key");cdev=cdev_alloc();cdev->ops=&fops;cdev_add(cdev,dev_num,1);cls=class_create(THIS_MODULE, "key");device_create(cls, NULL,dev_num,NULL,"key");return 0;
}
int remove(struct platform_device *d)
{return 0;
}
static struct of_device_id match={.compatible="key",
};static struct platform_driver driver={.probe=probe,.remove=remove,.driver={.name="key",.of_match_table=&match,},
};
static int __init start(void)
{platform_driver_register(&driver);printk(KERN_INFO "Hello, world!\n");return 0;
}
static void __exit stop(void)
{platform_driver_unregister(&driver);printk(KERN_INFO "Goodbye, world!\n");
}
module_init(start);
module_exit(stop);
MODULE_LICENSE("GPL");

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/410485.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

趣味算法------拯救阿拉德大陆

目录 ​编辑 题目描述&#xff1a; 思路解析&#xff1a; 具体代码&#xff1a; 总结&#xff1a; 题目描述&#xff1a; 此时一批勇士也随之而来&#xff0c;但其能力也是参差不齐&#xff0c;我们需要挑选出最优秀的勇士来守护这片大陆。每位勇士都有属于自己的编号&am…

JobSchedulerService.setRequiresCharging需充电且电量大于90%才触发的现象

一、摘要 从源码看原生JobSchedulerService.setRequiresCharging 的特性&#xff0c;该特性竞品机器华为、Oppo也是如此。 1、应用处于前台可见&#xff0c;满足充电条件&#xff0c;立刻触发 2、应用处于后台不可见&#xff0c;需要设备连接USB或AC且电量大于90%&#xff0…

挂个人-CSDN Java优秀内容博主rundreamsFly抄袭

事件起因 今天点开自己的CSDN博客&#xff0c;发现给我推了一篇文章抄袭我自己昨天18点发的文章。 就是这篇&#xff0c;一字不差&#xff0c;博主昵称是&#xff1a;rundreamsFly&#xff0c;账号是rundreams。 抄袭者文章 发布于2024-8-26 19:37:41秒&#xff0c;比我发布…

C的温故而知新:位操作(C Primer Plus第十五章)

第十五章&#xff1a;位操作 这一章的篇幅不是很长&#xff0c;但既然能单独作为一章来讲的话&#xff0c;应该蛮重要的&#xff0c;但是我貌似没有总结出多少需要注意、加强记忆的东西&#xff0c;可见在JAVA的日常开发过程中基本不太遇见有关位操作的内容&#xff0c;所以我…

FSQ26信号分析仪RS FSU26 20HZ-26.5G频谱分析仪

罗德与施瓦茨Rohde & Schwarz FSQ26信号分析仪&#xff0c;20 Hz - 26.5 GHz ​R&S FSQ26 信号分析仪集两种仪器于一身。它提供高达 120 MHz 解调带宽的信号分析&#xff0c;并具有高端频谱分析仪的动态范围。 频率范围&#xff1a;20 Hz 至 26.5 GHz 高端频谱分析仪…

神经网络—卷积层

1.讲解 Conv2d out_channels 参数为2时&#xff0c;会生成两个卷积核&#xff0c;分别与输入进行卷积。得到的两个输出为输出 新生成的卷积核和原来的卷积核不一定相同 in_channels (int) – Number of channels in the input image out_channels (int) – Number of channels…

ARM32开发——(六)GPIO_USART通信原理

1. 串行通信和并行通信 1.1 串行通信 串行通信是一种数据传输的方式&#xff0c;它是指将数据按照一位一位的顺序依次发送和接收&#xff0c;常用于远距离通信、嵌入式系统和低带宽传输场景下。串行通信相对于并行通信而言&#xff0c;只需要传输一条数据线&#xff0c;相对简…

一文了解机器学习顶会ICML 2024的研究热点

对人工智能研究领域前沿方向的跟踪是提高科研能力和制定科研战略的关键。本文通过图文并茂的方式介绍了ICML 2024的研究热点&#xff0c;帮助读者了解和跟踪机器学习和人工智能的前沿研究方向。本推文的作者是许东舟&#xff0c;审校为邱雪和黄星宇。 1 会议介绍 ICML&#x…

运放阻抗和噪声(同相放大器的输入/输出阻抗 + 电压跟随器阻抗 + 噪声 +信噪比)

2024-8-27&#xff0c;星期一&#xff0c;21:03&#xff0c;天气&#xff1a;阴雨&#xff0c;心情&#xff1a;晴。培训终于结束啦&#xff0c;开始轮岗了&#xff0c;看了两天PPT&#xff0c;加油加油&#xff0c;继续学习。 今天继续学习第六章运算放大器&#xff0c;主要学…

一文带你从零到实战,学会gcc和Makefile,多文件编译神器的使用与编写

目录&#xff1a; 目录&#xff1a; 一、什么是Makefile 1.1 makefile的作用&#xff1a; 1.2 makefile的基本组成&#xff1a; 二、Linux编译过程&#xff1a; 2.1 linux编译过程: 2.1.1 预处理&#xff08;Preprocessing&#xff09; 2.1.2 编译&#xff08;Compilation&am…

Android Studio 自定义字体大小

常用编程软件自定义字体大全首页 文章目录 前言具体操作1. 打开设置对话框2. 选择外观字体 前言 Android Studio 自定义字体大小&#xff0c;统一设置为 JetBrains Mono &#xff0c;大小为 14 具体操作 【File】>【Settings...】>【Appearance & Behavior】>【…

二、设置地图配置表

一、导入一个背景图 由于背景图比较大&#xff0c;需要缩小至0.73 二、写配置文件&#xff08;SO&#xff09; 使用List需要一个命名空间 写一个类&#xff0c;声明房间的出现数量和种类&#xff1b;将它实例化出来 三、枚举变量的多选 在枚举变量中标记命名空间&#xff…

docker 多线成服务,比如gunicorn服务启动报错解决办法

docker执行的时候报错&#xff0c;排查是线程创建权限不足导致的&#xff0c;报错如下。 解决办法 docker run -e OPENBLAS_NUM_THREADS1 your_image

Unity XR Interaction Toolkit 踩坑记录

1&#xff1a;按下 grap/select 键 物品直接飞到手上 2 按下 grap/select 键 物品一点点的想自己移动

OpenCV杂项图像变换(2)线性混合函数blendLinear()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 执行两个图像的线性混合&#xff1a; dst ( i , j ) weights1 ( i , j ) ∗ src1 ( i , j ) weights2 ( i , j ) ∗ src2 ( i , j ) \texttt{…

关于多线程你了解多少?

或许是执念太重&#xff0c;又或许是性格缺陷&#xff0c;我对java中一些知识的坚持&#xff0c;已经到了让人无法接受的地步。有些人甚至因此在背后骂我神经病、傻瓜。但我依旧我行我素&#xff0c;即使中间懈怠了很长时间&#xff0c;重新开始时我依旧会以这些知识为起点。不…

Ubuntu上搭建Nginx环境

1. 软件包下载 nginx下载地址 下载linux版本的nginx&#xff0c;如图圈示 2. 将下载好的软件包上传至Linux服务器 假设上传到 /opt/nginx 目录,进入目录 cd /opt/nginx解压&#xff0c;根据版本自行修改版本号 tar zxvf nginx-1.16.0.tar.gz3.安装 安装编译所需的依赖&a…

前端算法 === 力扣 111 二叉树的最小深度

目录 问题描述 DFS&#xff08;深度优先搜索&#xff09;方案 BFS&#xff08;广度优先搜索&#xff09;方案 总结 力扣&#xff08;LeetCode&#xff09;上的题目111是关于二叉树的最小深度问题。这个问题可以通过深度优先搜索&#xff08;DFS&#xff09;和广度优先搜索&…

QJson的写入和解析基本操作

一、QJson简介 QJson 是一个用于处理 JSON&#xff08;JavaScript Object Notation&#xff09;数据的 C 库 JSON&#xff08;JavaScript Object Notation&#xff09;是一种轻量级的数据交换格式 JSON 的语法简洁明了&#xff0c;使用人类可读的文本格式来表示数据 它由键值…

分块矩阵的转置

证明 则 证明&#xff1a;令&#xff0c;有&#xff0c;对它做一个分块使得和后面的分块矩阵中的是同型矩阵&#xff0c;要证明&#xff08;任意的&#xff09;&#xff0c;需要证明1&#xff09;是一个的矩阵 2&#xff09;任意的 首先证明1&#xff09;我们先定义两个函…