设备树基础概念:DTS、DTC、DTB、DTBO 文件格式与关系
做嵌入式Linux开发,设备树是绕不开的一道坎。我记得刚入行那会儿,看到一堆.dts文件,完全摸不着头脑。后来被硬件改版坑过几次,才老老实实把这块啃透。今天咱们就把这几个文件格式彻底聊明白。
一、设备树到底是什么?
说白了,设备树就是一套描述硬件信息的「数据结构」。它告诉内核:你的板子上有哪些外设、它们挂在哪条总线上、寄存器地址是多少、中断号怎么配。
你想想看,以前Linux内核里塞满了各种板级的硬编码代码。换一个板子就要改内核,重新编译。有了设备树之后,硬件描述和内核代码分开了。换板子?改个.dts文件就行,内核不用动。
核心思想:设备树 = 硬件配置的「说明书」,内核是「读说明书的人」。
二、四种文件格式详解
1. DTS(Device Tree Source)
这是人类可读的源文件。用文本编辑器打开,里面是树形结构的硬件描述。我习惯把DTS比作「C语言的源文件」——写给人看的。
// 一个简单的DTS片段
/dts-v1/;
/ {
model = "TI AM335x BeagleBone Black";
compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
cpus {
cpu@0 {
compatible = "arm,cortex-a8";
device_type = "cpu";
reg = <0>;
};
};
memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x20000000>; /* 512 MB */
};
};
注意第一行 /dts-v1/;,这是版本声明。我见过有人漏掉这行,编译直接报错。嗯,这里要注意。
2. DTC(Device Tree Compiler)
DTC就是那个把DTS编译成DTB的工具。它就像gcc之于C语言。在Linux源码的 scripts/dtc/ 目录下能找到它。
用法很简单:
dtc -I dts -O dtb -o output.dtb input.dts
我个人习惯加个 -@ 参数,生成带符号表的DTB,方便后面做overlay调试。
小技巧:用 dtc -I dtb -O dts -o reverse.dts input.dtb 可以把DTB反编译回DTS。调试时特别有用,我曾经靠这个救回过一次搞丢的源文件。
3. DTB(Device Tree Blob)
DTB是二进制格式,Bootloader(比如U-Boot)把它传给内核。内核解析DTB,就知道硬件长什么样了。
DTB的结构是扁平的,但内部用「节点+属性」的方式保留了树形关系。每个节点有一个偏移量,内核通过遍历这些节点来加载驱动。
| 格式 | 可读性 | 用途 | 类比 |
|---|---|---|---|
| DTS | 人类可读 | 编写、修改 | .c源文件 |
| DTB | 机器可读 | 内核加载 | .o目标文件 |
| DTBO | 机器可读 | 运行时叠加 | .so动态库 |
4. DTBO(Device Tree Blob Overlay)
DTBO是设备树的「补丁文件」。它允许你在系统运行时,动态添加或修改硬件描述。这个功能在FPGA、可插拔扩展板上特别实用。
举个例子:你有个树莓派的扩展板,插上后通过DTBO告诉内核「我多了个I2C设备」,不用重启系统。
// 一个简单的overlay示例
/dts-v1/;
/plugin/;
/ {
fragment@0 {
target = <&i2c1>;
__overlay__ {
status = "okay";
mydevice@48 {
compatible = "myvendor,mydevice";
reg = <0x48>;
};
};
};
};
注意 /plugin/; 这个声明,它告诉DTC这是个overlay文件。编译时用 -@ 参数保留符号表,否则没法叠加。
避坑指南:我曾经在项目里用DTBO给一块FPGA加载外设,结果忘了检查符号表是否匹配。内核直接panic,查了两天才发现是overlay里的节点名和基树对不上。记住:DTBO依赖基树的符号表,编译时一定要加 -@。
三、四种文件的关系
它们的关系其实很简单,我画个图你就明白了:
流程很清楚:你写DTS,用DTC编译成DTB。如果需要动态扩展,就额外编译一个DTBO。内核启动时加载DTB,运行时再叠加DTBO。
四、实际项目中的使用建议
- DTS一定要放在版本管理里。 我见过有人只保存DTB,源文件丢了,后面改板子只能反编译,反编译出来的东西可读性很差。
- 编译时加
-@参数。 哪怕你现在不用overlay,也加上。万一后面要用呢?不加的话,DTBO根本用不了。 - DTBO命名要有规范。 我习惯用
厂商-板子-功能.dtbo的格式,比如ti-beaglebone-i2c2.dtbo。不然时间长了你自己都分不清哪个是哪个。 - 用
fdtdump调试。 内核自带这个工具,可以打印DTB的结构。遇到驱动加载问题,先dump一下看看设备树有没有被正确解析。
个人经验:调试设备树时,我经常在DTS里加一个 status = "disabled"; 的节点,然后通过DTBO动态改成 "okay"。这样不用重新编译整个内核,调试效率高很多。
好了,四种文件格式和它们的关系就讲到这里。记住:DTS是源文件,DTC是编译器,DTB是内核加载的二进制,DTBO是运行时补丁。搞懂这个,设备树就算入门了。