一、设备树文件家族:dts、dtsi、dtb、dtbo 到底有啥区别?
做嵌入式 Linux 开发,天天跟设备树打交道。但你有没有想过,为什么会有这么多后缀名?dts、dtsi、dtb、dtbo…… 说实话,我刚入行那会儿也被搞晕过。今天咱们就把这几个文件掰开揉碎了讲清楚。
1.1 先看一张图,理清关系
我习惯用一张图来理解它们之间的关系。你看下面这个流程,基本就明白了:
1.2 .dtsi —— 设备树的“头文件”
.dtsi 全称是 Device Tree Source Include。说白了,它就是设备树的公共部分。
我在项目中遇到过这样的情况:一个芯片平台有多个开发板,每个板子外设不同,但 CPU、内存控制器、时钟这些底层配置是一样的。如果每个板子都写一份完整的 .dts,那维护起来简直是噩梦。
所以就有了 .dtsi。它存放的是:
- SoC 公共外设:比如 CPU 核、中断控制器、定时器、时钟控制器
- 芯片厂商提供的默认配置:像 I2C、SPI、UART 这些控制器的寄存器地址
- 可复用的节点定义:比如某个 IP 核的默认参数
举个例子:你打开 imx6ull.dtsi,里面定义了整个 i.MX6ULL 芯片的所有外设。然后不同的板子(比如野火、正点原子)各自写一个 .dts,通过 #include "imx6ull.dtsi" 把公共部分拉进来,再修改或添加自己板子特有的内容。
1.3 .dts —— 真正的设备树源文件
.dts 是 Device Tree Source 的缩写。它才是你真正要写的文件。
每个开发板对应一个 .dts 文件。它通过 #include 引入对应的 .dtsi,然后做三件事:
- 使能或禁用外设:比如
&uart1 { status = "okay"; }; - 修改默认参数:比如调整时钟频率、修改引脚复用
- 添加板级特有设备:比如板子上的 LED、按键、外部传感器
我个人习惯:把 .dts 写得尽量简洁。能用 &引用 方式修改的,绝不重新定义整个节点。这样后期维护起来,一眼就能看出哪些是板子特有的改动。
1.4 .dtb —— 内核真正吃进去的东西
.dtb 是 Device Tree Blob 的缩写。它是 .dts 经过 dtc 编译器编译后生成的二进制文件。
你想想看,内核在启动时,Bootloader(比如 U-Boot)会把 .dtb 文件加载到内存中,然后把地址传给内核。内核解析这个二进制数据,就知道板子上有哪些硬件了。
为什么不用 .dts 直接给内核?因为内核是 C 语言写的,它不认识文本格式的 .dts,只认二进制格式的 .dtb。这就好比你把一份 Word 文档发给别人,对方电脑没装 Word,你得先转成 PDF。
我曾经踩过一个坑:编译完内核后忘了重新编译设备树,结果烧录的还是旧版 .dtb。板子启动后,新加的 SPI 设备死活不工作。查了半天才发现是 .dtb 没更新。所以我现在每次编译内核,都会顺手执行一下 make dtbs。
1.5 .dtbo —— 运行时“打补丁”
.dtbo 是 Device Tree Blob Overlay 的缩写。这个功能是后来才加的,但非常实用。
它的作用是什么?允许你在系统运行时,动态地添加或修改设备树节点,而不需要重新编译整个 .dtb 或重启系统。
举个例子:你的板子有一个 FPGA 扩展接口。FPGA 加载不同的 bit 文件,会呈现不同的外设。如果用传统方式,你得为每种 FPGA 配置准备一个 .dtb,然后重启切换。有了 .dtbo,你可以在 FPGA 加载后,动态地 overlay 对应的设备树片段,内核就能识别新硬件了。
| 文件类型 | 格式 | 用途 | 是否直接给内核用 |
|---|---|---|---|
| .dtsi | 文本 | 公共头文件,被 .dts 包含 | 否 |
| .dts | 文本 | 板级设备树源文件 | 否 |
| .dtb | 二进制 | 编译后的设备树,内核启动时加载 | 是 |
| .dtbo | 二进制 | 运行时覆盖片段,动态修改设备树 | 是(通过 configfs 接口) |
1.6 它们之间的编译关系
搞清楚了各自的作用,咱们再看看编译命令。其实很简单:
# 编译 .dts 为 .dtb
dtc -I dts -O dtb -o myboard.dtb myboard.dts
# 编译 .dts 为 .dtbo(需要 -@ 选项保留符号)
dtc -I dts -O dtb -@ -o myoverlay.dtbo myoverlay.dts
# 反编译 .dtb 回 .dts(调试用)
dtc -I dtb -O dts -o myboard.dts myboard.dtb
注意:编译 .dtbo 时一定要加 -@ 选项。不加的话,overlay 里引用的节点符号解析不了。我刚开始用 overlay 时,就因为这个选项没加,折腾了一下午。
1.7 总结一下
嗯,到这里你应该清楚了:
- .dtsi 是公共部分,像 C 语言的 .h 头文件
- .dts 是板级源文件,你主要写这个
- .dtb 是编译后的二进制,内核启动时用
- .dtbo 是运行时补丁,动态修改设备树
这四个文件构成了设备树的完整生态。理解它们的关系,是写好设备树的第一步。后面咱们会深入每个文件的语法细节,到时候你就知道怎么写出优雅的设备树了。