LV030-中断实例
这里我是看的 rk3568 的教程学习的,这里就以 rk3568 为例,虽然芯片不同,但是设备树的语法都是一样的。
一、中断相关属性
下面展示的是 iTOP-RK3568 开发板 SDK 源码中的 ft5x06 设备树, 其中就是关于中断相关的描述, 包括了 interrupts、 interrupt-controller、 #interrupt-cells、 interrupt-parent 四种常见属性:
gpio0: gpio@fdd60000 {
compatible = "rockchip,gpio-bank";
reg = <0x0 0xfdd60000 0x0 0x100>;
interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&pmucru PCLK_GPI00>, <&pmucru DBCLK_GPI00>;
gpio-controller;
#gpio-cells = <2>;
gpio-ranges = <&pinctrl 0 0 32>;
interrupt-controller;
#interrupt-cells = <2>;
};
ft5x06: ft5x06@38 {
status = "disabled";
compatible = "edt,edt-ft5306";
reg = <0x38>;
touch-gpio = <&gpio0 RK_PB5 IRQ_TYPE_EDGE_RISING>;
interrupt-parent = <&gpio0>;
interrupts = <RK_PB5 IRQ_TYPE_LEVEL_LOW>;
reset-gpios = <&gpio0 RK_PB6 GPIO_ACTIVE_LOW>;
touchscreen-size-x = <800>;
touchscreen-size-y = <1280>;
touch_type = <1>;
};1. interrupts
interrupts 属性用于指定设备的中断相关信息。 它描述了中断控制器的类型、 中断号以及中断触发类型。前面列举的设备树源码中的 gpio0 节点和 ft5x06 节点都涉及到了 interrupts 属性,如下所示:
gpio0: gpio@fdd60000 {
//....
interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
//....
};
ft5x06: ft5x06@38 {
//....
interrupts = <RK_PB5 IRQ_TYPE_LEVEL_LOW>;
//....
};gpio0 节点的 interrupts 具有三个参数, 分别表示中断控制器类型、 中断号和中断触发类型,每个参数的具体描述如下所示:
- (1) 中断控制器类型
interrupts 属性的第一个参数指定了中断控制器的类型。 常见的类型包括 GIC (Generic Interrupt Controller)、 IRQ (Basic Interrupt Handling) 等。 例如, 在给定的代码片段中, GIC_SPI 表示中断控制器的类型为 GIC SPI 中断。
中断控制器负责管理系统中的中断信号, 它可以是硬件中的专用中断控制器, 也可以是处理器内部的中断控制器。
- (2)中断号
interrupts 属性的第二个参数指定了设备所使用的中断号。 中断号是一个唯一标识符, 用于区分不同的中断信号源。 系统使用中断号来识别中断源并进行相应的中断处理。
中断号可以是一个整数值, 也可以是一个宏定义或符号引用。 在给定的代码片段中, 33 表示该设备使用的中断号为 33。
- (3) 中断触发类型
interrupts 属性的第三个参数指定了中断的触发类型, 即中断信号的触发条件。 常见的触发类型包括边沿触发和电平触发。
边沿触发表示中断信号在从低电平到高电平或从高电平到低电平的变化时触发。 触发类型可以是上升沿触发、 下降沿触发或双边沿触发。 电平触发表示中断信号在保持特定电平状态时触发, 可以是高电平触发或低电平触发。
在给定的代码片段中, IRQ_TYPE_LEVEL_HIGH 表示中断的触发类型为高电平触发。 触发类型的宏定义在内核源码“irq.h - include/dt-bindings/interrupt-controller/irq.h” 目录下, 具体内容如下所示:
#define IRQ_TYPE_NONE 0 // 无中断触发类型
#define IRQ_TYPE_EDGE_RISING 1 // 上升沿触发
#define IRQ_TYPE_EDGE_FALLING 2 // 下降沿触发
#define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)// 双边沿触发
#define IRQ_TYPE_LEVEL_HIGH 4 // 高电平触发
#define IRQ_TYPE_LEVEL_LOW 8 // 低电平触发而在 ft5x06 节点中只有中断号和中断触发类型两个参数, 这是为什么呢?我们继续往下学习。
2. interrupt-controller
interrupt-controller 属性是设备树中用于描述中断控制器的属性之一。 它提供了关于中断控制器的相关信息, 以便操作系统和其他设备能够正确配置和使用中断系统。
interrupt-controller 属性用于标识当前节点所描述的设备是一个中断控制器。 中断控制器是硬件或软件模块, 负责管理和分发中断信号。 它接收来自各种设备的中断请求, 并根据优先级和配置规则分发中断给相应的处理器或设备。
interrupt-controller 属性本身没有特定的属性值, 只需出现在节点的属性列表中即可。 出现该属性的存在即表示该节点描述的设备是中断控制器。
3. interrupt-parent
interrupt-parent 属性是设备树中用于建立中断信号源与中断控制器之间关联的属性。 它指定了中断信号源所属的中断控制器节点, 以确保正确的中断处理和分发。
interrupt-parent 属性用于指定中断信号源所属的中断控制器。 中断信号源是产生中断的设备或其他中断源节点。 通过指定中断控制器, 操作系统可以正确地将中断请求传递给相应的中断控制器节点进行处理和分发。
interrupt-parent 属性值是一个引用, 它指向中断控制器节点的路径或标签。 可以使用路径来引用中断控制器节点, 如/interrupt-controller-node, 或使用标签来引用中断控制器节点, 如&interrupt-controller-label, 在前面例子中的 ft5x06 就是通过中断控制器节点和 gpio0 中断控制器建立了联系, 如下所示:
ft5x06: ft5x06@38 {
//....
interrupt-parent = <&gpio0>;
};中断信号源节点(例如设备节点或其他中断源节点) 中的 interrupt-parent 属性用于指定中断信号源所属的中断控制器节点。 这样, 中断信号源就可以将中断请求传递给正确的中断控制器进行处理。 中断信号源节点的 interrupts 属性中的中断号和其他相关信息将与指定的中断控制器关联起来。
在某些情况下, 中断控制器可以形成多级结构, 其中一个中断控制器节点可能是另一个中断控制器的父节点。 在这种情况下, interrupt-parent 属性可以用于指定层次结构中的上级中断控制器。
4. #interrupt-cells
#interrupt-cells 属性用于描述中断控制器中每个中断信号源的中断编号单元的数量。 中断编号单元是指用于表示中断号和其他相关信息的固定大小的单元。 通过指定中断编号单元的数量, 操作系统可以正确解析和处理中断信息, 并将其与中断控制器和中断信号源进行关联。
#interrupt-cells 属性的值是一个整数, 表示中断编号单元的数量。 通常, 这个值是一个正整数, 例如 1、 2 或 3, 取决于中断控制器和设备的要求。
在 gpio0 的中断控制器为 gic, 在 gic 节点中#interrupt-cells 属性被设置为 3, 这也就是为什么在 gpio0 节点中 interrupts 属性有三个值, 而 ft5x06 的中断控制器为 gpio0, 在 gpio0 节点中#interrupt-cells 属性被设置为 2, 所以 ft5x06 节点的 interrupts 属性只有两个值。
二、中断实例
1. 硬件原理图
这里我们还是来看我们的 imx6ull,alpha 有一个按键:

按键 KEY0 是连接到 I.MX6U 的 UART1_CTS 这个 IO 上的, KEY0 接了一个 10K 的上拉电阻,因此 KEY0 没有按下的时候 UART1_CTS 应该是高电平,当 KEY0 按下以后 UART1_CTS 就是低电平。搜一下参考手册就会发现,这个引脚是 GPIO1_IO18

2. 中断号怎么确定?
可以看这个笔记《LV04-07-中断与异常-05-IMX6ULL 按键中断实例 | 苏木》这里再简单了解一下。我们前边知道了按键接在了 GPIO1_IO18 上边,我们可以查看《I.MX6UL 参考手册》的 3.2 Cortex A7 interrupts 一节,找到这个 GPIO 管脚对应的中断号:

可以看到 GPIO1 的 0 -15 管脚使用的是 66,16 - 31 使用的是 67,这里只是 IRQ 的编号,对应到 GIC 的 SPI 中断号需要在此编号基础上加上 32,所以这里的按键中断号实际为 99(67+32)。但是其实在 linux 中开发的时候,会有函数(例如 gpio_to_irq())自动帮我们计算,我们只需要知道是哪个引脚就可以了。
3. 触发方式选择
触发方式就可以看这个 irq.h - include/dt-bindings/interrupt-controller/irq.h:
#define IRQ_TYPE_NONE 0 // 无中断触发类型
#define IRQ_TYPE_EDGE_RISING 1 // 上升沿触发
#define IRQ_TYPE_EDGE_FALLING 2 // 下降沿触发
#define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)// 双边沿触发
#define IRQ_TYPE_LEVEL_HIGH 4 // 高电平触发
#define IRQ_TYPE_LEVEL_LOW 8 // 低电平触发4. 按键中断节点
按键 KEY0 使用中断模式,需要在“key”节点下添加中断相关属性,添加完成以后的“key”节点内容如下所示:
sdev_key {
#address-cells = <1>;
#size-cells = <1>;
compatible = "sdev_key";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_key>;
key-gpio = <&gpio1 18 GPIO_ACTIVE_LOW>; /* KEY0 */
interrupt-parent = <&gpio1>;
interrupts = <18 IRQ_TYPE_EDGE_BOTH>; /* FALLING RISING */
status = "okay";
};第 8 行,设置 interrupt-parent 属性值为“gpio1”,因为 KEY0 所使用的 GPIO 为 GPIO1_IO18,也就是设置 KEY0 的 GPIO 中断控制器为 gpio1。
第 9 行,设置 interrupts 属性,也就是设置中断源,第一个 cells 的 18 表示 GPIO1 组的 18 号 IO。
这个 gpio1 是在 imx6ul.dtsi:
gpio1: gpio@209c000 {
compatible = "fsl,imx6ul-gpio", "fsl,imx35-gpio";
reg = <0x0209c000 0x4000>;
interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6UL_CLK_GPIO1>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
gpio-ranges = <&iomuxc 0 23 10>, <&iomuxc 10 17 6>,
<&iomuxc 16 33 16>;
};