Linux的DTS配置信息
一、介绍
在嵌入式 Linux 开发中,DTS(Device Tree Source,设备树源文件) 是一种描述硬件配置信息的文本文件,核心作用是将硬件细节(如CPU、内存、外设接口、中断号等)与内核代码解耦,避免修改内核源码即可适配不同硬件平台。
简单来说,DTS 就是给 Linux 内核的“硬件说明书”,内核通过解析它来识别当前系统有哪些硬件、以及这些硬件的参数和连接方式。
二、DTS 包含的核心配置信息
DTS 文件以树形结构组织硬件信息,主要内容包括:
- 根节点与CPU信息:最顶层的根节点( / ),以及子节点 cpus 描述CPU核心数量、架构(如ARM Cortex-A7)、时钟频率等。
- 内存配置:通过 memory 节点指定物理内存的起始地址和大小(如 reg = <0x40000000 0x20000000> 表示从0x40000000地址开始,共512MB内存)。
- 外设节点:每个硬件外设(如UART串口、SPI控制器、I2C传感器、GPIO引脚、中断控制器)对应一个独立节点,包含关键参数:
- compatible :匹配内核驱动的“兼容性字符串”(如 ti,am335x-uart 表示该UART外设适配TI AM335x系列的UART驱动)。
- reg :外设的寄存器地址范围(如 reg = <0x44E09000 0x1000> 表示寄存器起始地址0x44E09000,长度4KB)。
- interrupts :外设使用的中断号和触发方式(如 interrupts = <72 0x0> 表示中断号72,电平触发)。
- 时钟、引脚复用配置:如 clocks 指定外设依赖的时钟源, pinctrl-0 指定引脚的功能复用(如将GPIO引脚配置为UART_TX)。
- 总线节点:描述硬件总线(如I2C、SPI、AHB)的拓扑,外设节点会挂载到对应的总线节点下(如I2C传感器节点挂载在 i2c@44E0B000 总线节点下)。
三、DTS 的核心作用
1. 硬件与内核解耦:适配新硬件时,无需修改Linux内核源码,只需编写/修改DTS文件,降低开发难度。
2. 统一硬件描述标准:替代传统Linux内核中分散的“板级支持包(BSP)”代码,成为ARM、RISC-V等架构的通用硬件描述方式。
3. 支持动态配置:部分硬件参数(如GPIO功能、时钟频率)可通过DTS灵活配置,无需重新编译内核驱动。
实际开发中,DTS文件会被编译为二进制的 DTB(Device Tree Blob) 文件,在系统启动时由Bootloader(如U-Boot)加载到内存,供Linux内核解析使用。
四、🔧配置 DTS 的通用实践
基础结构:一个 DTS 文件通常以版本声明和根节点开始。
/dts-v1/; // 设备树版本声明
/ { // 根节点
model = "Your Board Name";
compatible = "your-board";
#address-cells = <1>;
#size-cells = <1>;
// ... 其他节点和属性
};
引用和覆盖:使用 #include "soc.dtsi" 包含 SoC 的通用定义( .dtsi 文件),然后在你的板级 DTS ( .dts ) 中通过标签引用(如 &uart1 )来覆盖或添加特定属性。
#include "imx6ull.dtsi" // 包含SoC通用定义
&uart1 {
status = "okay"; // 覆盖status属性,启用UART1
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart1>; // 引用引脚控制节点
};
内存映射:使用 ranges 属性在不同地址空间之间建立映射,特别是在有总线桥的情况下。
external-bus {
#address-cells = <2>;
#size-cells = <1>;
ranges = <0 0 0x10100000 0x10000>; // 子地址0x0映射到父地址0x10100000,长度0x10000
};
引脚控制:现代内核通常使用 pinctrl-* 属性来配置引脚功能,这需要在 SoC 的 .dtsi 中预先定义好引脚控制组。
&i2c1 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c1>; // 使用pinctrl节点配置I2C1引脚
clock-frequency = <100000>;
// ... 挂载在I2C1总线上的设备
};
五、 调试与验证技巧
编译与反编译:使用内核提供的 DTC 工具编译 .dts 为 .dtb ,也可将 .dtb 反编译为 .dts 进行检查: dtc -I dtb -O dts -o output.dts input.dtb 。
U-Boot 调试:在 U-Boot 中可以使用 fdt 命令检查设备树加载情况。
内核日志:启用 CONFIG_DEBUG_DEVICE_TREE 可以在内核启动时看到更详细的设备树解析信息。
确保兼容性:注意设备树语法和内核版本的匹配,旧版内核可能不支持新语法。
六、 核心
仔细阅读硬件手册: reg 、 interrupts 等属性的值必须严格参照芯片数据手册。
善用 .dtsi 文件:将 SoC 或平台的通用配置写在 .dtsi 中,板级特定的配置在 .dts 文件中通过引用进行覆盖或补充。
驱动匹配的关键: compatible 属性必须与驱动中的定义完全一致。
参考现有配置:内核源码中 arch/arm/boot/dts/ 目录下有大量参考示例,这是最好的学习资料。