【Linux驱动】设备树中指定中断 | 驱动中获得中断 | 按键中断实验

news2025/6/21 23:20:32

🐱作者:一只大喵咪1201
🐱专栏:《Linux驱动》
🔥格言:你只管努力,剩下的交给时间!
图

目录

  • 🏀在设备树中指定中断
  • 🏀代码中获得中断
  • 🏀按键中断
    • ⚽驱动程序
    • ⚽设备树
    • ⚽上机实验
  • 🏀总结

🏀在设备树中指定中断

图
继续拿这个中断流程图来说话。

在硬件上,中断控制器只有GIC这一个,但是我们在软件上可以把GPIO也归类为中断控制器。

芯片会有多个GPIO模块,所以软件上的中断控制器就会有很多个:GIC,GPIO1,GPIO2,GPIO3…等等。

其中GPIO1、GPIO2、GPIO3这些中断控制器模块都连接汇集到GIC模块,所以GIC模块就是GPIOx模块的父亲。

假设GPIO1有32个中断源,但是它把其中的16个汇聚起来向GIC发出一 个中断,把另外16个汇聚起来向GIC发出另一个中断。这就意味着GPIO1会用到 GIC 的两个中断,会涉及 GIC 里的 2 个 hwirq

  • 这些层级关系、中断号(hwirq),都会在设备树中有所体现。

dtsi:

图
如上图所示由BSP工程师提供的dtsi设备树文件:

  • intc:表示GIC中断控制器。
  • gpio1:表示GPIO1中断控制器。
  • gpio2:表示GPIO2中断控制器。

GIC是顶层中断控制器,所以它没有父亲,而GPIO1和GPIO2都是soc的子节点,子节点会继承父节点的属性

  • interrupt-parent = <&gpc>:表示父亲节点,soc节点的interrupt-parent = <&gpc>
  • GPIO1和GPIO2继承socinterrupt-parent = <&gpc>属性,所以它们的父节点也是gpc

本喵没有列出来,gpc的父节点是GIC中断控制器,所以从设备树反推出IMX6ULL的中断框图,它比之前多了一个GPC INTC

图
如上图所示新的中断框图,GPC INTC的功能是提供中断屏蔽、中断状态查询等功能。

  • 实际上这些功能在GIC中也实现了。
  • 之所以保留它是因为它还能提供唤醒功能。

继续回到dtsi设备树文件来看,每一个中断控制器中都有两个必须的属性:

  • interrupt-controller:该属性表明它是中断控制器。
  • #interrupt-cells:该属性表明引用这个中断控制器的话需要多少个cell
    • #interrupt-cells=<1>:别的节点要使用这个中断控制器时,只需要一个 cell来表明使用哪一个中断。
    • #interrupt-cells=<2>:别的节点要使用这个中断控制器时,需要两个cell,其中第一个来表明使用哪一个中断,第二个一般来描述中断的触发类型。

由于GIC规定了要引用该中断控制器需要使用3个cell,所以GPIO1和GPIO2就使用了<GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>这样的3个cell

  • GIC_SPI:GPIO模块向GIC发出中断的类型。
  • 66:GPIO模块向GIC发出中断的硬件中断号hirq
  • IRQ_TYPE_LEVEL_HIGH:GPIO模块向GIC发出中断的触发类型。

除了引用GIC中断控制器外,GPIOx模块也有自己的interrupt-controller属性和#interrupt-cells = <2>属性:

  • GPIO1和GPIO2中断控制器模块规定引用该控制器时需要使用两个cell

这是都是芯片厂家写好的,提供给我们使用的,我们只需要知道怎么去用它们就行。

dts:

图
如上图我们写的dts设备树文件中,这是一个spidev节点:

  • interrupt-parent = <&gpio1>:该设备的父节点是gpio1,表明该外部设备引用GPIO1控制器。
  • interrupts = <1 1>:表示该设备使用的硬件中断号hirq是1,触发类型是1。
    • 新写法interrupts-extend:一个这样的属性就可以既指定interrupt-parent又指定interrupts
    • 比如interrupts-extend = <&gpio1 1 1>

触发类型这里写的1,代表什么意思呢?有写什么类型呢?

tu
如上图所示,1就代表着low-to-high edge triggered上升沿触发。

如此一来,在设备树中指定了该外部设备的中断,在驱动程序中就可以直接使用了。

🏀代码中获得中断

我们知道,设备树中的节点有的会被内核转化为platform_device结构体,有些则不会。

对于能转化为platform_device结构体的节点,如果它在设备树里指定了中断属性,那么可以从platform_device中获得中断资源:

图
如上图所示platform_get_resource函数,用来获取中断资源:

  • dev:转化后的platform_device结构体指针。
  • type:获取哪类资源。
    • IORESOURCE_MEMIORESOURCE_REGIORESOURCE_IRQ 等。
  • num:这类资源中的哪一个。
    • 一个节点中使用不止一个中断源。

对于I2C设备、SPI设备,总线驱动在处理设备树里的I2C子节点时,也会处理其中的中断信息。

  • 一个I2C设备会被转换为一个i2c_client结构体,中断号会保存在i2c_clientirq成员里。

图
如上图代码所示,当I2C总线和驱动程序匹配以后,会自动调用probe函数,在该函数中使用of_irq_get函数,从它的子节点I2C设备中解析出中断号irq

  • 一个 SPI 设备会被转换为一个spi_device结构体,中断号会保存在spi_deviceirq成员里。

图
如上图,当SPI总线和驱动程序匹配后,在它的probe函数中,也会调用of_irq_get从子节点SPI设备中解析出中断号irq

如果设备节点既不能转换为platform_device,也不是I2C和SPI设备,那么在驱动程序中,可以自行调用of_irq_get函数去解析得到中断号。


对于GPIO引脚,芯片厂家提供了专门的接口函数来获取中断:

  • of_get_gpio_flags:使用该函数获取GPIO引脚,此时获取到的是使用老的方式描述GPIO引脚信息的那个整数。
  • gpio_to_desc:使用该函数获取GPIO引脚,获得是使用新方式描述GPIO引脚信息的那个desc结构体。
  • gpiod_to_irq:最后使用该函数从得到的GPIO引脚信息中获得软件中断号。

🏀按键中断

对于 GPIO 按键,我们并不需要去写驱动程序,使用内核自带的驱动程序 drivers/input/keyboard/gpio_keys.c就可以,然后需要做的只是修改设备树指定引脚及键值。

但是本喵还是要从头写一遍按键驱动程序,特别是如何使用中断,因为中断是其他基础知识的前提,以后的休眠-唤醒,POLL机制,异步通知,定时器,中断的线程化处理等内容都离不开中断。

图
如上图所示本喵使用的IMX6ULL开发板原理图,按键KEY1和按键KEY2使用的是GPIO5_1GPIO4_14两个引脚,并且是低电平有效。

同样的,按键驱动程序也要分为驱动程序和设备树两部分。

⚽驱动程序

图
如上图所示gpio_key_drv.c文件中的驱动程序:

  • 创建platform_driver结构体gpio_keys_driver,并且进行初始化。
    • 使用gpio_key_probe初始化probe函数。
    • 使用gpio_key_remove初始化remove函数。
    • 使用of_device_id数组Big_Miaomi_keys初始化driver.of_match_table
      • 数组中compatible属性的值是"Big_Miaomi,gpio_keys",用来和设备节点匹配。
  • 在入口函数gpio_key_init中使用platform_driver_register函数向内核注册驱动程序。
  • 在出口函数gpio_key_exit中使用platform_driver_unregister从内核中取消驱动程序注册。
  • 完善设备驱动信息。
  • 由于这是按键中断,不需要应用层来调用,所以不用在/dev下创建设备节点,也不用注册file_operations结构体。

probe函数:

图
如上图所示probe函数的实现:

  • 定义全局一个结构体指针gpio_keys_Big_Miaomi,该结构体是struct gpio_key 类型,用来存放中断的信息。
  • 使用of_gpio_count获得中断源个数,因为一个设备节点可能有多个中断源。
    • 按键设备可能有多个按键,此时就有多个中断源。
  • 使用内核的kzalloc函数在堆区上开辟一段堆空间,来存放中断信息。
  • 每一个中断源,都需要获取它的详细信息:
    • 使用of_get_gpio_flags获取中断的引脚信息gpio和有效标志。
    • 将用整数描述的引脚信息转换成使用gpio_desc类型描述的引脚信息。
    • 将中断引脚设置成低电平有效,与OF_GPIO_ACTIVE_LOW相与。
      • 因为电路中按键是低电平有效,原本的引脚标志是输入GPIOF_IN
    • 再使用devm_gpio_request_one将引脚状态设置成逻辑值。
      • 按键按下后,读取到的引脚值是1,尽管物理值是0。
    • 使用gpio_to_irq获取中断引脚的软件中断号irq

将所有中断信息获取到以后,再为每一个中断注册中断函数:

  • 使用request_irq注册中断服务函数:
    • 第一个参数传入中断的软件中断号gpio_keys_Big_Miaomi[i].irq
    • 第二个参数传入中断服务函数gpio_key_isr
    • 第三个参数传入中断触发方式IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING双边沿触发。
    • 第四个参数传入中断名称"100ask_gpio_key",该参数不重要。
    • 第五个参数传入dev_id,也就是中断信息所在的结构体指针&gpio_keys_Big_Miaomi[i]

此时中断函数就注册完成了,接下来就是实现中断服务函数中要做什么:

图
如上图所示中断服务函数,在里面仅获取引脚电平的逻辑值,并且打印出描述引脚的那个整数编号和引脚状态。

remove函数:

tu
如上图所示remove函数,在卸载驱动程序时:

  • 使用free_irq将所有前面注册的中断释放掉。
  • 使用kfree将存放引脚信息的堆空间释放掉。

⚽设备树

图
如上图所示蓝色框中代码,使用图形化工具生成GPIO5_1GPIO4_14的两个pin-controller节点代码。

图
如上图所示,将生成的pin-controller节点代码复制到我们要写的dts设备树文件中:

  • GPIO5_1:节点名称为Big_Miaomi_key1,表示按键1。
  • GPIO4_14:节点名称为Big_Miaomi_key2,表示按键2。

图
如上图所示,在dts设备树文件的根节点下,增加按键外部设备节点gpio_keys_Big_Miaomi

  • 使用GPIO子系统指定按键引脚和有效电平。
  • 使用Pinctrl子系统将引脚复用为通用GPIO功能。
  • 在原本的gpio-keys节点中,使用status = "disabled"属性让该节点失能,防止影响我们自己创建的按键节点。
  • 这里并没有在设备树中指定按键的interrupts-extend
  • 因为对于GPIO,芯片厂家提供了驱动程序中的一些列接口,可以直接获取GPIO的中断信息,包括中断号以及中断控制器等。

⚽上机实验

图
如上图所示,使用上面的makefile文件编译驱动程序,生成gpio_key_drv.ko驱动模块。

图
如上图所示,将写好的gpio_key_drv.c驱动程序和设备树文件,以及Makefile上传到服务器上,分别进行编译,编程成功后将生成的gpio_key.kodtb文件都拷贝到网络文件系统中供开发板使用。

图
如上图所示,先让开发板使用新的dtb设备树文件,再使用insmod安装gpio_key_drv.ko驱动模块,可以看到安装成功后输出匹配porbe函数的调试信息。

图
如上图所示,按下开发板上的KEY1KEY2时:

  • 按键按下,按键值是1,松开按键值是0。
  • 按键值前面的整数就是描述按键引脚的编号。

🏀总结

要知道在设备树中是如何描述一个设备的中断的,包括父节点interrupt-parent属性,以及描述中断引脚的interrupts属性的用法。

还要知道在中断程序中是如何获取设备树中的中断信息的,以及如何使用这些中断信息。

最后要会实现按键中断程序。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

spring boot mybatis plus mapper如何自动注册到spring bean容器

##Import(AutoConfiguredMapperScannerRegistrar.class) ##注册MapperScannerConfigurer ##MapperScannerConfigurer.postProcessBeanDefinitionRegistry方法扫描注册mapper ##找到mapper候选者 ##过滤mapper 类 候选者 ##BeanDefinitionHolder注册到spring 容器

JVM基础(4)——JVM存活判定算法

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 学习必须往深处挖&…

ArcGIS Pro中怎么加载在线地图

当我们在制图的时候&#xff0c;有的时候需要加载在线地图&#xff0c;在ArcGIS Pro中加载在线地图的方式有很多&#xff0c;这里为大家介绍一下加载的方法&#xff0c;希望能对你有所帮助。 加载底图 在菜单栏上选择地图&#xff0c;点击底图&#xff0c;可以看到所有可加载…

记录下载安装rabbitmq(Linux) 并整合springboot--详细版(全)

下载rabbitmq&#xff08;Linux&#xff09;&#xff1a; erlang压缩包&#xff1a; https://share.weiyun.com/TGhfV8eZ rabbitMq-server压缩包&#xff1a; https://share.weiyun.com/ZXbUwWHD &#xff08;因为RabbitMQ采用 Erlang 实现的工业级的消息队列(MQ)服务器&#…

【Nuxt3】Nuxt3脚手架nuxi安装项目和项目目录介绍

简言 最近学了Nuxt3,并使用它创建了自己的小网站。记录下学习到的nuxt3内容。 Nuxt3官网 Nuxt 是一个免费的开源框架&#xff0c;可通过直观、可扩展的方式使用 Vue.js 创建类型安全、高性能、生产级的全栈 Web 应用程序和网站。 支持SSR、SPA、建立静态网站&#xff0c;也可以…

C++ 图形界面学习效果及代码

#include <stdio.h> #include<conio.h> #include <stdlib.h> #include<graphics.h> #define WIDTH 800 #define HEIGHT 480 #define SIZE 20 int main() {const char* str "人生就是由欲望不满足而痛苦和满足之后无趣这两者所构成";const …

【征服redis1】基础数据类型详解和应用案例

博客计划 &#xff0c;我们从redis开始&#xff0c;主要是因为这一块内容的重要性不亚于数据库&#xff0c;但是很多人往往对redis的问题感到陌生&#xff0c;所以我们先来研究一下。 本篇&#xff0c;我们先看一下redis的基础数据类型详解和应用案例。 1.redis概述 以mysql为…

性能测试之全链路压测正确优化思路

性能测试之全链路压测的优化需要从多个方面入手&#xff0c;包括明确压测目标、模拟真实场景、选择合适的工具和技术、合理设计压测方案、分析性能瓶颈以及持续监控和改进等。通过这些措施的实施&#xff0c;可以有效地提高系统的性能和稳定性&#xff0c;为用户提供更好的服务…

ffmpeg解码音频planar模式和packed模式

转载&#xff1a;原文地址&#xff1a; FFmpeg连载4-音频解码-阿里云开发者社区ffmpeg连载系列https://developer.aliyun.com/article/1197520 转载的&#xff0c;看到了&#xff0c;留着备份一下 导读 前面我们介绍了使用FFmpeg解码视频&#xff0c;今天我们使用FFmpeg解码音…

MySQL的多表数据记录查询笔记

关系数据操作 合并查询数据记录 在MySQL中通过关键字UNION来实现并操作&#xff0c;即可以通过其将多个SELECT语句的查询结果合并在一起组成新的关系。 两张表&#xff0c;表1 和表2 带有关键字UNION的合并操作 关键字UNION会把查询结果集直接合并在一起&#xff0c;同时将…

现代控制理论基础

在学习卡尔曼滤波、粒子滤波、隐马尔可夫模型时候&#xff0c;经常会提到状态方程的概念&#xff0c;这边联想到当时学习过的一门课程现代控制理论&#xff0c;这边就简单回顾一下吧。在回顾之前&#xff0c;串联下高等数学中微分方程的知识点。 一. 微分方程 高等数学上册第…

今年的年终奖开了个寂寞

大家好啊&#xff0c;我是董董灿。 年底了&#xff0c;又到了一些公司开年终奖的时候了&#xff0c;往年这个时候&#xff0c;网上都是争相"炫富"的声音。 还记得去年某公司&#xff0c;在春节前一下子开出了十几个月的年终奖&#xff0c;让我羡慕了好长时间。 可…

JAVAEE——request对象(三)

1. request对象 1.1 知识点 &#xff08;1&#xff09;乱码问题的两种解决方式 &#xff08;2&#xff09;post和get提交的区别 &#xff08;3&#xff09;request接收同名参数的问题 1.2 具体内容 使用request接收参数 <%page contentType"text/html; charsetut…

深入理解 go chan

go 里面&#xff0c;在实际程序运行的过程中&#xff0c;往往会有很多协程在执行&#xff0c;通过启动多个协程的方式&#xff0c;我们可以更高效地利用系统资源。 而不同协程之间往往需要进行通信&#xff0c;不同于以往多线程程序的那种通信方式&#xff0c;在 go 里面是通过…

C++ Primer 6.3 返回类型和return语句 知识点+练习题

C Primer 6.3 返回类型和return语句 无返回值函数有返回值的函数两个错误值是如何被返回的返回类类型的函数和调用运算符引用返回左值列表初始化返回值主函数main的返回值返回数组指针 递归练习题疑问待更新 无返回值函数 用在返回值类型为void的函数中&#xff0c;可以不写re…

01章【JAVA开发入门】

计算机基本概念 计算机组成原理 计算机组装 计算机&#xff1a;电子计算机&#xff0c;俗称电脑。是一种能够按照程序运行&#xff0c;自动、高速处理海量数据的现代化智能电子设备。由硬件和软件所组成&#xff0c;没有安装任何软件的计算机称为裸机。常见的形式有台式计算机、…

浅析五种 React 组件设计模式

作为一名 React 开发者&#xff0c;你可能会面临下面几个问题&#xff1a; 如何构建一个高复用度性的组件&#xff0c;使其适应不同的业务场景&#xff1f;如何构建一个具有简单 API的组件&#xff0c;使其易于使用&#xff1f;如何构建一个在 UI 和功能方面具有可扩展性的组件…

Vue3-TS中的接口-泛型-自定义类型

1首先一般在src下新建types文件夹&#xff0c;用来存放接口类型 2定义一个接口&#xff0c;用于限制person对象的具体属性 当需要用这个类型形成数组时&#xff0c;有2种写法 export type Persons Array<PersonInter> export type Persons PersonInter[] 3在文件中使…

检索增强生成技术(RAG)深度优化指南:原理、挑战、措施、展望

ChatGPT、Midjourney等生成式人工智能&#xff08;GenAI&#xff09;在文本生成、文本到图像生成等任务中表现出令人印象深刻的性能。然而&#xff0c;生成模型也不能避免其固有的局限性&#xff0c;包括产生幻觉的倾向&#xff0c;在数学能力弱&#xff0c;而且缺乏可解释性。…