RK3568设备树实战:从零开始手把手教你修改DTS文件(附常见外设节点配置)
如果你刚开始接触RK3568这类嵌入式Linux开发板,可能会对“设备树”这个词感到既熟悉又陌生。它不像C语言代码那样直观,也不像硬件电路图那样具体,但却是连接硬件与Linux内核的桥梁。我最初接触设备树时,也经历过一段迷茫期——面对动辄数千行的DTS文件,不知从何下手。后来在几个实际项目中反复折腾,才逐渐摸清了门道。这篇文章,就是把我踩过的坑、总结的经验,用最直白的方式分享给你。
设备树本质上是一种描述硬件的数据结构,它告诉Linux内核:“这块板子上有什么”。对于RK3568这样的SoC,其外设资源(如UART、I2C、SPI控制器)是固定的,但具体如何连接到外部器件(如Flash、传感器、PHY芯片),则因板而异。设备树就是用来描述这些板级差异的。你不用再像以前那样,为了支持一块新板子而去修改内核源码、重新编译;现在只需修改或新增一个DTS文件,内核就能自动识别并加载对应驱动。
这篇文章面向的是已经具备一定Linux驱动基础,但设备树经验尚浅的开发者。我会从最基础的DTS语法讲起,带你一步步为一块自定义的RK3568板子添加CPU、UART、I2C等节点,并重点解析reg地址映射、compatible匹配规则这些核心概念。最后,我会用两个真实的配置示例——SPI-NOR Flash和以太网PHY——来演示如何将理论转化为实践。目标是让你读完就能动手,为自己的硬件定制设备树。
1. 设备树基础:从概念到文件结构
在深入修改DTS文件之前,我们得先搞清楚设备树到底是什么,以及它在RK3568开发中扮演什么角色。简单来说,设备树(Device Tree)是一种描述硬件组件及其连接关系的数据结构,采用一种名为DTS(Device Tree Source)的文本格式编写。这个描述文件会被编译成DTB(Device Tree Blob)二进制格式,由Bootloader(如U-Boot)在启动内核时传递给内核。内核解析DTB后,就能知道当前运行在什么样的硬件平台上,从而正确初始化和驱动各类外设。
为什么需要设备树?在设备树普及之前,内核源码中充斥着大量板级描述代码(位于arch/arm/mach-*目录)。每支持一款新板子,就要在内核中添加或修改这些代码,导致内核“虚胖”,且移植工作繁琐。设备树将硬件描述从内核中剥离出来,实现了硬件描述与内核代码的解耦。对于RK3568,瑞芯微官方提供了rk3568.dtsi这样的SoC级描述文件,描述了芯片内部的所有公共资源。我们开发者要做的,就是基于这个文件,编写或修改板级DTS文件,描述我们自己的硬件连接。
一个典型的RK3568设备树文件结构如下所示。它通常由板级DTS文件(如rk3568-myboard.dts)和引用的SoC级DTSI文件(如rk3568.dtsi)共同构成。
// 板级DTS文件:rk3568-myboard.dts
/dts-v1/;
#include "rk3568.dtsi" // 包含SoC级定义
#include "rk3568-pinctrl.dtsi" // 包含引脚复用定义
/ {
model = "My Custom RK3568 Board";
compatible = "mycompany,rk3568-myboard", "rockchip,rk3568";
// 板级特有节点和属性定义从这里开始
chosen {
bootargs = "console=ttyS2,1500000 earlycon=uart8250,mmio32,0xfe660000";
};
// 例如,定义板载LED
leds {
compatible = "gpio-leds";
led0 {
label = "heartbeat";
gpios = <&gpio0 RK_PA0 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "heartbeat";
};
};
};
// 对SoC已有节点进行覆盖或追加配置
&uart2 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&uart2m0_xfer>;
};
&i2c3 {
status = "okay";
clock-frequency = <400000>;
// 可以在这里挂载I2C设备,例如EEPROM
eeprom@50 {
compatible = "atmel,24c02";
reg = <0x50>;
};
};
关键点解析:
/dts-v1/;:声明设备树版本,必须放在文件开头。#include:用于包含其他.dtsi或.h文件。.dtsi类似于C语言的头文件,包含可重用的公共定义。- 根节点
/:所有设备的父节点。model属性描述板子型号,compatible属性是内核匹配板子的关键,它是一组字符串列表,内核会按顺序尝试匹配。 - 节点标签与引用:
&uart2表示引用标签为uart2的节点(该节点定义在rk3568.dtsi中)。这是修改或追加现有节点配置的标准方式,避免了直接修改公共文件。 status属性:这是你最常修改的属性之一。"okay"表示启用该设备,"disabled"表示禁用。很多外设在SoC级定义中默认是"disabled",需要在板级文件中显式启用。
设备树在系统中的直观体现是/proc/device-tree目录。内核启动后,会将解析的设备树以目录结构的形式呈现于此。你可以通过cat命令查看节点的属性值,这在实际调试中非常有用。
# 查看根节点的compatible属性,确认板子匹配
cat /proc/device-tree/compatible
# 查看某个节点(如i2c3)的状态
cat /proc/device-tree/i2c3/status
2. 核心语法与属性详解:读懂并编写节点
理解了文件结构,我们再来深入看看构成设备树的基本单元:节点(Node)和属性(Property)。每个节点描述一个设备或总线,属性则是描述该设备的键值对。
2.1 节点命名与结构
一个完整的节点定义如下:
node_label: node_name@unit_address {
property1 = value1;
property2 = value2;
child_node {
// 子节点定义
};
};
node_label(标签):可选项,用于在其他地方引用该节点,格式为&label。例如,&i2c0就引用了标签为i2c0的节点。使用标签是设备树编程的最佳实践,它让引用变得清晰且易于维护。node_name(节点名):描述设备类型,如i2c、spi、uart

&spm=1001.2101.3001.5002&articleId=152250507&d=1&t=3&u=210b91e576934818a55993f6c5a1c02c)
236

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



