【ARM】内核驱动之设备树的学习-长文

❤️作者主页:凉开水白菜
❤️作者简介:共同学习,互相监督,热于分享,多加讨论,一起进步!
❤️点赞 👍 收藏 ⭐再看,养成习惯

订阅的粉丝可通过PC端文末加我微信,可对文章的内容进行一对一答疑!


文章目录

  • 一、什么是设备树,为什么叫设备树?
  • 二、如何编译设备树?
  • 三、设备树基本语法
    • 3.1 根节点
    • 3.2 子节点
    • 3.3 节点名称规则
  • 四、设备树基本语法与属性
    • 4.1 reg属性
    • 4.2 #address-cells和#size-cells属性
    • 4.3 model属性
    • 4.4 status属性
    • 4.5 phandle属性
    • 4.6 compatible属性
    • 4.7 virtual-reg
  • 五、设备树特殊节点
    • 5.1 aliases 批量取别名属性
    • 5.2 chosen节点
    • 5.3 memory设备节点
    • 5.4 device_type属性
    • 5.5 自定义属性
    • 5.6 ranges属性
    • 5.7 .dtsi头文件
    • 5.8 向设备树结点追加数据,&label
  • 六、中断节点
    • 6.1 #interrupt-cells 、interrupt-parent 、interrupts
    • 6.2 RK瑞星微
    • 6.3 imx恩智浦
    • 6.4 三星平台
    • 6.5 全志平台
    • 6.6 其他写法:引用父节点属性
    • 6.7 其他写法:级联中断控制器
    • 6.8 其他写法:使用多个中断控制器
    • 6.9 总结
  • 七、时钟节点
    • 7.1 生产者属性
      • 7.1.1 #clock-cells
      • 7.1.2 clock-output-names
      • 7.1.3 clock-frequency
      • 7.1.4 assigned-clocks和assigned-clock-rates
      • 7.1.5 clock-indices
      • 7.1.6 assigned-clock-parents
    • 7.2 消费者属性
      • 7.2.1 clocks和clock-names
  • 八、 CPU节点
    • 8.1 cpus节点
    • 8.2 cpu-map节点
    • 8.3 socket节点
    • 8.4 core节点
    • 8.5 thread节点
    • 8.6 示例分析
  • 九、GPIO节点
    • 9.1 gpio-controller、#gpio-cells
    • 9.2 gpio-ranges
  • 十、Pinctrl子系统
    • 10.1 pinctrl-names
    • 10.2 pinctrl-N
    • 10.3 全志平台
    • 10.4 IMX平台
    • 10.5 三星平台
    • 10.6 RK平台
    • 10.7 总结
  • 十一、dtb文件
  • 十二、device\_node*转化为*platform\_device
    • 12.1 转换条件
    • 12.2 代码示例
  • 十三、设备树下platform\_device与platform\_driver匹配
  • 十四、设备树常用of函数
    • 14.1查找节点的 OF 函数
      • 14.1.1 of\_find\_node\_by\_name 函数
      • 14.1.2 of\_find\_node\_by\_type 函数
      • 14.1.3 of\_find\_compatible\_node 函数
      • 14.1.4 of\_find\_matching\_node\_and\_match 函数
      • 14.1.5 of\_find\_node\_by\_path 函数
    • 14.2 查找父/子节点的 OF 函数
      • 14.2.1 of\_get\_parent 函数
      • 14.2.2 of\_get\_next\_child
    • 14.3 提取属性值的 OF 函数
      • 14.3.1 of\_find\_property 函数
      • 14.3.2 of\_property\_count\_elems\_of\_size 函数
      • 14.3.3 of\_property\_read\_u32\_index 函数
      • 14.3.4 of\_property\_read\_u32\_array 函数
      • 14.3.5 of\_property\_read\_u32 函数
      • 14.3.6 of\_property\_read\_string 函数
      • 14.3.7 of\_n\_addr\_cells 函数
      • 14.3.8 of\_n\_size\_cells 函数
    • 14.4 中断获取的OF函数
      • 14.4.1 of\_parse\_and\_map函数
    • 14.5 其他常用的 OF 函数
      • 14.5.1 of\_iomap 函数
      • 14.5.2 of\_get\_address 函数
      • 14.5.3 of\_translate\_address 函数
      • 14.5.4 of\_address\_to\_resource 函数
  • 十五、设备树与驱动结合实战
    • 15.1 如何知道我们kernel使用的是那个设备树文件?
    • 15.2 不使用设备树点亮LED
    • 15.3 杂项设备获取设备树属性点亮LED
    • 15.4 platform总线匹配设备树
    • 15.5 获取中断资源并使用pinctrl驱动案件
      • 15.5.1 设备树代码
      • 15.5.2 驱动代码
  • 十六、结尾


一、什么是设备树,为什么叫设备树?

描述硬件得文本文件,因为语法结构像树所以叫设备树

DT:device tree:设备树(arm下表示)
FDT: flattened device tree:开放设备树、扁平设备树(powerpc使用的设备树,起源的设备又称openFirmware)因为源于openFirmware所以设备树很多函数带有of字词
dts:device tree source : 设备树源码
dtsi: device tree source include:通用设备树源码
dtb:device tree blob:编译设备树源码得到得文件,镜像文件
dtc:device tree compiler:设备树编译器

在这里插入图片描述
通过DTC编译dts、dtsi文件编译出dtb文件
所有的设备树文件都存在与下面的路径

// arm32位架构设备树源码位置
板子kernel/arch/arm/boot/dts
// arm64位架构设备树源码位置
板子kernel/arch/arm64/boot/dts/品牌/

二、如何编译设备树?

DTC编译器的源码路径,dtc文件夹下面的dtc执行文件就是我们的设备树编译器(要保证源码已经编译过一次)
如果编译完成还是没有可能是内核版本太低没有引进设备树,或者是配置选项未勾选,可以在.confg文件中查看该选项

在这里插入图片描述

板子kernel/scripts/dtc

最简单的设备树源码

/dts-v1/;
/ {
   

};

编译器编译指令

编译设备树:dtc -I dts -0 dtb -o xxx.dtb xxx.dts
反编译设备树: dtc -I dtb -0 dts -o xxx.dts xxx.dtb

/home/book/licheepi/kernel/scripts/dtc/dtc需要根据我们内核实际路径来找

编译
/home/book/licheepi/kernel/scripts/dtc/dtc -I dts -O dtb -o test.dtb test.dts
反编译
/home/book/licheepi/kernel/scripts/dtc/dtc -I dtb -O dts -o test.dts test.dtb

遇到错误:

Error: test.dts:1.1-2 syntax error
FATAL ERROR: Unable to parse input tree

语法错误如果把/dts-v1/;设备树版本写错或者不写就会出现该问题

编译设备树第二种方法是在内核路径下执行ARCH是指定arm位数,CROSS_COMPILE指定交叉编译器

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- dtbs

此时编译的是“板子kernel/arch/arm/boot/dts”该路径下的设备树文件,在该路径编译可能会出现错误,因为他编译的是所有的设备树文件

三、设备树基本语法

3.1 根节点

设备树的组成是一棵树,而根节点是树干,是必须存在树的组成还有子节点和子子节点组成

/dts-v1/;
/ {
   

};

3.2 子节点

以上为根节点为固定格式,下面是子节点格式

[lable:]node-name[@unit-address]{
   
     [properties definitions]
     [child nodes]   
};
// 需要注意在统一级节点名称节点名称不能相同不同级节点名称可以相同
// 子节点不能与子节点名称重复,但子子节点可以和子节点相同
// 例如子节点为node1 子子节点也可以有node1但子节点不能再有一个node1

举例

/dts-v1/;

/ {
   
    node1{
   //子节点,子节点名称为node1
        node1_child{
   //子节点的子节点,节点名称为node1_child   
         
        };
    };
    node2{
   
        node1_child{
    
         
        };
    };
};

3.3 节点名称规则

对于节点名称,在对节点进行命名的时候一般要体现设备的类型,比如网口一般命名为ethernet,串口一般命名为uart,对于名称一般要遵循下面的命令格式。

[标签]:<名称>[@<设备地址>]

其中,[标签]和[@<设备地址>]是可选项,<名称>是必选项。另外,这里的<设备地址>没有实际意义,只是让节点名称更加人性化,更方便阅读使用

例如

uart: serial@02288000

其中uart就是这个节点标签也叫别名,serial@2288000就是节点名称

这里如果子节点内容为空编译会产生警告,这个reg属性后面会讲到

test.dtb:警告(unit_address_vs_reg):节点/gpio@02288000有单元名称,但没有reg属性
test.dtb:警告(unit_address_format):节点/gpio@02288000单元名称不应以0开头

在设备树中命名使用字符或数字需要根据以下表格约束,如同C语言中的变量命名规则不能使用某某符号不能数字开头
在这里插入图片描述

四、设备树基本语法与属性

4.1 reg属性

reg属性可以用来描述地址信息,比如寄存器地址,我们的内核驱动也是通过这些属性来获取信息的,reg属性的格式如下:

reg = <address1 length1 address2 length 2 address 3 length3....>

例如

reg = <0x2200000 0x4000>
// 寄存器的起始地址0x2200000 寄存器的长度为0x4000

reg = <0x02200000 0x4000
    0x2205000 0x4000
>

4.2 #address-cells和#size-cells属性

#address-cells和#size-cells用来描述子节点中的reg信息中的地址和长度信息,他们决定了用多少个 32 位的数来表示 address 和 size,需要注意如果是在根节点中插入此属性需要位于子节点之前

例如

node1{
   
    #address-cells=<1>; //地址信息只能有一个u32记录
    #size-cells=<0>; // 长度信息为0也就是没有长度
    node1-child{
   
        reg=<0>; // 地址为0无长度
    };
};

node1{
   
    #address-cells=<1>; //地址信息只能有一个u32记录
    #size-cells=<1>; // 长度信息一个
    node1-child{
   
        reg=<0x02200000 0x4000>; //存储一个地址和一个长度信息
    };
};

node1{
   
    #address-cells=<2>; //地址信息两个u32
    #size-cells=<0>; // 长度信息无
    node1-child{
   
        reg=<0x02200000 0x02205000>; //存储两个地址
    };
};

如果属性插入在子节点之后会报错

Error: test.dts:22.5-24 Properties must precede subnodes
FATAL ERROR: Unable to parse input tree

4.3 model属性

model属性的值是一个字符串,一般用model描述一些信息,比如设备的名称名字等
例如

model = "lan8720a-eth";
model = "this is eth device";

4.4 status属性

status属性是和设备的状态有关系的,status的属性值是字符串,属性值为下面四个状态中的其中一个表示
在这里插入图片描述

4.5 phandle属性

phandle属性为devicetree中唯一的节点指定一个数字标识符,节点中的phandle属性,它的取值必须是唯一的(不要跟其他的phandle值一样),例如:

pic@10000000 {
   
    phandle = <1>;
    interrupt-controller;
};
another-device-node {
   
    interrupt-parent = <1>;   // 使用phandle值为1来引用上述节点
};

注:DTS中的大多数设备树将不包含显式的phandle属性,当DTS被编译成二进制DTB格式时,DTC工具会自动插入phandle属性。

4.6 compatible属性

该属性是非常重要的一个属性,compatible是用来和驱动进行匹配的,匹配成功后会执行probe函数,推荐的格式是“制造商,型号”

例如

compatible = "i2c-oled", "i2c-display";

compatible = "fsl,mpc8641", "ns16550";

在匹配的时候会先使用第一个值进行匹配“i2c-oled”,如果没有就使用第二个值进行匹配“i2c-display”。

技巧用法:对于某个 LED,内核中可能有 A、B、C 三个驱动都支持它,那可以这样

led {
   
    compatible = "A", "B", "C";
};

4.7 virtual-reg

虚拟reg属性指定了一个映射到设备节点的reg属性中指定的第一个物理地址的有效地址。此属性使引导程序能够为客户端程序提供已设置的虚拟到物理映射。他的值由一个32位数字组成也就是物理地址

小节示例

/dts-v1/;

/ {
   
    model = "this is linux board";
    #address-cells=<1>; // 地址信息一个
    #size-cells=<1>; // 长度信息一个

    node1{
   //子节点,子节点名称为node1
    // 这里重新赋予reg属性的address-cells限制和size-cells限制
        #address-cells=<1>; // 地址信息一个
        #size-cells=<0>; // 长度信息0
        node1_child@2280000{
   //子节点的子节点,节点名称为node1_child   
            reg = <0x02280000>;
        };
    };

    node2{
   
        node1_child{
    
         
        };
    };

    rgb:gpio@2288000{
   
        compatible = "rgb-led";
        // 这里采用根节点赋予的address-cells限制和size-cells限制
        reg = <0x02288000 0x40>;
        status = "okay";
    };
};

表示reg寄存器的值超过了32bit的限制

Error: test.dts:13.20-32 Value out of range for 32-bit array element

节点/node1/node1_child具有reg或range属性,但没有单元名称

test.dtb: Warning (unit_address_vs_reg): Node /node1/node1_child has a reg or ranges property, but no unit name

这个字节点的名称需要根据前面的格式来填写

// 修改前
node1_child{
   //子节点的子节点,节点名称为node1_child   
            reg = <0x02280000>; // reg值的大小不能超过32位,否则会产生错误            
        };
//  修改后
node1_child@2280000{
   //子节点的子节点,节点名称为node1_child   
            reg = <0x02280000>;
        };
// 也可以取个别名,注意别名不能使用-这个字符可以test_node不能test-node
test_node:node1_child@2280000{
   //子节点的子节点,节点名称为node1_child   
            reg = <0x02280000>;
        };

五、设备树特殊节点

5.1 aliases 批量取别名属性

特殊节点aliases用来定义别名。定义别名的目的就是为了方便引用节点,当然除了使用aliases来命名别名也可以在对节点命名的时候添加标签来命名别名
例如

aliases{
   
    mmc0 = &sdmmc0;
    mmc1 = &sdmmc1;
    mmc2 = &sdhc1;
    serial0 = "/simple@fe000000/serial@11c500";
};

示例

/home/book/licheepi/kernel/scripts/dtc/dtc -I dts -O dtb -o test.dtb test.dts
/dts-v1/;

/ {
   
    model = "this is linux board";
    #address-cells=<1>; // 地址信息一个
    #size-cells=<1>; // 长度信息一个

    aliases{
   
        gpiotest = "/nodel/node1_child@2280000";
        gpiotest1 = "/gpio@2288000";
        gpiotest2 = &test;
    };

    node1{
   //子节点,子节点名称为node1
    // 这里重新赋予reg属性的address-cells限制和size-cells限制
        #address-cells=<1>; // 地址信息一个
        #size-cells=<0>; // 长度信息0
        node1_child@2280000{
   //子节点的子节点,节点名称为node1_child   
            reg = <0x02280000>;
        };
    };

    test:node2{
   
        node1_child{
    
         
        };
    };

    gpio@2288000{
   
        compatible = "rgb-led";
        // 这里采用根节点赋予的address-cells限制和size-cells限制
        reg = <0x02288000 0x40>;
        status = "okay";
    };
};

反编译后得到

/home/book/licheepi/kernel/scripts/dtc/dtc -I dtb -O dts -o test.dts test.dtb
/dts-v1/;

/ {
   
    model = "this is linux board";
    #address-cells = <0x1>;
    #size-cells = <0x1>;

    aliases {
   
        gpiotest = "/nodel/node1_child@2280000";
        gpiotest1 = "/gpio@2288000";
        gpiotest2 = "/node2";
    };

    node1 {
   
        #address-cells = <0x1>;
        #size-cells = <0x0>;

        node1_child@2280000 {
   
            reg = <0x2280000>;
        };
    };

    node2 {
   

        node1_child {
   
        };
    };

    gpio@2288000 {
   
        compatible = "rgb-led";
        reg = <0x2288000 0x40>;
        status = "okay";
    };
};

5.2 chosen节点

chosen节点用来给uboot给内核传递参数,重点是bootargs参数,chose节点必须是根节点的子节点。
例如

chosen{
   
    bootargs = "root=/dev/nfs rw nfsroot=192.168.1.1 console=ttyS0,115200";
};

5.3 memory设备节点

所有设备树都需要一个memory设备节点,它描述了系统的物理内存布局。如果系统有多个内存块,可以创建多个memory节点,或者可以在单个memory节点的reg属性中指定这些地址范围和内存空间大小。
例如:一个64位的系统有两块内存空间:RAM1:起始地址是0x0,地址空间是 0x80000000;RAM2:起始地址是0x10000000,地址空间也是0x80000000;同时根节点下的 #address-cells = <2>和#size-cells = <2>,这个memory节点描述为:

memory@0 {
   
    device_type = "memory";
    reg = <0x00000000 0x00000000 0x00000000 0x80000000
           0x00000000 0x10000000 0x00000000 0x80000000>;
};

或者:
memory@0 {
   
    device_type = "memory";
    reg = <0x00000000 0x00000000 0x00000000 0x80000000>;
};
memory@10000000 {
   
    device_type = "memory";
    reg = <0x00000000 0x10000000 0x00000000 0x80000000>;
};

这里的#address-cells = <2>所以由两个u32表示一个地址,#size-cells = <2>表示一个reg有两个参数一个地址一个大小,

0x00000000 0x10000000 表示RAM2的起始地址
0x00000000 0x80000000表示地址空间为0x80000000

5.4 device_type属性

device_type 属性值为字符串, IEEE 1275 会用到此属性,用于描述设备的 FCode,但是设备树没有 FCode,所以此属性也被抛弃了。某些设备树文件中可以看到device_type属性,device_type的值是字符串,只用于cpu节点或者memmory节点进行描述

例如

memory@30000000{
   
    device_type = "memory";
    reg = <0x30000000 0x4000000>;
};

例如2

cpu1: cpu@1{
   
    device_type = "cpu";
    compatible = "arm, cortex-a35", "arm, arnv8";
    reg = <0x0 0x1>;
};

5.5 自定义属性

设备树中规定的属性有时候并不能满足我们的需求,这时候我们可以自定义属性。

例如我们这里自定义一个管脚标号的属性pinnum

pinnum= <0 1 2 3 4 5>;

也就是因为这个特性所以我们在看有些设备树文件的时候经常不能理解有一些节点的意思的原因,从根本来说设备树只是一个文件记录文件,这个记录里面的数据或则说设备怎么去使用要不要使用都需要根据我们的驱动去决定;

5.6 ranges属性

ranges属性值可以为空或者按照 (child-bus-address,parent-bus-address,length) 格式编写的数字矩阵, ranges 是一个地址映射/转换表, ranges 属性每个项目由子地址、父地址和地址空间长度这三部分组成:

  • child-bus-address:子总线地址空间的物理地址,由父节点的 #address-cells 确定此物理地址所占用的字长。
  • parent-bus-address:父总线地址空间的物理地址,同样由父节点的 #address-cells 确定此物理地址所占用的字长。
  • length:子地址空间的长度,由父节点的 #size-cells 确定此地址长度所占用的字长。
soc {
   
    compatible = "simple-bus";
    #address-cells = <1>;
    #size-cells = <1>;
    ranges = <0x0 0xe0000000 0x00100000>;
    serial {
   
        device_type = "serial";
        compatible = "ns16550";
        reg = <0x4600 0x100>;
        clock-frequency = <0>;
        interrupts = <0xA 0x8>;
        interrupt-parent = <&ipic>;
        };
};

节点 soc 定义的 ranges 属性,值为 <0x0 0xe0000000 0x00100000>,此属性值指定了一个 1024KB(0x00100000) 的地址范围,子地址空间的物理起始地址为 0x0,父地址空间的物理起始地址为 0xe0000000。

serial 是串口设备节点,
reg 属性定义了 serial 设备寄存器的起始地址为 0x4600,寄存器长度为 0x100。
经过地址转换, serial 设备可以从 0xe0004600 开始进行读写操作,0xe0004600=0x4600+0xe0000000。

5.7 .dtsi头文件

和 C 语言一样,设备树也支持头文件,设备树的头文件扩展名为 .dtsi;同时也可以像C 语言一样包含 .h头文件;在设备树中包含了一些原厂提供的头文件信息包含其路径在:kernel/scripts/dtc/include-prefixes/dt-bindings或者/kernel/include/dt-bindings他们的内容都是一样的

/include/ "sun8i-v3s.dtsi" // 包含bsp原厂提供的设备树
/include/ "dt-bindings/interrupt-controller/arm-gic.h"

注:.dtsi 文件一般用于描述 SOC 的内部外设信息,比如 CPU 架构、主频、外设寄存器地址范围,比如 UART、 IIC 等等。

5.8 向设备树结点追加数据,&label

假设需要往 i2c1 节点中添加 fxls8471 子节点,i2c1 节点是定义在 imx6ull.dtsi 文件中的,如果直接在 i2c1 节点中添加 fxls8471 相当于在其他的所有板子上都添加了 fxls8471 这个设备,其他所有使用到I.MX6ULL这颗 SOC 的板子都会引用 imx6ull.dtsi 这个文件,但是其他的板子可能并没有这个设备!所以这样操作是不行的。
按照以下方式在.dts文件中添加 fxls8471子节点即可:

&i2c1 {
   
   /* 要追加或修改的内容 */
};

通过&label 来访问节点,然后直接在里面编写要追加或者修改的内容,不会对其他使用这颗SOC的板子造成任何影响。

六、中断节点

6.1 #interrupt-cells 、interrupt-parent 、interrupts


#interrupt-cells <2>; //中断有两个值,一般一个值是管脚一个是触发方式

interrupt-parent = <&gpio0>;
interrupts = <RK_PB5 IRQ_TYPE_LEVEL_LOW>;

interrupts第一个参数表示gpio组是gpio0,管脚号为rk_pb5也就是使用gpio0-pb5这个引脚,IRQ_TYPE_LEVEL_LOW低电平触发中断,interrupts有两个值是由#interrupt-cells规定的;

6.2 RK瑞星微

在这里插入图片描述
gpio控制器

gpio-controller;

表示这个gpio的参数有两个

#gpio-cells = <2>

中断控制器

interrupt-controller;

中断有两个值,一般一个值是管脚一个是触发方式

#interrupt-cells <2>;

第一个参数表示gpio组是gpio0,管脚号为rk_pb5也就是使用gpio0-pb5这个引脚,IRQ_TYPE_LEVEL_LOW低电平触发中断,interrupts有两个值是由#interrupt-cells规定的;

interrupt-parent = <&gpio0>;
interrupts = <RK_PB5 IRQ_TYPE_LEVEL_LOW>;

中断触发方式包括:

#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

6.3 imx恩智浦

在这里插入图片描述
一图为BSP原厂编写的节点同样包含gpio控制器(gic控制器)和终端控制器,#interrupt-cells <2>;同样限制为两个参数,interrupt-parent指定了我们使用的gpio组为gpio1,使用的引脚号为9,0一般表示低电平触发;

interrupt-parent = <&gpio1>;
interrupts = <9 0>;

6.4 三星平台

在这里插入图片描述
可以看到原厂编写的子节点只有核心的几个参数和上面俩芯片的内容相同,下方的节点中我们可以看到使用了一个宏定义判断,其实就是判断使用的屏幕类型来实现不同的定义,如果是rgb屏中断引脚为gpioc_26下降沿触发,如果是使用lvds屏幕中断引脚为gpiob_29下降沿触发;

6.5 全志平台

timer@01c20c00 {
   
    compatible = "allwinner,sun4i-a10-timer";
    reg = <0x01c20c00 0xa0>;
    #interrupt-cells = <3>;
    interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
    clocks = <&osc24M>;
 };

在上面例子中 interrupts 属性指定了中断控制器、中断号 及 中断触发方式,
GIC 是一个通用中断控制器(Generic Interrupt Controller),SPI 是中断类型,IRQ_TYPE_LEVEL_HIGH 表示中断触发方式。
中断类型包括:
SGI(Software-generated interrupt):范围0 - 15,软件触发的中断,一般用于核间通讯,在内核中通常叫做 IPI (Inter processer interrupt)
PPI(Private processer interrupt): 范围16 - 31,私有外设中断,只对指定的core有效
SPI(Shared processer interrupt):范围32 - 1019,共享中断,不限定特定的core

该控制器的 interrupts 属性之所以有三个参数,是因为 gic 中断控制器中 #interrupt-cells 属性值为 3

6.6 其他写法:引用父节点属性

/ {
   

    interrupt-parent = <&gic>;
    
    gic:interrupt-controller@228000{
   
        compatible = "arm, gic";
        interrupt-controller;
        #interrupt-cells = <2>;
    };
    
    ft5x@38{
   
        compatible = "ft5x06";
        interrupt = <26 0>;
    };

在这段描述中可以看到我们的ft5x@38节点中和我们之前总结的写法有差别他没有interrupt-parent属性,这是一种特殊的写法,当子节点中没有包含interrupt-parent节点来指定我们的中断控制器的时候就会去父节点中找该属性;

6.7 其他写法:级联中断控制器

 / {
   

    interrupt-parent = <&gic>;
    
    gic:interrupt-controller@228000{
   
        compatible = "arm, gic";
        interrupt-controller;
        #interrupt-cells = <2>;
    };
    
     gic2:interrupt-controller@228200{
   
        compatible = "arm, gic2";
        interrupt-controller;
        #interrupt-cells = <2>;
        interrupt-parent = <&gic>;
     };
    
    ft5x@38{
   
        compatible = "ft5x06";
        interrupt = <26 0>;
    };

可以看到上方描述的有两个gic节点,两个gic都具备 interrupt-controller属性说明他们都是属于中断控制器,但是在gic2节点中interrupt-parent = <&gic>;引用了gic节点,这这种写法表示gic2控制器与gic控制器是属于级联状态;在内核驱动中我们可以通过某一级中断控制器获取另外一级中断控制器这就是级联;

6.8 其他写法:使用多个中断控制器

/ {
   

    gic:interrupt-controller@228000{
   
            compatible = "arm, gic";
            interrupt-controller;
            #interrupt-cells = <2>;</

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【语音控制SU-03T的使用】

语音控制SU-03T的使用 最近入手了SU-03T型号的语音模块&#xff0c;下面记录一下使用方式。相对于LD3320语音模块来说SU-03T更智能、使用更方便&#xff0c;从价格来讲也相对便宜&#xff0c;需要的可以在淘宝自行购买。 引脚详解一、智能公元/AIOT产品化平台配置 智能公元链接…

React井字棋游戏官方示例

在本篇技术博客中&#xff0c;我们将介绍一个React官方示例&#xff1a;井字棋游戏。我们将逐步讲解代码实现&#xff0c;包括游戏的组件结构、状态管理、胜者判定以及历史记录功能。让我们一起开始吧&#xff01; 项目概览 在这个井字棋游戏中&#xff0c;我们有以下组件&am…

【数据预测】基于蜣螂优化算法DBO的VMD-KELM光伏发电功率预测 短期功率预测【Matlab代码#53】

文章目录 【可更换其他算法&#xff0c;获取资源请见文章第6节&#xff1a;资源获取】1. 蜣螂优化算法DBO2. 变分模态分解VMD3. 核极限学习机KELM4. 部分代码展示5. 仿真结果展示6. 资源获取 【可更换其他算法&#xff0c;获取资源请见文章第6节&#xff1a;资源获取】 1. 蜣螂…

Vulnhub: hacksudo: search靶机

kali&#xff1a;192.168.111.111 靶机&#xff1a;192.168.111.170 信息收集 端口扫描 nmap -A -sC -v -sV -T5 -p- --scripthttp-enum 192.168.111.170 80端口目录爆破 feroxbuster -k -d 1 --url http://192.168.111.170 -w /opt/zidian/SecLists-2022.2/Discovery/Web…

机器学习之Boosting和AdaBoost

1 Boosting和AdaBoost介绍 1.1 集成学习 集成学习 (Ensemble Learning) 算法的基本思想就是将多个分类器组合&#xff0c;从而实现一个预测效果更好的集成分类器。 集成学习通过建立几个模型来解决单一预测问题。它的工作原理是生成多个分类器/模型&#xff0c;各自独立地学…

ChatGPT长文本对话输入方法

ChatGPT PROMPTs Splitter 是一个开源工具&#xff0c;旨在帮助你将大量上下文数据分成更小的块发送到 ChatGPT 的提示&#xff0c;并根据如何处理所有块接收到 ChatGPT&#xff08;或其他具有字符限制的语言模型&#xff09;的方法。 推荐&#xff1a;用 NSDT设计器 快速搭建可…

iOS开发-NotificationServiceExtension实现实时音视频呼叫通知响铃与震动

iOS开发-NotificationServiceExtension实现实时音视频呼叫通知响铃与震动 在之前的开发中&#xff0c;遇到了实时音视频呼叫通知&#xff0c;当App未打开或者App在后台时候&#xff0c;需要通知到用户&#xff0c;用户点击通知栏后是否接入实时音视频的视频或者音频通话。 在…

【雕爷学编程】MicroPython动手做(17)——掌控板之触摸引脚

知识点&#xff1a;什么是掌控板&#xff1f; 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片&#xff0c;支持WiFi和蓝牙双模通信&#xff0c;可作为物联网节点&#xff0c;实现物联网应用。同时掌控板上集成了OLED…

ChatGLM-6B 部署与 P-Tuning 微调实战-使用Pycharm实战

国产大模型ChatGLM-6B微调部署入门-使用Pycharm实战 1.ChatGLM模型介绍 ChatGLM-6B 是一个开源的、支持中英双语的对话语言模型&#xff0c;基于 General Language Model (GLM) 架构&#xff0c;具有 62 亿参数。结合模型量化技术&#xff0c;用户可以在消费级的显卡上进行本…

【指针二:穿越编程边界的超能力】

本章重点 5. 函数指针 6. 函数指针数组 7. 指向函数指针数组的指针 8. 回调函数 五、函数指针 首先看一段代码&#xff1a; 输出的是两个地址相同&#xff0c;这两个相同的地址都是 test 函数的地址。 那我们的函数的地址要想保存起来&#xff0c;怎么保存&#xff1f; 下面我…

Install the Chinese input method on Linux

Open terminal and input: sudo -i apt install fcitx fcitx-googlepinyinWait for it to finish. Search fcitx: "设置"-->"输入法": Finally, we get the following result&#xff1a; Ctrl Space&#xff1a;Switch the input method. The test …

HbuilderX运行时遇见文件找不到问题

错误类型 解决方法 找到报错的文件 系统提示crypto-js 和 sm-crypto 找不到&#xff0c;然后注释掉找不到的文件 运行成功&#xff01;&#xff01;&#xff01;

【OpenCV • c++】图像几何变换 | 图像坐标映射

&#x1f680; 个人简介&#xff1a;CSDN「博客新星」TOP 10 &#xff0c; C/C 领域新星创作者&#x1f49f; 作 者&#xff1a;锡兰_CC ❣️&#x1f4dd; 专 栏&#xff1a;【OpenCV • c】计算机视觉&#x1f308; 若有帮助&#xff0c;还请关注➕点赞➕收藏&#xff…

今天学学消息队列RocketMQ:消息类型

RocketMQ支持的消息类型有三种&#xff1a;普通消息、顺序消息、延时消息、事务消息。以下内容的代码部分都是基于rocketmq-spring-boot-starter做的。 普通消息 普通消息是一种无序消息&#xff0c;消息分布在各个MessageQueue当中&#xff0c;以保证效率为第一使命。这种消息…

AI绘画Stable Diffusion原理之Autoencoder-Latent

前言 传送门&#xff1a; stable diffusion&#xff1a;Git&#xff5c;论文 stable-diffusion-webui&#xff1a;Git Google Colab Notebook&#xff1a;Git kaggle Notebook&#xff1a;Git 今年AIGC实在是太火了&#xff0c;让人大呼许多职业即将消失&#xff0c;比如既能帮…

【Vscode | R | Win】R Markdown转html记录-Win

Rmd文件转html R语言环境Vscode扩展安装及配置配置radian R依赖包pandoc安装配置pandoc环境变量验证是否有效转rmd为html 注意本文代码块均为R语言代码&#xff0c;在R语言环境下执行即可 R语言环境 官网中去下载R语言安装包以及R-tool 可自行搜寻教程 无需下载Rstudio Vscod…

Linux:ELK:日志分析系统(使用elasticsearch集群)

原理 1. 将日志进行集中化管理&#xff08;beats&#xff09; 2. 将日志格式化&#xff08;logstash&#xff09; 将其安装在那个上面就对那个进行监控 3. 对格式化后的数据进行索引和存储&#xff08;elasticsearch&#xff09; 4. 前端数据的展示&#xff08;kibana&…

python多进程编程(模式与锁)

multiprocessing的三种模式 fork&#xff0c;【拷贝几乎所有资源】【支持文件对象/线程锁等传参】【unix】【任意位置开始】【快】spawn&#xff0c;【run参数传参必备资源】【不支持文件对象/线程锁等传参】【unix、win】【main代码块开始】【慢】forkserver&#xff0c;【ru…

C++ 类和对象

面向过程/面向对象 C语言是面向过程&#xff0c;关注过程&#xff0c;分析出求解问题的步骤&#xff0c;通过函数调用逐步解决问题 C是基于面对对象的&#xff0c;关注的是对象——将一件事拆分成不同的对象&#xff0c;依靠对象之间的交互完成 引入 C语言中结构体只能定义…

41. linux通过yum安装postgresql

文章目录 1.下载安装包2.关闭内置PostgreSQL模块:3.安装postgresql服务:4.初始化postgresql数据库:5.设置开机自启动:6.启动postgresql数据库7.查看postgresql进程8.通过netstat命令或者lsof 监听默认端口54329.使用find命令查找了一下postgresql.conf的配置位置10.修改postgre…