news 2026/9/5 6:52:58

OpenHarmony RK3568设备树移植实战:从选型到调试全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
OpenHarmony RK3568设备树移植实战:从选型到调试全解析

1. 为什么搞 OpenHarmony 移植,先得跟设备树死磕

先说个很多刚入坑 OpenHarmony 的人都会撞上的场景:你手里有一块 RK3568 的开发板,教程也下了,源码也拉了,结果打开 kernel 目录一看,arch/arm64/boot/dts/rockchip/底下躺着几十个以rk3568开头的 dts 文件。什么rk3568-evb1-ddr4-v10.dtsrk3568-evb2-lpddr4-v10.dtsrk3568-evb2-lpddr3-v10.dts,还有各种-demo-dt后缀的变体。你脑子里的第一个问题绝对是:我到底该选哪个?第二个问题可能是:这些看着差不多的 dts,改起来到底在改什么?

这就是设备树 DTS(Device Tree Source)在 OpenHarmony 实战开发里最真实的痛点,尤其是当你用的还不是官方推荐的那几块板子,而是自己画的板、自己选的 DDR 颗粒、自己调的引脚,那设备树就不再是"编译内核时顺便勾选的一个选项",而是决定你能不能点亮屏幕、能不能跑起 WiFi、能不能让系统稳定不重启的核心关卡。这篇文章就把我在 OpenHarmony + RK3568 上跟设备树死磕的整套经验写出来,从 DTS 语法基础、文件结构,到多板型选择策略、常用改动点,再到编译、烧录和排错流程,争取让看完的人从"不知道选哪个 dts"进阶到"拿到一块板子能自己把设备树改明白"。

先说明白,这篇文章对标的是 OpenHarmony 标准系统(也就是带 kernel 的 full 版本),不是轻量系统那个跑在 MCU 上的场景。标准系统里,内核用的还是 Linux 内核那套机制,所以 DTS 的语法和编译方式跟传统嵌入式 Linux 高度一致,但 OpenHarmony 的构建系统、烧录方式、以及 device 目录下的 hdf 驱动配置会和纯 Linux 有些差异,这也是很多人卡住的地方。适合谁看?正在做 OpenHarmony 板级移植的开发、打算在非官方板子上跑 OpenHarmony 的玩家、以及想把内核设备树这块"知其然不知其所以然"补全的入门者。

2. 别急着改 dts,先搞懂 DTS/DTB/DTC 到底在干什么

2.1 一套三板斧:dts、dtb、dtc 的关系

设备树这套东西,核心目的就一句话:把"硬件长什么样"和"驱动怎么工作"解耦。在设备树出现之前,内核里描述硬件的方式是写一堆 board 文件,代码里到处都是平台设备注册、资源填充,每换一块板子就要动一遍 C 代码。设备树的做法是,把硬件信息用树状的节点描述出来,内核启动时通过解析这棵树来自动匹配驱动、填充资源。

具体到 OpenHarmony 里,source 文件是.dts,这个是人类可读的文本格式。编译工具是dtc,全称 Device Tree Compiler,它把.dts编译成二进制的.dtb文件。内核启动早期阶段会去加载 dtb,然后解析树上的节点,逐个匹配驱动。这套流程和 Linux 内核完全一致,只不过在 OpenHarmony 的构建脚本里,dtc 的调用被打包进了内核编译流程,你在kernel/linux/build的日志里能看到类似DTC arch/arm64/boot/dts/rockchip/rk3568-evb2-lpddr4.dtb的输出。

这里有个非常容易踩的认知坑:很多人觉得设备树改了只要重新编译 kernel 就行,实际不是。dtb 文件编译出来以后,最终要不要被加载,还得看 bootloader(OpenHarmony 标准系统里通常是 U-Boot 或者 fastboot 方式)传不传它、传的是哪个。也就是说,你改了 dts 并编译出新的 dtb,还得确保烧录时这个 dtb 真的被放到了 boot 分区里并被引导加载。

2.2 节点、属性、标签:读懂一段 dts 的最小案例

不用把 dts 想得多玄,它本质就是个嵌套的键值对结构。看一段最常见的:

/ { model = "Rockchip RK3568 EVB2 LPDDR4 Board"; compatible = "rockchip,rk3568-evb2-lpddr4", "rockchip,rk3568"; chosen { bootargs = "earlycon=uart8250,mmio32,0xfe660000 console=ttyFIQ0 root=PARTUUID=614e0000-0000 rw rootwait"; }; memory@00000000 { device_type = "memory"; reg = <0x0 0x0 0x0 0x80000000>; }; };

根节点/下面的model是板子名称,compatible是匹配关键字,驱动通过比较这个字符串来找设备。chosen节点存放的是启动参数,这里面console=ttyFIQ0是 RK 平台特有的 FIQ 串口调试口配置,如果你自己板子的调试串口号改过,串口起不来十有八九就是这里和 U-Boot 传参没对齐。memory节点描述内存起始地址和大小,reg里四个 32 位值拼成了 64 位地址和大小,0x80000000就是 2GB。

看到没有,dts 并不复杂,复杂的是你要改哪一个字段、在什么上下文里改。一颗 SoC 有几十个外设控制器,每个控制器都要描述寄存器地址、中断号、时钟、复位、引脚等,一个完整的 RK3568 evb 板级 dts 通常有三四千行。我们不用全看懂,但得知道每一段是干嘛的,改起来才不心虚。

为了加深理解,再说一下"标签"和"引用"的关系。很多 dts 里会出现这种写法:

&uart0 { status = "okay"; };

这个&uart0是引用了在 dtsi(设备树包含文件)里定义好的uart0: serial@fe660000节点。这种分层写法是 RK 平台设备树组织的核心:SoC 级别的硬件描述全放在.dtsi里,板级文件(.dts)只负责"启用哪些外设、配什么引脚、调什么参数"。这样同一颗芯片做十几个板子,dtsi 基本不动,每个板子只需在 dts 里改外设开关和引脚复用,工作量小很多,也方便维持主线同步。

2.3 为什么说 dtsi + dts 的组织方式救了 Rockchip

RK 的 dts 目录结构特别有自己的风格。你打开kernel/linux/arch/arm64/boot/dts/rockchip/后会发现一堆.dtsi文件:

  • rk3568.dtsi:SoC 级描述,包含 CPU、GIC 中断控制器、片上外设、时钟、电源域等
  • rk3568-pinctrl.dtsi:引脚复用定义,特别长,定义了每个 pin 的可选功能
  • rk3568-aioc.dtsirk3568-cru.dtsi:音频编解码、时钟复位单元等
  • rk3568-evb.dtsi:EVB 公共板级配置
  • rk3568-evb2-lpddr4.dts:具体板型的最终 dts

这种结构的核心好处是"改配置只动一处"。举个例子,你要把一块板子的 UART2 调试串口改成 UART3,传统 Linux 开发你可能要翻 init 脚本、bootargs、内核配置、驱动代码,但在设备树模式下,你只需要在 dts/dtsi 里找到串口对应的 pinctrl 节点,把rk3568-uart2-m0相关引脚配置改成rk3568-uart3-m0,再把 bootargs 里的 console 映射对应一下,其余不用动。

理解了这套组织结构,你面对"到底选哪个 dts"这个问题时,思路就不是"试一个撞运气",而是"从 dtsi 继承链倒推出这块 dts 的关键差异"。

3. 手把手选 dts:RK3568 多板型到底怎么挑

3.1 先分清三类 dts 文件,避免一上来就懵

拿我自己的经历说。刚拿到一块 RK3568 板子时,我先去翻 SDK 里的 dts 列表,结果瞬间被文件名劝退。后来我把 RK3568 相关的 dts 文件大致分成了三类,思路就清晰了:

第一类是官方评估板(EVB)的 dts,对应你买的开发板,比如rk3568-evb1-ddr4-v10.dtsrk3568-evb2-lpddr4-v10.dts等。这类文件最全,外设基本都调通了,适合做参照模板,但不建议直接拿来量产,因为很多配置(如 IO 扩展芯片、屏幕型号)都跟你实际板子对不上。

第二类是厂商 release 的客户板型 dts。瑞芯微和方案商在发布 SDK 时,通常会附带几个客户板或者公板的设计,比如各方案商的rk3568-demo-*系列,里面有一些真实项目的影子,比如特定的 eDP 屏参、MIPI 摄像头配置、音频 codec 型号。这些 dts 适合做"同功能比对",比如你的板子正好用了同一个摄像头 sensor,可以直接把相关节点抄过来改引脚。

第三类是你们自己的板级 dts,通常由做硬件底包的人新建,可能是从 SDK 里某个最接近的 dts 拷贝出来改的。如果你在公司里负责系统移植,大概率你拿到的是这一类,而你的任务往往就是找出"它从哪个 dts 改过来的、改了什么"。

用一句话总结选型思路:先从外设和内存类型出发缩小范围,再通过串口和 flash 型号确认最终目标板,最后用 diff 对比确认继承关系。

3.2 内存颗粒类型是第一步筛选器

RK3568 支持 DDR4、LPDDR4、LPDDR4X、LPDDR3 等不同类型的内存颗粒。设备树命名里通常会直接写出来。你板子焊的是 LPDDR4,那rk3568-evb1-ddr4-v10.dts就不用看了,即使你硬编成它,启动时 DDR 初始化可能能过,但稳定性很可能出问题,因为 RK 的 ddr 频率调频表、驱动强度参数在不同颗粒类型上有差异。

怎么看自己的板子是哪种内存?最靠谱的方法当然是看原理图里的 DDR 颗粒型号,比如颗粒丝印是NT6AN512T32AV这类,查 datasheet 就知道是 LPDDR4。如果手头没有原理图,也可以看 U-Boot 启动日志,它会打印LPDDR4或者DDR4等信息。日志里还会显示容量,比如Bus Width=32 Col=10 Bank=8 Row=15等,这些参数对后续核对内存节点也有帮助。

筛选完内存类型之后,再按"板级外设差异"来做第二次筛。比如 EVB1 和 EVB2 的区别主要在接口排布和几个外设的供电控制引脚不一样。如果你拿的板子是自己画的,最接近的官方参照板是哪个,通常硬件工程师会给到参考设计图,系统工程师顺着参考设计图去选 dts,能省很多事。

3.3 x86 和 RK 的交叉困惑:电脑上能不能跑 OpenHarmony

顺便说个从热搜词里看到的高频问题:电脑版 x86 OpenHarmony 要不要写设备树?答案是:x86 平台也有设备树,但 OpenHarmony 在 PC 上更常用的是 ACPI(高级配置与电源管理接口)方式,跟 ARM 平台的设备树机制是两套不同的硬件描述体系。如果你是想在普通 x86 笔记本上装 OpenHarmony,那主要障碍不是 dts,而是 GPU 驱动、声卡、WiFi 网卡驱动这些二进制固件缺失,跟 dts 关系不大,这里不展开,免得跑题。

回到 RK3568。当你确定好内存类型和外设差异后,选 dts 就不玄学了。我自己在 RK3568 上触摸屏调试时就是这样的经历——SDK 默认的 dts 里没有我的触摸 IC 型号,我就找了一块同样用 gt9xx 系列触摸的其他板型 dts,把 i2c 节点、中断引脚、复位引脚直接参考过来,再微调 GPIO 编号,省了大量试错时间。

3.4 实在不确定选哪个,用 diff 和 log 定位

最稳妥的确认方法,是先把你怀疑的几个 dts 分别编译出 dtb,然后用 U-Boot 的booti或者 fastboot 方式分别烧写启动,看串口日志里的板级标识信息。感谢 RK 平台这点做得好:启动早期会打印板子名称,比如Board: Rockchip evb_rk3568,还有内存频率、型号信息。串口能出这些,说明 dts 至少没选得太离谱。

如果再深入一步,你还可以把两个相似的 dts 拉出来做文本比对:

diff -u rk3568-evb1-ddr4-v10.dts rk3568-evb2-lpddr4-v10.dts

你会看到差异主要集中在 ddr 类型、几个外设的 status 开关、引脚 pinctrl 配置、背光 PWM 通道、LCD 屏参等。这些差异正好是"硬件设计不同"在软件层的直接映射。做多了之后,我甚至能从 diff 内容反推硬件改了什么,所以强烈建议新人多养成 diff 的习惯,而不是只盯着一个文件埋头看。

4. 拿下一块 RK3568,DTS 要改的核心位置

4.1 串口与 bootargs:把调试口先点亮

我的习惯是拿到板子后第一件事不是去看屏幕、WiFi,而是先把调试串口点亮。串口没起来,后面所有调试都抓瞎。在 dts 里调试串口主要涉及三块:chosen节点里的bootargsconsole参数、串口节点的status和 pinctrl、以及 U-Boot 环境变量里的console=设置。

以 RK3568 为例,调试串口常用 UART2:

&uart2 { status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&uart2m0_xfer>; };

如果你发现编译烧录后串口完全没输出,第一步查 U-Boot 阶段有没有输出。如果 U-Boot 有输出但内核启动后串口停住,那大概率是 bootargs 里的console和 dts 里的 uart 节点对不上。比如 bootargs 写console=ttyFIQ0,但 dts 中实际启用的串口不是 UART2,那日志就会在 earlycon 阶段之后戛然而止。

有些板子为了让调试串口更早出 log,会在 dts 里直接加:

chosen { bootargs = "earlycon=uart8250,mmio32,0xfe660000 ..."; };

这里的0xfe660000是 UART2 的寄存器基地址。如果你的调试串口改成了 UART3(基地址0xfe670000),这里也要同步改。这块必须跟硬件原理图对应着查,别想当然。

4.2 pinctrl 与 GPIO:引脚复用错了,外设死活不工作

做 OpenHarmony 设备移植时,最大的"隐形杀手"就是引脚复用。RK3568 的引脚大部分是多功能的,同一个 pin 可能是 GPIO 功能,也可能是 UART、I2C、PWM、SPI 等功能。设备树里pinctrl-0干的事就是告诉内核:此刻这个 pin 要复用成哪个功能。

看一个典型的 i2c 节点:

&i2c2 { status = "okay"; clock-frequency = <100000>; pinctrl-names = "default"; pinctrl-0 = <&i2c2m1_xfer>; };

i2c2m1_xfer的含义是"i2c2 的 m1 组引脚做传输功能"。在rk3568-pinctrl.dtsi里能看到这组引脚具体是 GPIO3 的哪几个 pin、对应的 iomux 寄存器值。硬件工程师设计时选了哪一组引脚,你在 dts 里就必须配哪一组,写错系统不会报编译错误,但总线上的外设就是读不到,这是最典型的灰色问题。

还有一个高频翻车点:两个外设共用了同一个引脚,设备树里又没有察觉。比如你用了 I2C2 的 m1 组引脚,同时另一个模块又把其中一个 pin 配成了 GPIO 中断。硬件上如果没注意到,就有可能在开机时两个驱动都去 request 同一个 pin,导致一个 probe 失败。排查方法很简单,在 kernel 启动日志里搜pinctrl-rockchip或者pinconfig相关报错,通常会有pin ... already requested的记录。

4.3 电源与 regulator:系统反复重启先查电压域配置

很多刚开始做板级移植的朋友,设备树里外设开关都开了,但系统跑几分钟就死机,或者一加载 GPU 就重启。这种问题很大概率出在电源域和 regulator 配置上。RK3568 的 dtsi 里定义了多个 power domain,比如 GPU、NPU、VOP 等,板级 dts 里要确保对应外设节点引用了正确的 power domain。

看一个典型外设节点配置:

&gpu { status = "okay"; mali-supply = <&vdd_gpu>; power-domains = <&power RK3568_PD_GPU>; };

vdd_gpu是在板级 dtsi 里用regulator-fixed或者rk809的 regulator 节点定义的,它对应硬件上给 GPU 供电的 PMIC 输出。如果硬件上 GPU 供电不是这个 rail,或者电压值写错了,GPU 一 load 就崩。排查这类问题要用一个技巧:在 kernel 启动日志里同时抓 regulator 状态和 power domain 状态,比如通过 debugfs:

cat /sys/kernel/debug/regulator/regulator_summary cat /sys/kernel/debug/pm_genpd/pm_genpd_summary

这两个文件能直观看到每个外设的供电和电源域状态,省很多事。

4.4 显示相关:点亮 LCD 的四要素

显示设备树配置是 RK 平台移植里最繁琐、也最容易让人失去耐心的部分。一块 MIPI DSI 屏或 eDP 屏要在设备树里配的东西,大致可以拆成四块:显示控制器节点、对应的输出端口、屏参 panel 节点、背光 PWM 节点。

以常见的 MIPI DSI 屏为例,dts 里要有:

&dsi1 { status = "okay"; rockchip,lane-rate = <600>; panel@0 { compatible = "simple-panel-dsi"; reg = <0>; backlight = <&backlight>; reset-gpios = <&gpio3 RK_PB6 GPIO_ACTIVE_LOW>; prepare-delay-ms = <20>; reset-delay-ms = <20>; init-delay-ms = <20>; enable-delay-ms = <120>; disable-delay-ms = <20>; unprepare-delay-ms = <20>; width-mm = <68>; height-mm = <121>; dsi,flags = <(MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM)>; dsi,format = <MIPI_DSI_FMT_RGB888>; display-timings { native-mode = <&timing0>; timing0: timing0 { clock-frequency = <70000000>; hactive = <720>; vactive = <1280>; hback-porch = <80>; hfront-porch = <40>; vback-porch = <8>; vfront-porch = <16>; hsync-len = <24>; vsync-len = <4>; de-active = <0>; pixelclk-active = <0>; }; }; ... }; };

display-timings里的这些时序值,必须来自屏幕规格书。很多人直接抄别的板子的屏参,结果画面偏移、闪屏、甚至花屏。时序参数不对的典型表现是:屏幕能亮,但画面有偏移,或者顶部有噪声条纹,这时候单独调hback-porchvback-porch之类的值就能看到了,不用怀疑内核驱动。hactivevactive是分辨率,clock-frequency是像素时钟,这几个是硬指标,必须查规格书确认。

背光 PWM 配置也是显示环节里常见问题点。dts 里通过pwm-backlight驱动配置:

backlight: backlight { compatible = "pwm-backlight"; pwms = <&pwm3 0 25000 0>; brightness-levels = <0 4 8 16 32 64 128 255>; default-brightness-level = <6>; power-supply = <&vcc_light>; enable-gpios = <&gpio3 RK_PA0 GPIO_ACTIVE_HIGH>; };

pwms里的25000是 PWM 周期,单位是纳秒,对应 PWM 频率 40kHz。如果你发现背光有频闪,可以先查这个频率是不是在人耳可听范围或人眼敏感范围。brightness-levels数组可以做一些非线性亮度映射,嫌麻烦可以只写 0~255 的线性表,但很多屏在低亮度下会偏色,需要自己调表。

4.5 网络与 WiFi:mac 地址、天线开关这些容易漏

网络设备树的坑相对少,但也不省心。以太网的 phy 地址、复位引脚、mac 地址来源;WiFi 模组的 sdio 引脚、电源使能脚、中断脚;蓝牙的 uart 引脚和 baud 率,这些都写在 dts 里。

一个常见的坑是:WiFi 模组用的 sdio 接口,sdio 节点里需要配置non-removable属性,不然内核把它当成可插拔卡来对待,会有一些奇怪的枚举问题。另外,WiFi 的中断引脚如果没接对,会出现能扫描到热点但连不上 AP 的现象。排查这类问题要结合ifconfig和 dmesg 日志,着重看 sdio 枚举时间和报错信息。

以太网方面,RK3568 内置 GMAC,一般接一个外部 PHY(如 RTL8211F)。dts 里要指定 PHY 的地址和复位时序:

&gmac1 { status = "okay"; phy-mode = "rgmii"; clock_in_out = "input"; assigned-clocks = <&cru SCLK_GMAC1_RX_TX>, <&cru SCLK_GMAC1>; assigned-clock-rates = <0>, <125000000>; pinctrl-names = "default"; pinctrl-0 = <&gmac1m1_miim>, <&gmac1m1_rgmii_bus>; phy-handle = <&phy0>; phy-supply = <&vcc_phy>; phy0: ethernet-phy@0 { compatible = "ethernet-phy-ieee802.15-c22"; reg = <0>; reset-gpios = <&gpio4 RK_PB2 GPIO_ACTIVE_LOW>; reset-assert-us = <10000>; reset-deassert-us = <50000>; }; };

reset-assert-usreset-deassert-us这两个值跟 PHY 上电时序要求有关。如果网口插上去 link 灯不亮,先量 PHY 供电和复位引脚的波形,再看 dts 的 PHY 地址(reg = <0>)和芯片手册地址是否一致。PHY 地址不对时,内核日志会报Phy not found

5. 从修改到生效:编译 dtb 并正确烧录

5.1 OpenHarmony 内核编译的两种方式

OpenHarmony 内核编译跟普通 Linux 内核编译有细微差别,特别是你如果用的是 DevEco 或者 hb(鸿蒙构建)工具链。常用方式有两种:一种是只编内核,独立产出一份 boot.img;另一种是跟随整个系统镜像一起 build。

独立编内核的命令大致是:

cd kernel/linux make ARCH=arm64 rockchip_linux_defconfig make ARCH=arm64 rk3568-evb2-lpddr4.img -j$(nproc)

编出来的 dtb 路径通常在arch/arm64/boot/dts/rockchip/rk3568-evb2-lpddr4.dtb。这个过程跟我们日常 build kernel 基本一样,所以如果你熟悉内核编译,这步不陌生。

但 OpenHarmony 标准系统里的典型场景是用 hb 工具:

hb build -f -T kernel

或者只编译某个 kernel 镜像目标:

./build.sh --product-name rk3568 --build-target kernel

编译成功后在 out 目录下能找到新的 boot.img 或者 kernel 相关镜像。我个人的建议是:调试前期尽量用独立编译内核的方式,迭代快;等确认 dts 没问题了,再走完整系统编译,避免每次改一个引脚都全量 build 一小时。

5.2 烧录分区:dtb 到底在哪个分区

这是新手最容易卡住的地方。在 OpenHarmony 的 RK3568 烧录脚本里,常见分区包括bootvendorsystemuserdata等。部分 SDK 会把 dtb 独立成一个分区(比如dtbo),但 RK3568 的 OpenHarmony 通常不是独立 dtbo 分区,而是把 dtb 打包进boot.img或者resource.img。具体要看 SDK 的 mkimage 配置。

如果你改完 dts 并编了新 boot.img,烧录时只需要烧 boot 分区:

upgrade_tool uf boot.img

如果烧完发现改动没生效,多半是因为 boot.img 里的实际 dtb 不是你以为的那个。验证方法是:在系统起来后,用以下命令读出当前实际使用的设备树:

ls /sys/firmware/devicetree/base/model cat /sys/firmware/devicetree/base/model

如果显示的 model 不是你改过的那个字符,说明 boot.img 打的 dtb 不对,回查内核构建配置或打包脚本。再强调一次:这个"你以为改了但实际没生效"的问题,占了 dts 调试时间的很大一部分,所以我每改完一处,必查一遍/sys/firmware/devicetree/base/下的实时树。

5.3 快速验证 dts 语法正确性:dtc 单独编译

如果你不想每次为了验证 dts 拼写错误去编整个内核,也可以单独直接跑 dtc 编译。OpenHarmony 内核源码目录里如果有 dtc 工具,可以用:

./scripts/dtc/dtc -I dts -O dtb -o test.dtb rk3568-evb2-lpddr4.dts

这个过程能最快暴露语法错误,比如漏了分号、大括号不匹配等。但注意:单独的 dts 文件通常会#include一堆 dtsi,直接跑 dtc 常常会因为找不到头文件而失败,需要用-i参数指定 include 路径。而在内核 build 里,这些 include 路径由 Makefile 统一管理,所以编译失败时不一定是你的 dts 语法错,也可能是包含路径问题。

dtb 编出来以后可以用fdtdump或者dtc -I dtb -O dts反编译来检查最终展开的设备树,看你的改动是否真的合入、有没有被 dtsi 里的默认值覆盖。

6. 踩坑实录:我在这几个问题上卡得最久

6.1 改了 dts 屏幕还是黑的,原来卡在 u-boot 的 logo 参数

这块记忆太深刻了。有次帮客户调一块非官方屏幕,dts 里的屏参、pinctrl、背光都配好了,内核日志也显示panel-simple-dsiprobe 成功,但屏幕始终黑着。折腾了整整两天,最后发现问题根本不在内核 dts,而在 U-Boot 环境变量。RK 平台 U-Boot 会先初始化显示并显示 logo,如果 U-Boot 里没有配置对应的屏幕参数,它初始化失败后跳过显示,但它不会把信息告诉内核,导致内核把屏当成了"已经在工作的状态",于是什么都不做。

最终解决办法是同步修改 U-Boot 设备树或环境变量里的显示配置。这个案例想说明的是,dts 调试往往不是孤立问题,需要把 U-Boot 阶段、内核阶段、甚至 vendor 的 hdf 驱动拿到一起看。所以新人在排查显示问题时,先问一句:U-Boot 阶段屏幕有 logo 吗?U-Boot 没有输出,就开始死磕内核 dts,方向就错了。

6.2 两个 dts 的 WiFi 节点冲突,日志里全是 sdio 超时

有一次在一批板子上发现有十几块 WiFi 连不上 AP,但能扫到网络。反复排查后,发现问题不是天线、不是驱动,而是我在一个公共 dtsi 里改了 sdio 引脚定义,结果某个板型 dts 里又覆盖了同一组引脚为 GPIO 其他功能。两个节点同时引用同一个 pin,内核没有直接报错,但 sdio 的时钟线被拉低,枚举过程不稳定,出现间歇性超时。

从这个坑里我学到一条经验:RK 平台 dts 的继承关系比较复杂,你在 dtsi 里改引脚,一定要全盘检查所有下游 dts 有没有覆盖。检查方法还是 diff 和 grep:

grep -rn "i2c2m1\|sdmmc1\|gmac1m1" arch/arm64/boot/dts/rockchip/

把所有引用都拉出来看一遍,避免"你以为是全局配置,实际上在别处被悄悄覆盖"的尴尬。

6.3 内核打印 "failed to get regulator" 不代表 dts 错了

很多外设节点在 probe 时都会打印failed to get ... regulator之类的 log,新手一看就以为 dts 少了 regulator 引用。但很多时候,这只是驱动尝试获取一个可选 regulator,失败了会跳过,并不影响功能。

怎么判断是致命还是可选?两个方法:一是看驱动源码,搜索这个打印是在devm_regulator_get_optional还是devm_regulator_get后面,后者如果没有对应 regulator 通常会直接返回并 fail probe;二是看这个 log 之后有没有probe success之类的输出。如果有成功日志,说明这个 regulator 是可选项,不用管。这个经验能避免你在排错时被日志误导,白白浪费半天去补一个根本不存在的电压节点。

6.4 系统起来之后 dts 生效了,但 hdf 驱动不匹配怎么办

OpenHarmony 标准系统在标准内核之上还有一层 HDF(HarmonyOS Driver Framework)驱动框架。部分外设驱动,比如 sensor、display、audio 的某些能力,是由 HDF 驱动的,它们除了要读 dts 节点,还会读vendor分区里的 HDF 配置,通常是hdf_default或者板级配置文件里的device_info

这意味着你在 dts 里配好了硬件资源,但 HDF 配置里如果没有声明对应的设备,驱动一样不会加载。典型的表现是:内核日志里什么都没有,没有 probe 失败,也没有成功日志,就是设备节点不存在。排查思路是去vendor代码目录里找对应的配置文件,确认 HDF 设备声明与 dts 节点匹配。这块内容如果要展开讲,篇幅非常大,这里只提一个排查入口:/sys/kernel/debug/hdf/目录下有 HDF 驱动的调试信息,看驱动列表能更快定位是内核驱动问题还是 HDF 配置问题。

经验总结是:OpenHarmony 的设备树调试,比传统 Linux 多了一层 HDF 的维度,如果你只盯着 dts 改、不看 HDF 配置,很容易陷入"明明改对了却不生效"的循环。反过来,如果你能把这套"dts + HDF + U-Boot + 打包烧录"的完整链路理清楚,那么 RK3568 平台的绝大多数外设问题都能在半小时内定位到具体环节。

最后给我个人最常用的一条小建议:每次拿到一块新板子,不要急着改驱动,先花一小时做设备树基线工作——确认串口、确认内存容量、确认存储介质、确认屏幕类型,把这四条路径全打通,再谈其他功能。这条习惯我沿用到现在,帮我避开了无数次"改了半天才发现之前底层配置就不对"的冤枉路。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/5 6:51:37

x86、ARM、RISC-V中断机制深度对比:一根主线看懂三大架构处理流程

把三种架构的中断手册摊在一起看&#xff0c;你会发现一个有意思的现象&#xff1a;x86的中断流程写得像一部程序员的流水账&#xff0c;ARM的异常模型讲得像个状态机&#xff0c;RISC-V则在强调“我只是把陷阱门打开了&#xff0c;剩下的你来”。但只要你真正在嵌入式或OS底层…

作者头像 李华
网站建设 2026/9/5 6:50:20

端侧AI部署实战:边缘算力模组选型与避坑指南

不少做端侧AI的朋友应该都有这种经历&#xff1a;模型在服务器上精调好了&#xff0c;指标也漂亮&#xff0c;可一旦要把算法塞进现场设备&#xff0c;事情就开始拧巴。尤其这两年边缘智能的需求明显变多&#xff0c;工业相机、巡检机器人、自助终端、安防闸机都不太想再依赖随…

作者头像 李华
网站建设 2026/9/5 6:50:14

ARM ABI规范源码审计:编译器后端ABI落地实践指南

做编译器后端时间久了&#xff0c;你会发现一个很矛盾的现象&#xff1a;明明每天都在和字节、寄存器打交道&#xff0c;但真正遇到“这个结构体为什么这样传参”“这个函数为什么栈上要留 16 字节空洞”这类问题时&#xff0c;大多数人不是去读一手规范&#xff0c;而是先看老…

作者头像 李华
网站建设 2026/9/5 6:49:24

KTH‑TIPS 材质 / 纹理 分类数据集介绍、下载

KTH‑TIPS 材质 / 纹理分类完整数据集下载目录 KTH‑TIPS 材质 / 纹理分类测数据集&#x1f6e0;️&#xff1a;数据集介绍、下载&#x1f4e5; | 目标分类&#xff5c;原始图像✅&#xff5c;分类标签✅ 文章目录 一、基础信息二、文件结构与标签三、KTH-TIPS 与 KTH-TIPS2&a…

作者头像 李华
网站建设 2026/9/5 6:44:17

Flux 3音频处理与手机金属乐现场录制完整指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华