设备树Device Tree简介
1. 概述
在Linux中,设备树(Device Tree)是一种描述硬件配置的数据结构,它被用来将硬件的结构信息(包括CPU 架构和型号, 内存基址和大小, 总线控制器,外设设备, 中断控制器和中断线, GPIO 控制器和引脚, 时钟源 )传递给操作系统内核。这样,内核就可以在不依赖于硬编码的情况下,支持不同的硬件平台。
设备树最初是在Open Firmware(定义计算器固件接口的标准,以前由IEEE认可。起源于Sun Microsystems,最初被称为OpenBoot)中使用的,后来被广泛用于嵌入式Linux系统,特别是那些使用ARM、PowerPC等架构的系统。设备树的主要目的是提供一种不依赖于架构的方式来描述硬件,使得同一个内核镜像能够支持多个不同的硬件平台。
设备树由以下几个部分组成:
设备树源文件(.dts):这些是文本文件,用于描述硬件设备。它们通常由硬件厂商或板级支持包(BSP)提供。
设备树编译器(dtc):这是一个工具,用于将设备树源文件(.dts)编译成设备树二进制文件(.dtb)。
设备树二进制文件(.dtb):这是由设备树编译器生成的二进制文件,它包含了硬件设备的描述信息。这个文件通常在启动时由引导程序(如U-Boot)加载到内存中,并传递给Linux内核。
设备树绑定(Bindings):这些是文档,描述了如何为特定设备编写设备树节点。它们通常位于Linux内核源码的
Documentation/devicetree/bindings目录下。
设备树的基本语法类似于树形结构,由节点(node)和属性(property)组成。每个节点可以包含子节点,属性则是键值对,用于描述节点的特性。
一个简单的设备树示例:
/dts-v1/;
/ {
model = "My Board";
compatible = "my,board";
cpus {
cpu@0 {
compatible = "arm,cortex-a9";
device_type = "cpu";
reg = <0>;
};
};
memory@0 {
device_type = "memory";
reg = <0x00000000 0x40000000>;
};
uart0: serial@101f0000 {
compatible = "ns16550a";
reg = <0x101f0000 0x1000>;
interrupts = <0x0 0x2 0x0>;
};
};
在这个例子中:
-
根节点(
/)有两个属性:model和compatible。 -
cpus节点有一个子节点cpu@0,描述了CPU的信息。 -
memory@0节点描述了内存的起始地址和大小。 -
uart0节点描述了一个串口设备,包括其寄存器地址和中断信息。
设备树在Linux内核启动时被解析,内核会根据设备树中的信息来初始化和配置硬件设备。这样,内核就可以在不重新编译的情况下,适应不同的硬件平台。
在嵌入式开发中,经常需要修改设备树来添加或修改硬件设备。修改后,需要重新编译设备树生成新的.dtb文件,并将该文件用于启动内核。
总结一下,设备树在Linux中的作用是:
描述硬件配置,使得内核能够动态地识别和初始化硬件。
减少内核为支持不同硬件平台所需的代码量。
提供一种标准化的方式来表示硬件,便于维护和移植。
在 Linux 中,设备树(Device Tree)是一种描述硬件配置的数据结构,它已经成为嵌入式 Linux 系统中描述硬件的标准方式。
2. 设备树编译和使用
# 编译 .dts 为 .dtb
dtc -I dts -O dtb -o myboard.dtb myboard.dts# 反编译 .dtb 为 .dts
dtc -I dtb -O dts -o myboard.dts myboard.dtb
# 查看当前设备树
ls /proc/device-tree/
# 查看特定属性
cat /proc/device-tree/model
# 在启动时加载设备树
# 在 bootloader 中指定:
bootz kernel_addr initrd_addr dtb_addr
3. 示例
GPIO 控制器
gpio0: gpio@1000000 {
gpio0:节点标签,其他节点可以通过&gpio0引用这个 GPIO 控制器;gpio@1000000:节点名称,表示这是一个 GPIO 控制器,位于地址 0x1000000
compatible = "vendor,gpio-controller";//用于绑定设备驱动"vendor,gpio-controller" 表示这个设备与名为 "vendor,gpio-controller" 的驱动程序兼容,实际中 vendor 会被替换为具体的厂商名,如 "ti,gpio-controller"
reg = <0x1000000 0x1000>;
定义 GPIO 控制器的内存映射区域
0x1000000:起始物理地址
0x1000:地址空间大小(4KB)#gpio-cells = <2>;
gpio-controller;
#gpio-cells = <2>:定义引用 GPIO 时需要多少个参数
通常第一个参数是 GPIO 编号
第二个参数是标志(如 GPIO_ACTIVE_HIGH/LOW)
gpio-controller:声明这是一个 GPIO 控制器
interrupt-controller;
#interrupt-cells = <2>;
interrupt-controller:声明这是一个中断控制器
#interrupt-cells = <2>:定义引用中断时需要多少个参数
通常第一个参数是中断号
第二个参数是中断类型(如边沿触发、电平触发)
}
I2C 设备
i2c0: i2c@2000000 {
compatible = "vendor,i2c-controller";
reg = <0x2000000 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
clock-frequency = <100000>;
eeprom@50 {
compatible = "atmel,24c02";
reg = <0x50>;
pagesize = <16>;
};
};
中断控制器
intc: interrupt-controller@3000000 {
compatible = "arm,gic-400";
#interrupt-cells = <3>;
interrupt-controller;
reg = <0x3000000 0x1000>,
<0x3002000 0x2000>;
};
设备树绑定(Bindings)
设备树绑定定义了特定设备所需的属性和格式:
// LED 设备绑定示例
leds {
compatible = "gpio-leds";
led0 {
label = "heartbeat";
gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "heartbeat";
};
led1 {
label = "mmc0";
gpios = <&gpio0 16 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "mmc0";
};
};
4. 调试技巧
查看设备树
# 查看完整设备树 dtc -I fs /sys/firmware/devicetree/base # 查看特定节点 find /sys/firmware/devicetree/base -name "*uart*" # 内核启动参数添加设备树调试 dracut --add "dts" ...
常用调试工具
# 设备树编译器 dtc --version # 查看设备树 overlay fdtoverlay --help # 设备树实用工具 apt-get install device-tree-compiler
注:设备树使得 Linux 内核可以支持多种硬件平台而无需重新编译,大大提高了嵌入式系统的灵活性和可维护性。
更多推荐



所有评论(0)