4. DTS 基本语法:节点、属性、标签与引用
设备树源文件(.dts)采用树形结构描述硬件,其核心语法围绕 节点(node)、属性(property)、标签(label) 和 引用(&) 展开。掌握这四要素是编写正确 DTS 的基础。
4.1 节点(Node)—— 树形结构的骨架
节点是设备树的基本组成单元,每个节点代表一个硬件设备、总线或控制器。节点通过斜杠路径组织成树状层次。
节点语法规则:
- 根节点用
/表示,整个 DTS 有且只有一个根节点。 - 子节点格式:
节点名@地址 { ... }; - 节点名应反映设备类型(如
uart、i2c),地址部分为寄存器基址或片选号,可省略。 - 节点内可嵌套子节点,形成深度不超过 32 层的树。
/ { // 根节点
model = "Embedded Board";
compatible = "vendor,board";
cpu@0 { // 子节点,地址为 0
compatible = "arm,cortex-a7";
reg = <0x0>;
};
serial@1c28000 { // 子节点,地址为 0x1c28000
compatible = "ns16550a";
reg = <0x1c28000 0x100>;
};
};
4.2 属性(Property)—— 描述节点特征
属性以键值对形式存在,用于描述节点的配置信息、地址范围、中断号等。属性值支持多种数据类型。
| 属性类型 | 语法示例 | 说明 |
|---|---|---|
| 字符串 | compatible = "vendor,device"; |
用于驱动匹配,多个值用 \0 分隔 |
| 32 位整数 | reg = <0x1c28000 0x100>; |
尖括号内可包含多个整数,用空格分隔 |
| 64 位整数 | reg = <0x00000000 0x80000000>; |
用两个 32 位整数拼接表示 |
| 布尔值 | status = "disabled"; |
常用 "okay" 或 "disabled" |
| 字节数组 | local-mac-address = [00 11 22 33 44 55]; |
方括号内为十六进制字节 |
| 字符串列表 | clock-names = "uart", "spi"; |
逗号分隔多个字符串 |
属性命名规范: 推荐使用全小写字母加连字符(如
clock-frequency),避免使用下划线。自定义属性建议添加厂商前缀(如 myvendor,feature)防止冲突。
4.3 标签(Label)—— 节点的别名
标签为节点提供一个全局唯一的别名,便于在其他位置引用该节点。标签定义在节点名之前,用冒号分隔。
/ {
uart0: serial@1c28000 { // 标签为 uart0
compatible = "ns16550a";
reg = <0x1c28000 0x100>;
interrupts = <0 33 4>;
};
gpio0: gpio@1c20800 { // 标签为 gpio0
compatible = "allwinner,sun8i-gpio";
reg = <0x1c20800 0x400>;
};
};
标签命名规则:
- 只能包含字母、数字、下划线,不能以数字开头。
- 建议使用设备功能缩写(如
uart0、i2c1、mmc0)。 - 标签在整个 DTS 文件中必须唯一。
4.4 引用(&)—— 节点复用与覆盖
引用机制允许在 DTS 文件的不同位置通过 &标签 语法访问或扩展已有节点。这是实现 .dtsi 文件复用和板级覆盖的核心手段。
引用典型场景:
- 追加属性: 在
.dts中为.dtsi定义的节点添加或修改属性。 - 启用设备: 将
status从"disabled"改为"okay"。 - 填充引脚配置: 为 pinctrl 节点添加具体引脚复用信息。
// 在 .dtsi 中定义
uart0: serial@1c28000 {
compatible = "ns16550a";
reg = <0x1c28000 0x100>;
status = "disabled"; // 默认关闭
};
// 在 .dts 中引用并启用
&uart0 {
status = "okay"; // 覆盖为启用
clock-frequency = <24000000>;
};
4.5 节点、标签与引用的关系图解
下图展示了 DTS 中节点树、标签定义与引用操作之间的逻辑关系:
4.6 常见错误与避坑指南
⚠️ 新手易犯错误:
- 标签重复: 同一 DTS 中不能出现两个相同标签,否则编译报错。
- 引用未定义标签:
&uart0前必须确保uart0标签已定义。 - 属性值类型错误: 字符串用双引号,整数用尖括号,字节数组用方括号,混用会导致编译警告或解析错误。
- 节点名含特殊字符: 节点名只能使用字母、数字、连字符和
@,不能包含空格或下划线。 - 忘记分号: 每个属性定义和节点结束都必须以分号结尾。
4.7 语法速查表
| 语法元素 | 格式 | 示例 |
|---|---|---|
| 根节点 | / { ... }; |
/ { model = "board"; }; |
| 子节点 | 节点名@地址 { ... }; |
cpu@0 { reg = <0x0>; }; |
| 标签定义 | 标签: 节点名@地址 { ... }; |
uart0: serial@1c28000 { }; |
| 引用节点 | &标签 { 属性; }; |
&uart0 { status = "okay"; }; |
| 包含文件 | #include "文件名.dtsi" |
#include "sun8i.dtsi" |
实战建议: 编写 DTS 时,先在
.dtsi 中定义带标签的节点并默认关闭,然后在板级 .dts 中通过 &标签 引用并启用。这种分层设计可大幅提高代码复用率,减少重复定义。