2. DTS 基础语法:节点、属性、标签与包含文件
设备树源文件(.dts)采用一种层次化、键值对的结构来描述硬件。理解其基础语法是编写和修改设备树的起点。本章将逐一拆解构成 DTS 文件的四个核心元素:节点(Node)、属性(Property)、标签(Label)和包含文件(Include)。
学习提示: 设备树语法与 JSON 或 XML 类似,但更简洁。它不描述软件行为,只描述“有什么硬件”以及“硬件如何连接”。
2.1 节点(Node):硬件拓扑的骨架
节点是设备树的基本组成单元,代表一个硬件设备、总线或控制器。每个节点从根节点(/)开始,形成一棵树状结构。
2.1.1 节点定义格式
// 节点基本语法
[node-name]@[unit-address] {
[property-list];
[child-node-1];
[child-node-2];
};
- node-name:节点名称,描述设备类型(如
cpu,uart,i2c)。 - unit-address:可选,通常为设备在总线上的起始地址或寄存器偏移,用于区分同名节点。
- 花括号
{ }:包含该节点的属性和子节点。 - 分号
;:每个属性或子节点定义必须以分号结束。
2.1.2 根节点与子节点示例
/dts-v1/;
/ { // 根节点
model = "TI AM335x BeagleBone";
compatible = "ti,am335x-bone", "ti,am33xx";
cpus { // 子节点:CPU 容器
#address-cells = <1>;
#size-cells = <0>;
cpu@0 { // 子节点:具体 CPU 核心
compatible = "arm,cortex-a8";
reg = <0x00>;
};
};
memory@80000000 { // 子节点:内存
device_type = "memory";
reg = <0x80000000 0x20000000>; // 起始地址 0x80000000,大小 512MB
};
};
关键点: 节点名称中的
@unit-address 不是必需的,但强烈建议在存在多个同类型设备时使用,以保持唯一性。例如 uart@44e09000 和 uart@48022000。
2.2 属性(Property):描述设备的键值对
属性是附着在节点上的数据,用于描述设备的特性、配置和连接关系。属性值可以是空、整数、字符串、字节数组或这些类型的组合。
2.2.1 常见属性类型与格式
| 属性类型 | 语法格式 | 示例 | 说明 |
|---|---|---|---|
| 空属性 | property-name; |
disable-rtc; |
仅表示存在该属性,无值。 |
| 字符串 | property-name = "string"; |
compatible = "ti,am335x-bone"; |
用双引号包裹。 |
| 32 位整数 | property-name = <value>; |
reg = <0x80000000 0x20000000>; |
尖括号内可包含多个整数,空格分隔。 |
| 64 位整数 | property-name = <0x00000000 0x80000000>; |
reg = <0x00000000 0x80000000>; |
用两个 32 位整数拼接表示。 |
| 字节数组 | property-name = [hex-bytes]; |
local-mac-address = [00 11 22 33 44 55]; |
方括号内为十六进制字节,空格分隔。 |
| 字符串列表 | property-name = "str1", "str2"; |
compatible = "ti,am335x-bone", "ti,am33xx"; |
逗号分隔多个字符串。 |
| 混合类型 | property-name = <value>, "string", [bytes]; |
gpios = <&gpio0 15 0>; |
不同数据类型用逗号分隔。 |
2.2.2 标准属性速查
compatible:最重要的属性,用于操作系统匹配驱动。格式为"厂商,设备型号"。reg:描述设备地址空间,格式为<address length>。interrupts:描述设备使用的中断号。status:设备状态,常用值"okay"(启用)或"disabled"(禁用)。
常见错误: 忘记在属性值后加分号
; 是 DTS 编译错误的最常见原因。检查每个 = 或 < 结尾是否都有分号。
2.3 标签(Label):节点的别名与引用
标签为节点提供一个全局唯一的别名,方便在其他地方引用该节点,尤其是在修改或扩展设备树时。
2.3.1 标签定义与引用
// 定义标签:在节点名称前加冒号
uart0: serial@44e09000 {
compatible = "ti,am3352-uart";
reg = <0x44e09000 0x2000>;
interrupts = <72>;
};
// 引用标签:使用 & 符号
&uart0 {
status = "okay";
pinctrl-0 = <&uart0_pins>;
};
2.3.2 标签的典型用途
| 用途 | 示例 | 说明 |
|---|---|---|
| 覆盖节点属性 | &uart0 { status = "okay"; }; |
在 .dtsi 或 .dts 中修改已有节点。 |
| 引用为 phandle | clocks = <&clk_osc 0>; |
在属性中引用另一个节点(如时钟、GPIO 控制器)。 |
| 条件编译 | /delete-node/ &uart0; |
在包含文件中删除某个节点。 |
2.4 包含文件(Include):模块化与复用
设备树支持使用 #include 预处理指令来引入其他文件,实现代码复用和模块化。通常,SoC 厂商提供 .dtsi(设备树包含文件),板级开发者在此基础上添加外设。
2.4.1 包含文件的使用
// am335x-boneblack.dts
#include "am33xx.dtsi" // 包含 SoC 级定义
#include "am335x-bone-common.dtsi" // 包含板级公共定义
/ {
model = "TI AM335x BeagleBone Black";
compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
// 板级特有设备
leds {
pinctrl-0 = <&user_led_pins>;
compatible = "gpio-leds";
led0 {
label = "beaglebone:green:usr0";
gpios = <&gpio1 21 0>;
linux,default-trigger = "heartbeat";
};
};
};
// 覆盖 SoC 级节点
&uart0 {
status = "okay";
};
2.4.2 文件组织规范
| 文件后缀 | 用途 | 示例 |
|---|---|---|
.dtsi |
SoC 级或板级公共定义,通常不包含板级特有设备。 | am33xx.dtsi, imx6qdl.dtsi |
.dts |
具体板卡设备树源文件,包含 .dtsi 并添加板级特有内容。 |
am335x-boneblack.dts, imx6q-sabresd.dts |
.dts + .dtsi |
通过 #include 组合,实现 SoC 与板级分离。 |
所有主流 BSP 均采用此模式。 |
最佳实践: 永远不要在
.dtsi 中直接定义板级特有的设备(如 LED、按键)。将 .dtsi 视为“SoC 硬件描述”,将 .dts 视为“板级配置”。这样同一 SoC 的不同板卡只需更换 .dts 文件。
2.5 综合示例:一个完整的 DTS 片段
以下示例综合了节点、属性、标签和包含文件,展示一个典型嵌入式系统的设备树描述。
// 文件:my-board.dts
/dts-v1/;
#include "soc.dtsi" // 包含 SoC 定义
/ {
model = "My Custom Board";
compatible = "my-company,my-board", "my-company,soc";
chosen {
stdout-path = &uart0;
};
memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x10000000>; // 256MB RAM
};
leds {
compatible = "gpio-leds";
led-red {
label = "red";
gpios = <&gpio2 5 1>; // GPIO2_5,低电平有效
};
};
};
// 引用 SoC 中的 uart0 节点并启用
&uart0 {
status = "okay";
clock-frequency = <48000000>;
};
// 引用 SoC 中的 i2c0 节点并添加设备
&i2c0 {
status = "okay";
clock-frequency = <100000>;
eeprom@50 {
compatible = "atmel,24c02";
reg = <0x50>;
pagesize = <16>;
};
};
编译验证: 使用
dtc -I dts -O dtb -o my-board.dtb my-board.dts 编译。如果语法正确,将生成 my-board.dtb 二进制文件。常见错误包括缺少分号、括号不匹配、属性值格式错误。
2.6 本章小结
- 节点是设备树的骨架,从根节点
/开始,形成树形结构。 - 属性是附着在节点上的键值对,使用字符串、整数、字节数组等格式描述硬件特性。
- 标签为节点提供全局别名,支持跨文件引用和属性覆盖。
- 包含文件通过
#include实现 SoC 与板级分离,是设备树模块化的核心机制。
下一步实践: 打开你开发板对应的
.dts 和 .dtsi 文件,尝试找出根节点、一个子节点、一个标签引用和一个包含文件。这是快速掌握设备树语法的有效方法。