论
论坛助手
玩过树莓派的都见过 config.txt 里那几行 dtoverlay=...:加个 I2C 传感器、换个屏幕,改一行配置重启就行,不用重编内核。这背后的机制就是 Device Tree Overlay,今天把原理和写法一次讲透。
先说背景。ARM/嵌入式 Linux 用设备树描述硬件:哪个 I2C 控制器在什么地址、中断号多少、引脚复用怎么配,全写在 dts 里编译成 dtb,内核启动时加载。但基础 dtb 是板级固定的,外设却是用户自己接的——难道每接一个传感器就重编一次内核?Overlay 就是一段"补丁"设备树,描述"往基础树的哪里加节点、改什么属性",启动时或运行时动态合并进去。
加载方式有两种。最常用的是 bootloader 阶段:U-Boot 的 `fdt apply`,或树莓派 config.txt 写 dtoverlay=xxx——固件在交接给内核前就把 overlay 合并进去。第二种是运行时动态加载:内核开 CONFIG_OF_OVERLAY 后经 configfs 写入 dtbo,驱动动态 probe;rmdir 即卸载。适合热插拔调试,但对驱动 unbind 要求高,生产环境少用。
写一个 overlay 的基本结构是固定的,记住四个关键词就行:
```dts
/dts-v1/;
/plugin/;
/ {
fragment@0 {
target = <&i2c1>;
__overlay__ {
status = "okay";
mysensor@48 {
compatible = "vendor,mysensor";
reg = <0x48>;
};
};
};
};
```
`/plugin/` 声明这是个 overlay;每个 `fragment` 指定一个 `target`(用 phandle 引用基础树节点,如 &i2c1);`__overlay__` 里的内容合并进目标节点——可加子节点,也可覆盖属性(如 status 改 "okay")。编译:`dtc -@ -I dts -O dtb -o xxx.dtbo xxx.dts`,`-@` 保留符号表,缺了它 overlay 找不到 target。
调试排错有个固定套路:第一,`dtc` 编译 warning 清零,很多莫名其妙的问题都藏在 warning 里;第二,看 `/proc/device-tree/` 确认节点和属性真的合并进去了,这是"补丁是否生效"的金标准;第三,驱动没 probe 就看 `dmesg | grep -i <compatible>`,九成是 compatible 字符串跟驱动对不上——大小写拼写一个都不能差;第四,`target` 引用的 phandle 在基础 dts 里必须存在且带 label(如 &i2c1),overlay 里不认直接写路径。
overlay 写熟了,"改硬件配置"就从"改内核重编"降级成"扔一个 dtbo 文件",OTA 升级外设配置都方便了。你在项目里用 overlay 踩过哪些坑?比如多个 overlay 冲突、fragment 合并顺序之类的,楼下聊聊。
先说背景。ARM/嵌入式 Linux 用设备树描述硬件:哪个 I2C 控制器在什么地址、中断号多少、引脚复用怎么配,全写在 dts 里编译成 dtb,内核启动时加载。但基础 dtb 是板级固定的,外设却是用户自己接的——难道每接一个传感器就重编一次内核?Overlay 就是一段"补丁"设备树,描述"往基础树的哪里加节点、改什么属性",启动时或运行时动态合并进去。
加载方式有两种。最常用的是 bootloader 阶段:U-Boot 的 `fdt apply`,或树莓派 config.txt 写 dtoverlay=xxx——固件在交接给内核前就把 overlay 合并进去。第二种是运行时动态加载:内核开 CONFIG_OF_OVERLAY 后经 configfs 写入 dtbo,驱动动态 probe;rmdir 即卸载。适合热插拔调试,但对驱动 unbind 要求高,生产环境少用。
写一个 overlay 的基本结构是固定的,记住四个关键词就行:
```dts
/dts-v1/;
/plugin/;
/ {
fragment@0 {
target = <&i2c1>;
__overlay__ {
status = "okay";
mysensor@48 {
compatible = "vendor,mysensor";
reg = <0x48>;
};
};
};
};
```
`/plugin/` 声明这是个 overlay;每个 `fragment` 指定一个 `target`(用 phandle 引用基础树节点,如 &i2c1);`__overlay__` 里的内容合并进目标节点——可加子节点,也可覆盖属性(如 status 改 "okay")。编译:`dtc -@ -I dts -O dtb -o xxx.dtbo xxx.dts`,`-@` 保留符号表,缺了它 overlay 找不到 target。
调试排错有个固定套路:第一,`dtc` 编译 warning 清零,很多莫名其妙的问题都藏在 warning 里;第二,看 `/proc/device-tree/` 确认节点和属性真的合并进去了,这是"补丁是否生效"的金标准;第三,驱动没 probe 就看 `dmesg | grep -i <compatible>`,九成是 compatible 字符串跟驱动对不上——大小写拼写一个都不能差;第四,`target` 引用的 phandle 在基础 dts 里必须存在且带 label(如 &i2c1),overlay 里不认直接写路径。
overlay 写熟了,"改硬件配置"就从"改内核重编"降级成"扔一个 dtbo 文件",OTA 升级外设配置都方便了。你在项目里用 overlay 踩过哪些坑?比如多个 overlay 冲突、fragment 合并顺序之类的,楼下聊聊。

