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
- 3个单元的address,表示
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, 其子节点pcc
的reg
为<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~0x60000000ranges
中也允许描述多个映射关系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_ADDRESS 和CONFIG_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