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

这篇具有很好参考价值的文章主要介绍了【Linux驱动】设备树中指定中断 | 驱动中获得中断 | 按键中断实验。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

🐱作者:一只大喵咪1201
🐱专栏:《Linux驱动》
🔥格言:你只管努力,剩下的交给时间!
【Linux驱动】设备树中指定中断 | 驱动中获得中断 | 按键中断实验,Linux驱动,linux,c语言,驱动开发,arm开发

🏀在设备树中指定中断

【Linux驱动】设备树中指定中断 | 驱动中获得中断 | 按键中断实验,Linux驱动,linux,c语言,驱动开发,arm开发
继续拿这个中断流程图来说话。

在硬件上,中断控制器只有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:

【Linux驱动】设备树中指定中断 | 驱动中获得中断 | 按键中断实验,Linux驱动,linux,c语言,驱动开发,arm开发
如上图所示由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

【Linux驱动】设备树中指定中断 | 驱动中获得中断 | 按键中断实验,Linux驱动,linux,c语言,驱动开发,arm开发
如上图所示新的中断框图,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:

【Linux驱动】设备树中指定中断 | 驱动中获得中断 | 按键中断实验,Linux驱动,linux,c语言,驱动开发,arm开发
如上图我们写的dts设备树文件中,这是一个spidev节点:

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

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

【Linux驱动】设备树中指定中断 | 驱动中获得中断 | 按键中断实验,Linux驱动,linux,c语言,驱动开发,arm开发
如上图所示,1就代表着low-to-high edge triggered上升沿触发。

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

🏀代码中获得中断

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

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

【Linux驱动】设备树中指定中断 | 驱动中获得中断 | 按键中断实验,Linux驱动,linux,c语言,驱动开发,arm开发
如上图所示platform_get_resource函数,用来获取中断资源:

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

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

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

【Linux驱动】设备树中指定中断 | 驱动中获得中断 | 按键中断实验,Linux驱动,linux,c语言,驱动开发,arm开发
如上图代码所示,当I2C总线和驱动程序匹配以后,会自动调用probe函数,在该函数中使用of_irq_get函数,从它的子节点I2C设备中解析出中断号irq

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

【Linux驱动】设备树中指定中断 | 驱动中获得中断 | 按键中断实验,Linux驱动,linux,c语言,驱动开发,arm开发
如上图,当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机制,异步通知,定时器,中断的线程化处理等内容都离不开中断。

【Linux驱动】设备树中指定中断 | 驱动中获得中断 | 按键中断实验,Linux驱动,linux,c语言,驱动开发,arm开发
如上图所示本喵使用的IMX6ULL开发板原理图,按键KEY1和按键KEY2使用的是GPIO5_1GPIO4_14两个引脚,并且是低电平有效。

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

⚽驱动程序

【Linux驱动】设备树中指定中断 | 驱动中获得中断 | 按键中断实验,Linux驱动,linux,c语言,驱动开发,arm开发
如上图所示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函数:

【Linux驱动】设备树中指定中断 | 驱动中获得中断 | 按键中断实验,Linux驱动,linux,c语言,驱动开发,arm开发
如上图所示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]

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

【Linux驱动】设备树中指定中断 | 驱动中获得中断 | 按键中断实验,Linux驱动,linux,c语言,驱动开发,arm开发
如上图所示中断服务函数,在里面仅获取引脚电平的逻辑值,并且打印出描述引脚的那个整数编号和引脚状态。

remove函数:

【Linux驱动】设备树中指定中断 | 驱动中获得中断 | 按键中断实验,Linux驱动,linux,c语言,驱动开发,arm开发
如上图所示remove函数,在卸载驱动程序时:

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

⚽设备树

【Linux驱动】设备树中指定中断 | 驱动中获得中断 | 按键中断实验,Linux驱动,linux,c语言,驱动开发,arm开发
如上图所示蓝色框中代码,使用图形化工具生成GPIO5_1GPIO4_14的两个pin-controller节点代码。

【Linux驱动】设备树中指定中断 | 驱动中获得中断 | 按键中断实验,Linux驱动,linux,c语言,驱动开发,arm开发
如上图所示,将生成的pin-controller节点代码复制到我们要写的dts设备树文件中:

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

【Linux驱动】设备树中指定中断 | 驱动中获得中断 | 按键中断实验,Linux驱动,linux,c语言,驱动开发,arm开发
如上图所示,在dts设备树文件的根节点下,增加按键外部设备节点gpio_keys_Big_Miaomi

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

⚽上机实验

【Linux驱动】设备树中指定中断 | 驱动中获得中断 | 按键中断实验,Linux驱动,linux,c语言,驱动开发,arm开发
如上图所示,使用上面的makefile文件编译驱动程序,生成gpio_key_drv.ko驱动模块。

【Linux驱动】设备树中指定中断 | 驱动中获得中断 | 按键中断实验,Linux驱动,linux,c语言,驱动开发,arm开发
如上图所示,将写好的gpio_key_drv.c驱动程序和设备树文件,以及Makefile上传到服务器上,分别进行编译,编程成功后将生成的gpio_key.kodtb文件都拷贝到网络文件系统中供开发板使用。

【Linux驱动】设备树中指定中断 | 驱动中获得中断 | 按键中断实验,Linux驱动,linux,c语言,驱动开发,arm开发
如上图所示,先让开发板使用新的dtb设备树文件,再使用insmod安装gpio_key_drv.ko驱动模块,可以看到安装成功后输出匹配porbe函数的调试信息。

【Linux驱动】设备树中指定中断 | 驱动中获得中断 | 按键中断实验,Linux驱动,linux,c语言,驱动开发,arm开发
如上图所示,按下开发板上的KEY1KEY2时:

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

🏀总结

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

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

最后要会实现按键中断程序。文章来源地址https://www.toymoban.com/news/detail-796706.html

到了这里,关于【Linux驱动】设备树中指定中断 | 驱动中获得中断 | 按键中断实验的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【IMX6ULL驱动开发学习】14.Linux驱动开发 - GPIO中断(设备树 + GPIO子系统)

    代码自取 【14.key_tree_pinctrl_gpios_interrupt】: https://gitee.com/chenshao777/imx6-ull_-drivers 主要接口函数: 1. of_gpio_count (获得GPIO的数量) 2. kzalloc (向内核申请空间) 3. of_get_gpio (获取GPIO子系统标号) 4. gpio_to_irq (根据GPIO子系统标号得到软件中断号) 5. request_irq (根据软件中断号

    2024年02月12日
    浏览(51)
  • 韦东山Linux驱动入门实验班(2)hello驱动---驱动层与应用层通讯,以及自动产生设备节点

    (1)学习韦东山老师的Linux,因为他讲的很精简,以至于很多人听不懂。接下来我讲介绍韦东山老师的驱动实验班的第二个Hello程序。 (2)注意,请先学习完视频再来看这个教程!本文仅供入门学习!如需深入,请搜索其他博客! (3)因为上一个教程已经讲的很详细了,所

    2024年02月05日
    浏览(49)
  • 【Linux驱动】Linux的中断系统 | 中断的重要数据结构

    🐱作者:一只大喵咪1201 🐱专栏:《Linux驱动》 🔥格言: 你只管努力,剩下的交给时间! 如上图所示,本喵使用的 IMX6ULL 也是ARM架构,中断也是异常的一种,CPU在运行的过程中,会被各种异常打断,包括: 未定义指令异常 指令、数据访问异常 SWI(软中断) 快中断 中断 导致

    2024年02月02日
    浏览(35)
  • 【Linux】按键驱动程序

    【Linux】按键驱动程序 前言: 一、按键驱动程序的背景知识 1.1 查询方式 1.2 休眠-唤醒方式 1.3 poll方式 1.4 异步通知  1.5 总结  二、按键驱动程序的框架 三、按键驱动程序实战 3.1 头文件(button_drv.h) 3.2 驱动程序(button_drv.c) 3.3 驱动程序(button_100ask_imx6ull.c) 3.4 Makefil

    2024年02月10日
    浏览(43)
  • Linux输入设备应用编程(键盘,按键,触摸屏,鼠标)

    目录 一 输入设备编程介绍 1.1 什么是输入设备呢?  1.2 什么是输入设备的应用编程?   1.3 input子系统 1.4  数据读取流程 1.5 应用程序如何解析数据 1.5.1 按键类事件:  1.5.2 相对位移事件  1.5.3 绝对位移事件  二 读取 struct input_event数据   本章学习Linux输入设备的应用编程

    2024年02月05日
    浏览(52)
  • 驱动开发-按键中断

    编写LED灯的驱动,使用GPIO子系统,里面添加按键的中断处理 1.应用程序发送指令控制LED亮灭 2.按键1 按下,led1电位反转 按键2按下,led2电位反转 按键3 按下,led3电位反转 功能函数 驱动代码

    2024年02月11日
    浏览(37)
  • linux驱动开发 - 09_中断

    链接: C/C++Linux服务器开发/后台架构师【零声教育】-学习视频教程-腾讯课堂 在裸机中使用中断需要做一大堆的工作,比如配置寄存器,使能 IRQ 等等。 Linux 内核提供了完善的中断框架,只需要申请中断,然后注册中断处理函数即可,使用非常方便,不需要一系列复杂的寄存器

    2024年02月03日
    浏览(34)
  • linux驱动学习3-外部中断

    在做中断试验时,发现中断驱动总是insmod失败,之后定位到 gpio_request 失败,之后是想到使用的野火做好的系统,在uEnv.txt中会加载大量设备树插件,将key相关的设备树插件屏蔽即可。 中断号 每个中断都有一个中断号,通过中断号即可区分不同的中断,在 Linux 内核中使用一个

    2024年02月11日
    浏览(41)
  • 【stm32----按键中断实验,按键控制LED灯】

    1、按下KEY1,LED1亮,再次按下KEY1,LED1灭; 2、按下KEY2,LED2亮,再次按下KEY2,LED2灭; 3、按下KEY3,LED3亮,再次按下KEY3,LED3灭; 一、头文件 1、gpio.h 2、key.h 二、初始化函数及功能函数 1、gpio.c 2、key.c 三、中断处理函数 do_irq.c 四、主函数 main.c 依次按下key3、key2、key1、key2

    2024年02月04日
    浏览(55)
  • STM32MP157驱动开发——按键驱动(中断)

    对于使用中断的按键驱动,内核自带的驱动程序 drivers/input/keyboard/gpio_keys.c 就可以,需要做的只是修改设备树指定引脚及键值 中断是引入其他基础知识的前提:休眠-唤醒、POLL 机制、异步通知、定时器、中断的线程化处理都离不开中断 设备树相关 查看原理图确定按键使用的

    2024年02月15日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包