RK3568设备树实战:从零开始手把手教你修改DTS文件(附常见外设配置示例)
如果你刚拿到一块基于RK3568的开发板,准备在上面跑自己的Linux系统,那么设备树(Device Tree)就是你绕不开的第一道坎。几年前,我第一次接触嵌入式Linux时,面对那些密密麻麻的.dts文件也是一头雾水——明明硬件连接都检查过了,驱动代码也写好了,可系统就是识别不到我的传感器。后来才发现,问题出在一个不起眼的设备树节点上,少写了一个status = "okay"。这种经历让我深刻体会到,在嵌入式Linux开发中,硬件描述和驱动代码同等重要,而设备树正是连接二者的桥梁。
对于RK3568这样的现代ARM芯片,Linux内核已经完全依赖设备树来获取硬件信息。这意味着,无论你是要添加一个I2C温湿度传感器、配置一个GPIO控制的LED,还是启用某个串口,都需要通过修改设备树文件来告诉内核:“嘿,这块板子上有这个设备,地址在这里,中断号是那个”。本篇文章将从一个实战者的角度,带你彻底掌握RK3568设备树的修改方法。我不会只讲枯燥的语法,而是结合具体的硬件场景——比如为I2C5接口添加MPU6050陀螺仪、配置GPIO1_A0引脚控制LED——一步步演示如何操作,并解释背后的原理和容易踩的坑。
1. 理解RK3568设备树的基本框架与文件结构
在动手修改之前,我们得先搞清楚RK3568的设备树文件是怎么组织的。打开你的Linux内核源码目录,进入arch/arm64/boot/dts/rockchip/,你会看到一大堆.dts、.dtsi和.dtb文件。别被数量吓到,它们其实有清晰的层次关系。
核心文件角色解析:
rk3568.dtsi:这是Rockchip官方提供的芯片级描述文件。它定义了RK3568这颗SoC内部的所有硬件资源,比如四个Cortex-A55 CPU核心、各个外设控制器(I2C、SPI、UART等)的寄存器地址、中断号、时钟配置等。你几乎不需要修改这个文件,它是所有RK3568板卡的共同基础。rk3568-evb1-ddr4-v10.dtsi:这是板级描述文件的“模板”或“通用部分”。它描述了基于RK3568的某款评估板(EVB)的硬件配置,比如DDR类型、电源管理、一些默认开启的外设等。不同的具体板卡可以引用它并覆盖或添加自己的配置。rk3568-atk-evb1-ddr4-v10-linux.dts:这才是你最终要修改的具体板卡设备树文件。它通过#include指令包含了上述的.dtsi文件,然后在此基础上,针对你这块特定板卡的硬件差异进行配置。比如你的板子I2C1上接的是AT24C02而不是FT5206,就需要在这里修改。
文件包含关系的直观理解:
你可以把这种结构想象成面向对象编程中的继承:
// 伪代码类比
class rk3568_soc { /* 芯片通用属性 */ }; // 对应 rk3568.dtsi
class evb_board : public rk3568_soc { /* 评估板通用属性 */ }; // 对应 rk3568-evb1-ddr4-v10.dtsi
class my_board : public evb_board { /* 我的板子特有属性 */ }; // 对应你实际修改的 .dts 文件
关键目录与编译产出:
在开发过程中,你主要关注两个位置:
- 源码位置:
arch/arm64/boot/dts/rockchip/- 存放所有.dts和.dtsi源文件。 - 编译输出:编译后会在相同目录或
arch/arm64/boot/dts/下生成对应的.dtb(Device Tree Blob)二进制文件,这个文件才是最终被内核加载的。
一个快速定位你要修改的文件的方法: 查看开发板配套资料或内核编译配置,确定你的板子对应的.dts文件名。通常可以从uboot启动日志中看到类似这样的信息:
[ 0.000000] OF: fdt: Machine model: Rockchip RK3568 ATK EVB1 DDR4 V10 Board
对应的设备树文件很可能就是rk3568-atk-evb1-ddr4-v10-linux.dts。
提示:在修改前,务必先备份原始文件。建议使用Git进行版本管理,每次修改都做好注释和提交记录。
2. 设备树语法核心精要:从节点到属性
设备树语法并不复杂,它本质上是一种结构化的键值对描述语言。我们通过一个最简单的LED节点例子来理解其核心概念。
节点(Node)的基本结构:
每个硬件设备或组件在设备树中都是一个节点。节点有名字,可以包含子节点,形成树状结构。根节点是/,所有其他节点都是它的子孙。
// 这是一个完整的节点定义示例
led1: led@1 { // 节点标签:节点名@单元地址
compatible = "gpio-leds"; // 属性:兼容性,用于匹配驱动
label = "system_status"; // 属性:标签,方便用户识别
gpios = <&gpio0 10 GPIO_ACTIVE_HIGH>; // 属性:GPIO资源引用
linux,default-trigger = "heartbeat"; // 属性:Linux特定行为
default-state = "on"; // 属性:默认状态
};
关键属性详解:
-
compatible(兼容性):这是最重要的属性,没有之一。内核通过它来决定使用哪个驱动来管理这个设备。它的值是一个或多个字符串组成的列表,格式通常为"制造商,型号"。例如:"rockchip,rk3568-i2c"匹配RK3568的I2C控制器驱动"ti,bq25601"匹配TI的BQ25601充电芯片驱动"gpio-keys"匹配通用的GPIO按键驱动
当有多个值时,内核会按顺序尝试匹配,直到找到合适的驱动。
-
reg(寄存器区域):描述设备占用的地址空间。对于内存映射设备(如UART、SPI控制器),它指定寄存器块的起始地址和长度;对于I2C从设备,它指定设备地址。// 内存映射设备示例:UART2寄存器从0xfe660000开始,长度0x100 uart2: serial@fe660000 { reg = <0x0 0xfe660000 0x0 0x100>; }; // I2C从设备示例:设备地址为0x1e(7位地址) mpu6050@68 { reg = <0x68>; }; -
status(状态):控制设备是否启用。常用值:"okay"或"ok":启用设备"disabled":禁用设备- 不写
status属性时,默认等同于"okay"
-
pinctrl-*(引脚控制):RK3568有强大的引脚复用功能,一个物理引脚可以作为GPIO、UART的TX、I2C的SCL等。pinctrl属性指定引脚的功能配置。&i2c1 { status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&i2c1m0_xfer>; // 使用i2c1m0_xfer这个引脚配置 }; -
clocks和clock-names(时钟):指定设备使用的时钟源。RK3568的时钟树比较复杂,通常直接引用芯片头文件中定义的时钟。&uart2 { clocks = <&cru SCLK_UART2>, <&cru PCLK_UART2>; clock-names = "baudclk", "apb_pclk"; };
地址单元与大小单元:#address-cells和#size-cells
这两个属性决定了子节点r

&spm=1001.2101.3001.5002&articleId=153770924&d=1&t=3&u=94699655daa74c398f8fdf3dec931f95)
863

被折叠的 条评论
为什么被折叠?



