Zephyr Devicetree详解-重要属性和节点

本文说明Zephyr Devicetree中常用的标准属性和Zephyr中特有的节点。

常用标准属性 链接到标题

compatible 链接到标题

compatible指定节点所代表硬件设备的名称。推荐的格式是 “vendor,device”,它的值是一个字符串或一个字符串数组。 例如

  • avago,apds9960
  • ti,hdc", "ti,hdc1010

vendor 是供应商的缩写名称。zephyr/dts/bindings/vendor-prefixes.txt 中含有普遍使用的 vendor 名称列表。 device 部分通常取自设备的规格书。

有时候也不一定是"vendor,device",当是通用硬件的时候compatible可能是下面的值:

  • gpio-keys
  • mmio-sram
  • fixed-clock

Zephyr构建系统通过compatible的值来找查找该节点正确的绑定文件,例如compatible = "espressif,esp32-timer"就会找到zephyr/dts/bindings/counter/espressif,esp32-timer.yaml绑定文件。同时Zephyr的驱动会与compatible关联,当compatible是数组时,Zephyr会按顺序寻找关联驱动,并使用最先找到的驱动。

reg 链接到标题

reg 给出设备的寻址信息,其值由一个或多个“register block”组成,“register block”的格式为(address, length) 这里address和length都是由32bit数组成,具体有多少个32bit单元取决于其父节点的#address-cells#size-cells属性。

soc {
    #address-cells = < 0x1 >;
    #size-cells = < 0x1 >;
    compatible = "simple-bus";
    interrupt-parent = < &nvic >;
    ranges;
    i3c0: i3c@36000 {
        compatible = "nxp,mcux-i3c";
        reg = < 0x36000 0x1000 >;
        interrupts = < 0x31 0x0 >;
        clocks = < &clkctl1 0x600 >;
        clk-divider = < 0xc >;
        clk-divider-slow = < 0x1 >;
        clk-divider-tc = < 0x1 >;
        status = "okay";
        #address-cells = < 0x3 >;
        #size-cells = < 0x0 >;
        pinctrl-0 = < &pinmux_i3c >;
        pinctrl-names = "default";
        i2c-scl-hz = < 0x61a80 >;
        i3c-scl-hz = < 0x61a80 >;
        i3c-od-scl-hz = < 0x61a80 >;
        lps22hh0: lps22hh@5d0000020800b30000 {
            compatible = "st,lps22hh";
            reg = < 0x5d 0x208 0xb30000 >;
            status = "okay";
        };
    };
}
  • soc#address-cells为1,size-cells为1, 其子节点i3c0的reg< 0x36000 0x1000 >
    • 1个单元的address,i3c0的寄存器组基地址为0x36000
    • 1个单元的size,i3c0的寄存器组长度为0x1000
  • i3c0#address-cells为3,size-cells为0, 其子节点lps22hh0的reg< 0x5d 0x208 0xb30000 >
    • 3个单元的address,表示lps22hh0在i3c上的地址为0x5d0000020800b30000, 按大端方式组合
    • 0个单元的size

reg的值也可以是多个(address, length) 对,例如

soc {
    #address-cells = < 0x1 >;
    #size-cells = < 0x1 >;
    compatible = "simple-bus";
    pcc: clock-controller@4000d000 {
        compatible = "nuvoton,npcx-pcc";
        /* Cells for bus type, clock control reg and bit */
        #clock-cells = <3>;
        /* First reg region is Power Management Controller */
        /* Second reg region is Core Domain Clock Generator */
        reg = <0x4000d000 0x2000 0x400b5000 0x2000>;
        reg-names = "pmc", "cdcg";
    };
}
  • soc#address-cells为1,size-cells为1, 其子节点pccreg<0x4000d000 0x2000 0x400b5000 0x2000>表示ppc在soc的总线上占有两个寄存器组
    • 一组的寄存器基地址为0x4000d000,长度为0x2000
    • 另一组的寄存器基地址为0x400b5000,长度为0x2000

以下是常见reg的adress和size模式

  • 内存映射 I/O 寄存器访问的设备: address是该设备在父节点的基地址,length 是寄存器占用的字节数
  • I2C 设备:address就算I2C 设备的地址,length为0
  • SPI 设备:address是片选的index,length为0

ranges 链接到标题

ranges 属性是用来定义地址映射,描述了子地址空间如何映射到父地址空间,使用ranges后,子节点就可以使用相对地址。

ranges有两种格式:

  • 当 ranges 属性存在但没有值,表示子地址空间和父地址空间是一对一映射,也就是用绝对地址
  • ranges=<子地址 父地址 长度> 表示子地址被映射到父地址上。
    • ranges = < 0x0 0x50000000 0x10000000 >; 表所子地址0~0x10000000被映射到了0x50000000~0x60000000
    • ranges中也允许描述多个映射关系ranges = < 0x0 0x10000000 0x500000 0x20000000 0x30000000 0x500000 >; 表示子地址0x0~0x500000被映射到父地址0x10000000~0x10500000,子地址0x20000000~0x20500000被映射到0x30000000~0x30500000

实例

peripheral: peripheral@50000000 {
    ranges = < 0x0 0x50000000 0x10000000 >;
    #address-cells = < 0x1 >;
    #size-cells = < 0x1 >;
    clkctl0: clkctl@1000 {
        compatible = "nxp,lpc-syscon";
        reg = < 0x1000 0x1000 >;
        #clock-cells = < 0x1 >;
    };
};

peripheral的子节点地址从0~0x10000000映射到0x50000000~0x60000000,因此clkctl0寄存器基地址绝对地址应该时0x500001000,寄存器组长度时0x1000

status 链接到标题

status属性用于描述节点是否启用,Devicetree 规范允许此属性具有值 okay 、 disabled 、 reserved 、 fail 和 fail-sss 。目前Zephyr只会使用 okay 和 disabled ;使用其他值当前会导致未定义的行为。如果节点的status属性为 okay 或未定义(不存在于 Devicetree 源中),则该节点被视为已启用.

interrupts 链接到标题

interrupts 属性是用来描述设备的中断信息,格式为interrupts=<中断说明符>。基本的中断说明符格式:

  • interrupts=<中断号> :例如interrupts = <3>;
  • interrupts=<中断号 触发类型>:例如interrupts = <72 4>;,触发类型的取值如下:
    • 1: 上升沿触发
    • 2: 下降沿触发
    • 3: 边沿触发(上升和下降)
    • 4: 高电平触发
    • 8: 低电平触发
  • 当设备有多个中断时可以写成这样:interrupts = <72 4>, <73 4>, <85 1>;

对于不同的体系结构又有不同的说明符格式, 更多可以参考Devicetree 规范版本 v0.3 中的第 2.4 节“中断和中断映射”.

Zephyr特殊节点 链接到标题

在Zephyr中有一些特殊节点,并不是简单的描述硬件信息,其用法更像是配置选择。

chosen 链接到标题

Zephyr Devicetree详解 Devicetree语法基础一文提到过chosen节点,并不表示实际硬件,用于表示选择节点。如下:

	chosen {
		zephyr,sram = &sram0;
		zephyr,console = &uart0;
		zephyr,shell-uart = &uart0;
		zephyr,flash = &flash0;
		zephyr,code-partition = &slot0_partition;
		zephyr,bt-hci = &esp32_bt_hci;
	};

在Zephyr的内核,测试程序,示例程序中会使用预定好的节点名,例如在代码中shell uart都会使用zephyr,shell-uart, 当相改变shell uart使用uart1时只用修改Devicetree为如下即可

	chosen {
		zephyr,sram = &sram0;
		zephyr,console = &uart0;
		zephyr,shell-uart = &uart1;
		zephyr,flash = &flash0;
		zephyr,code-partition = &slot0_partition;
		zephyr,bt-hci = &esp32_bt_hci;
	};

Zephyr支持特定的选择属性如下

Type 类型 Description 描述
zephyr,bt-c2h-uart 选择蓝牙中用于主机通信的 UART:HCI UART
zephyr,bt-mon-uart 设置用于蓝牙监控记录的 UART 设备
zephyr,bt-hci 选择蓝牙主机堆栈使用的 HCI 设备
zephyr,canbus 设置默认 CAN 控制器
zephyr,ccm 某些 STM32 SoC 上的Core-Coupled内存节点
zephyr,code-partition Zephyr Image的text section链接到的Flash分区
zephyr,console 设置控制台使用的 UART 设备
zephyr,display 设置默认显示控制器
zephyr,keyboard-scan 设置默认键盘扫描控制器
zephyr,dtcm 某些 Arm SoC 上的DTCM内存节点
zephyr,entropy 用作系统范围熵源的设备
zephyr,flash 其reg用于设置CONFIG_FLASH_BASE_ADDRESSCONFIG_FLASH_SIZE的默认值
zephyr,flash-controller zephyr,flash对应flash控制器设备的节点
zephyr,gdbstub-uart 设置GDB STUB子系统使用的 UART 设备
zephyr,ieee802154 为网络子系统设置 IEEE 802.15.4 设备
zephyr,ipc 为OpenAMP 子系统指定 IPC 设备
zephyr,ipc_shm OpenAMP 子系统使用其reg来确定可用于 IPC 的共享内存的基址和大小的节点
zephyr,itcm 某些 Arm SoC 上的ITCM内存节点
zephyr,log-uart 设置日志子系统的 UART 后端使用的 UART 设备
zephyr,ocm Xilinx Zynq-7000 和 ZynqMP SoC 上的片上存储器节点
zephyr,osdp-uart 设置 OSDP 子系统使用的 UART 设备
zephyr,ot-uart 为 OpenThread Spinel 协议指定 UART 设备
zephyr,pcie-controller PCIe Controller对应的节点
zephyr,ppp-uart 设置 PPP 使用的 UART 设备
zephyr,settings-partition Fixed partition节点。定义后,NVS 和 FCB 使用该分区
zephyr,shell-uart 设置串行 shell 后端使用的 UART 设备
zephyr,sram 其reg设置 Zephyr 可用的 SRAM 内存的基址和大小,在链接期间使用
zephyr,tracing-uart 设置tracing子系统使用的 UART 设备
zephyr,uart-mcumgr 设置Device Management使用的 UART 设备
zephyr,uart-pipe 设置串行管道pipe使用的 UART 设备
zephyr,usb-device USB 设备节点。如果定义并具有vbus-gpios属性,则 USB 子系统将使用它们来启用/禁用 VBUS

aliases 链接到标题

如果说chosen是Zephyr限定好的节点别名,那么aliases就是开放给用户自定义的节点别名,好处就是硬件修改后只需要变动Devicetree。例如应用中通过sw0访问硬件,按下面写法访问的是user_button1

aliases {
		sw0 = &user_button1;
		i2c-0 = &i2c0;
		watchdog0 = &wdt0;
	};

当我希望使用user_button2作为sw0时,修改为sw0 = &user_button2;即可,而无需改动代码

zephyr,user 链接到标题

Zephyr 的 Devicetree 脚本将zephyr,user节点作为特殊情况处理:该节点不用绑定(无compatible属性),用户可以在其中放入任意的属性并访问它们的值。当需要一些简单的属性时,可以用到它。值的注意的是,没有绑定就没有约束,Devicetree 脚本无法检查其属性的正确性,这就隐含的要求用户知道自己写的zephyr,user中属性和代码中访问该属性之间的约定。

zephyr,user支持各种类型的属性

  • 简单值
/ {
     zephyr,user {
             boolean;
             bytes = [81 82 83];
             number = <23>;
             numbers = <1>, <2>, <3>;
             string = "text";
             strings = "a", "b", "c";
     };
};

设备

/ {
     zephyr,user {
             handle = <&gpio0>;
             handles = <&gpio0>, <&gpio1>;
     };
};

GPIOs

#include <zephyr/dt-bindings/gpio/gpio.h>

/ {
     zephyr,user {
             signal-gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>;
     };
};

参考 链接到标题

https://docs.zephyrproject.org/3.7.0/build/dts/intro-syntax-structure.html#aliases-and-chosen-nodes https://docs.zephyrproject.org/3.7.0/build/dts/zephyr-user-node.html