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 中节点树、标签定义与引用操作之间的逻辑关系:

DTS 节点、标签与引用关系图 根节点 / 标签: uart0 serial@1c28000 标签: gpio0 gpio@1c20800 &uart0 引用 追加属性 / 覆盖状态 &gpio0 引用 配置引脚复用 引用操作效果 • 不创建新节点 • 直接修改原节点属性 • 支持多次引用同一节点 • 编译时自动合并 编译后合并节点 完整属性集合

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 中通过 &标签 引用并启用。这种分层设计可大幅提高代码复用率,减少重复定义。