RK3568+OpenHarmony多路显示移植实战:从设备树到异显
2026/9/14 19:51:25 网站建设 项目流程

开头先交代背景。我这段时间一直在搞一块基于 RK3568 的商显方案,主芯片选了瑞芯微 RK3568,系统基于开源鸿蒙 OpenHarmony 标准系统做整机定制。需求倒不复杂:一台设备要同时带一块 HDMI 大屏做广告/信息发布,一块 MIPI 触摸屏给操作员本地交互,后面还想通过 BT1120 往外送一路视频给后级处理设备。说白了,就是要把 RK3568 的多路显示能力在 OpenHarmony 上真正“跑起来、亮起来、各干各的”。这类需求在工业 HMI、自助终端、会议平板、充电桩、楼宇对讲上都特别常见。

这篇文章我会按实际移植顺序来写:先把 RK3568 显示子系统和 OpenHarmony 显示架构的对应关系理清楚,再讲内核 Kconfig 和设备树怎么配,然后到 OpenHarmony 侧的多屏适配,最后是联调和问题排查。全程会带上我实际操作的命令、改过的节点和踩过的坑,尽量做到你拿一台 RK3568 开发板就能照着复现。

这次移植适合谁看?主要是做 OpenHarmony 系统适配、内核/设备树开发的工程师,其次是做整机方案的软硬件工程师,他们需要知道多屏时序、带宽、引脚复用这些硬约束。如果你是刚接触 OpenHarmony 的嵌入式开发者,也可以从这里入手,因为显示子系统是上手操作系统移植最好的“骨架”之一。

1. 需求拆解:RK3568+OpenHarmony多路显示移植到底在移什么

1.1 先搞清楚RK3568能输出哪几路画面

RK3568 是瑞芯微一颗很典型的四核 A55 平台,它的显示控制器不是单个 VOP 出口,而是分成了两个独立的 Video Output Processor,在 Rockchip 内核驱动里通常叫 VOPB 和 VOPL。这两个 VOP 可以独立使能、独立配时序,各自挂不同的显示接口,这是“多路显示”的硬件基础。

RK3568 对外引出的显示接口大致有:

接口类型典型分辨率常见应用场景
HDMI 2.0最高 4K@60广告机、会议屏、电视机
eDP 1.3最高 2560x1600笔记本模组、一体机、高端 HMI
MIPI DSI(两路)每路常见 1080P@60车载屏、门禁、平板
LVDS1080P@60工控屏、电梯面板
BT1120/并行接口由外部转接芯片决定视频采集、工业相机、后级处理

这也就意味着,一块 RK3568 单芯片做“HDMI + MIPI DSI + BT1120”的三路输出,在硬件管脚上是完全可以支撑的。关键是系统侧要能同时枚举出三个 connector,并且在 OpenHarmony 的图形合成器里正确识别它们。

多路显示通常分“同显”和“异显”两种模式。同显就是把同一画面复制到多个屏幕,适合展览展示;异显是每个屏幕显示不同内容,适合“主屏放业务界面、副屏放操作面板”的整机设计方案。我在这个项目里要的是异显:HDMI 出去的是面向客户的大屏内容,MIPI 屏是本地运维操作界面,BT1120 那一路则是给后端图像处理设备的原始视频源。

1.2 从系统框架看移植的三个层级

在 OpenHarmony 上做显示移植,不是只改一个 dts 文件就完事。整个图形链路从底层到上层大致是:内核 DRM 驱动 -> HDF 显示适配层 -> RenderService/Composer 合成 -> 应用侧多屏接口。任何一个层级没对齐,表现出的症状都是“屏幕不亮”或者“亮但没内容”,但排查方向完全不同。

内核 DRM 层是最先要打通的。VOPB/VOPL 驱动要能初始化,HDMI、DSI、BT1120 这些 encoder/connector 要通过设备树被正确 probe,最终在 /dev/dri/card0 上挂出对应的 DRM device。这一层如果没做好,上层图片渲染得再好也送不出去。

HDF(Hardware Driver Foundation)显示适配层是 OpenHarmony 特有的。它相当于把内核 DRM 的能力封装成标准的 Display HDI 接口,供系统的 RenderService 调用。RK3568 在 OpenHarmony 生态里比较成熟,官方和一些开发板厂商已经把这层的通用驱动做好了,我们移植的重点通常是确认它读到了哪个 connector、把哪一路作为主屏。

最上层是 RenderService/Composer 的多屏管理。OpenHarmony 从 3.2 版本开始对多屏的支持逐渐完善,系统可以通过 DisplayManager 的接口枚举所有显示设备,设置主屏、副屏、扩展模式或镜像模式。做系统适配时,我们一般会在 init 或者开机脚本里把默认主屏顺序固定住,避免每次升级后 HDMI 和 MIPI 的显示顺序随机变化。

1.3 平台选择与版本基线

我这次用的基线是 OpenHarmony 4.1 Release 对应的 RK3568 标准系统代码,内核是 Linux 5.10。选这个版本的原因很直接:RK3568 在这条分支上被验证得最多,Rockchip 官方 SDK 里关于 display 的 dts 和 Kconfig 可以直接参考,踩坑资料也相对好找。

如果你刚拿到一块新的 RK3568 开发板,建议先别急着定制,先把官方镜像烧进去,确认单屏显示正常,再去动设备树做多屏。多屏移植的难度不是“加起来”,而是“排列组合”。HDMI 单独能亮、MIPI 单独能亮,不代表两个同时开就能各显各的,这和 VOP 分配、时钟、带宽、GPIO 复用都有关系。我后面会专门讲这些联动问题。

2. 环境准备:内核Kconfig与显示驱动依赖一个都不能漏

2.1 编译环境与代码基线确认

OpenHarmony 的编译环境和普通嵌入式 Linux 不太一样,它走的是一套基于 illumos/clang+GN 的构建系统。我习惯用一台 32GB 内存以上的 Ubuntu 22.04 服务器做全量编译,RK3568 标准系统首次编译大概需要半小时到一小时,和机器磁盘性能关系很大。

代码拉取可以按 OpenHarmony 官方 release 文档操作,用 repo 把 manifest 拿到手,重点确认三个仓库:vendor下的对应开发板工程、device/board下的板级配置、kernel/linux分支对应的内核版本。这三个仓库必须和同一个版本基线匹配,否则很容易出现“内核起来了但 HDF 驱动版本对不上”的问题。

一个很实用的验收习惯:先不改任何代码,直接编译烧录官方镜像,用 HDMI 接一台 1080P 显示器,确认系统能正常开机进桌面。如果这一步都起不来,说明你的环境/烧录流程还有问题,不要带着未知因素去改显示配置。

2.2 显示相关的内核Kconfig逐项核对

RK3568 显示移植最先踩的坑,往往不是设备树写错,而是内核 .config 里根本没编译对应的显示驱动。移植前,请先确认下面这些配置项是打开的:

配置项作用漏配的现象
CONFIG_DRM_ROCKCHIPRockchip DRM 主驱动/dev/dri 不出现
CONFIG_ROCKCHIP_DW_HDMIHDMI 控制器驱动HDMI 无输出、dmesg 无 HDMI 相关日志
CONFIG_ROCKCHIP_DW_MIPI_DSIMIPI DSI 控制器驱动DSI 屏黑屏、无 DSI 日志
CONFIG_ROCKCHIP_ANALOGIX_DPeDP 控制器驱动eDP 屏不亮
CONFIG_DRM_PANEL_SIMPLE通用 panel 支持dts 里的 simple-panel 节点无法 probe
CONFIG_BACKLIGHT_PWMPWM 背光驱动屏幕能出画面但背光不亮

修改方式有几种,最干净的是直接改内核 defconfig。以 RK3568 为例,路径通常在kernel/arch/arm64/configs/rockchip_linux_defconfig,加上对应配置后重新编译内核。改完编译后,务必在 ./out 内核产物里检查一遍.config,确认配置真正生效了,不要只看你改了 defconfig 就以为一定进了。

我见过一些同事漏了 CONFIG_BACKLIGHT_PWM,结果 HDMI 屏正常,MIPI 屏亮度一直为 0,黑漆漆一片。这个配置很容易被忽略,因为表现上像背光硬件坏了。

2.3 先跑通一组基线显示配置

在配置全开之后,我建议先做一次“最小显示验证”。不碰多屏,不改复杂 panel,先用默认 dts 把开发板原装的那块屏点亮。验证方法很简单:

  1. 烧录编译好的 boot 和系统镜像;
  2. hdc shell连接开发板;
  3. 执行ls /sys/class/drm/,确认能看到类似card0-HDMI-A-1card0-DSI-0的节点;
  4. 执行dmesg | grep -iE "drm|hdmi|dsi",看有没有报错和链路建立日志。

这一步通过后,再进入多屏设备树改造。不要试图一步到位把三路显示同时配好,那样出了问题根本不知道是哪个节点的问题。

3. 设备树配置:三路显示节点从零到亮屏

3.1 先理清RK3568显示硬件的拓扑关系

RK3568 的设备树里,显示相关的节点拓扑可以用一句话概括:display_subsystem是总目录,下面挂 VOPB/VOPL 两个显示控制器,每个 VOP 通过 port 与不同的 encoder 连接,encoder 再接对应的 connector。以官方 Linux SDK 为例,常见的节点有vopbvoplhdmidsi0dsi1edpbt1120,还有一大堆route_hdmiroute_dsi0这类路由节点。

很多移植失败的根因,是只开了&hdmi { status = "okay"; },却没开对应的&route_hdmi。这在 Rockchip 的驱动设计里是专门的控制开关:route_xxx节点决定某个显示接口和哪个 VOP 绑在一起,status = "okay"表示这个显示通路要被激活。二者缺一不可。

不同 SDK 版本之间,节点命名会有差异。比如有的版本是&hdmi_in_vp0,有的直接是&route_hdmi { connect = <&vp0_out_hdmi>; };。我建议以你手头 SDK 里arch/arm64/boot/dts/rockchip/下现成的 evb dts 文件为参照,不要盲目照抄社区里别的版本的写法。

3.2 HDMI输出节点配置参考

下面这段是我在这台设备上使用的 HDMI 相关节点配置,基于常见 RK3568 SDK 整理,节点名以你实际 SDK 为准:

&hdmi { status = "okay"; }; &hdmi_in_vp0 { status = "okay"; }; &route_hdmi { status = "okay"; connect = <&vp0_out_hdmi>; }; &hdmi_sound { status = "okay"; };

这段配置的含义是:把 HDMI 控制器挂到 VP0 上,并激活 HDMI 路由。hdmi_sound开不开取决于你有没有用 HDMI 音频,我用到的场景不需要音频,但保留也没问题。

如果 HDMI 插上后分辨率不对,或者始终以低分辨率输出,常见原因是显示器的 EDID 读取失败。可以在内核日志里看drm相关输出,确认有没有EDID读取记录。也可以在 dts 里给 HDMI 节点加上固定的display-timings或者允许驱动使用video=参数强制指定分辨率,不过这是我后面推荐的“最后手段”,正常情况应该优先让 EDID 自动识别。

3.3 MIPI DSI屏的配置与背光控制

MIPI DSI 屏的配置比 HDMI 复杂,因为面板的时序、初始化序列、背光、复位 GPIO 全都要在设备树里描述清楚。我的 MIPI 屏是一块常见的 1080P IPS 屏,驱动 IC 本身不需要复杂的初始化序列,所以我直接用 simple-panel 节点加 display-timings:

/ { backlight: backlight { compatible = "pwm-backlight"; pwms = <&pwm4 0 25000 0>; brightness-levels = <0 20 40 80 120 160 200 255>; default-brightness-level = <4>; power-supply = <&vcc3v3_lcd0_n>; status = "okay"; }; panel: panel { compatible = "simple-panel"; backlight = <&backlight>; enable-gpios = <&gpio0 RK_PC6 GPIO_ACTIVE_HIGH>; display-timings { native-mode = <&timing0>; timing0: timing0 { clock-frequency = <148500000>; hactive = <1920>; hback-porch = <148>; hfront-porch = <88>; hsync-len = <44>; vactive = <1080>; vback-porch = <36>; vfront-porch = <4>; vsync-len = <5>; hsync-active = <0>; vsync-active = <0>; de-active = <0>; pixelclk-active = <0>; }; }; status = "okay"; }; }; &dsi0 { status = "okay"; panel@0 { compatible = "simple-panel"; reg = <0>; backlight = <&backlight>; }; ports { port@1 { reg = <1>; dsi0_out: endpoint { remote-endpoint = <&vp0_out_dsi0>; }; }; }; };

这里提两个容易出错的细节。第一,pwm425000是 PWM 周期,单位是纳秒,对应 40kHz。背光频率太低会听到电流声,太高又可能对触摸屏产生干扰,我用 20kHz 到 40kHz 之间比较稳,具体看你屏厂推荐值。第二,enable-gpios这个复位/使能引脚的时序非常重要,如果驱动 GPIO 被复用成了别的功能,屏幕就会出现“初始化了但一直黑”的情况。

VOP 的分配这里也要注意:如果 HDMI 已经占了 VP0,DSI 那一路建议挂到 VP1,否则两路共用一个 VOP,带宽和扫描时序容易互相干扰。不同内核版本的 route 写法不一样,我用的是&vp0_out_dsi0这种 endpoint 连接方式,你那边可能是&dsi0_in_vp1之类的节点,原理是一样的。

3.4 eDP屏与BT1120的补充思路

eDP 屏的配置和 DSI 很像,也需要 panel 节点、背光节点、eDP 控制器节点以及路由节点。区别在于 eDP 有 Link Rate、Lane Count 这些参数,以及有时需要用edp-panel的 compatible 让驱动去读 eDP 屏的 DPCD 信息来自动协商链路。如果你手持的是一块 eDP 笔记本屏模组,不知道详细参数,优先走自动协商,不要死填 timing。

BT1120 这路比较特殊。它不是接常规 LCD 的,而是把 VOP 输出的数字视频信号以 BT.1120 并行格式送出去,给外部视频处理芯片或采集设备用。配置思路同样是三件套:控制器节点、输入路由节点、路由节点状态。但实际调通后你会发现,BT1120 本身不含像素时钟恢复,对后端设备的同步要求更高,需要和后端联调水平/垂直同步信号。

我没有在这台设备的 BT1120 上做复杂的内容合成,只是把其中一路 VOP 的画面直接送出去。如果你也想这么干,务必确认后端设备要求的色彩空间和时序,BT1120 通常是 YUV 信号,不是普通 LCD 用的 RGB,转换没做对的话画面会整体偏色或者绿屏。

4. OpenHarmony侧适配:主屏顺序与多屏策略落地

4.1 HDF显示设备注册与Composer识别顺序

设备树配置好、内核能枚举出多个 connector 之后,OpenHarmony 的 HDF 显示驱动会在系统起来的时候扫描 DRM device,创建对应的显示设备。多数 RK3568 的 OpenHarmony 移植包已经带好了这块逻辑,但你会遇到一个新问题:到底哪块屏是主屏?

主屏顺序直接决定了开机 Logo 显示在哪、RenderService 默认把桌面绘制到哪。它不是一个运行时的“自动行为”,而是由 HDF 驱动扫描 connector 的顺序决定的,扫描顺序又和 dts 中节点的注册顺序、内核枚举顺序有关。最可靠的做法是在系统侧通过配置文件固定下来。

具体做法看你的 vendor 包怎么组织。有些 RK3568 工程里,显示相关的 HDF 配置在/vendor/etc/display_config/下,里面会有类似display_device_config的文件,可以指定屏幕尺寸、刷新率、方向;有些则是在 init 脚本里通过属性控制。我建议先跑一条命令看当前系统识别的显示设备:

hdc shell hidumper -ls

在列出的服务里找到显示相关服务,再 dump 具体信息。不同版本服务名不一样,所以我没法给你一个固定的命令参数。你只要确认“系统确实看到了两个屏幕”,这一步就算完成了。

4.2 主屏、副屏、异显与同显的落地方式

模式的选择要看你的产品定义。我这个项目里,HDMI 是“对外展示面”,MIPI 是“本地操作面”,二者显示内容完全不同,属于异显。

OpenHarmony 系统级有没有提供“直接配置异显”的命令行开关?说实话,这个能力在不同版本里成熟度差异很大,4.0 之前主要靠应用层代码调多屏接口来实现,4.1 之后系统能力完善了很多,但也还没有一个像 Androidwm set-user-rotation那样通用统一的命令。所以我会分两条腿走路:

一是在系统底层的 init 配置里确认两个显示设备都能被正常枚举和打开,保证整机不会因为“副屏没准备好”导致主界面卡顿或者渲染异常;

二是在业务应用层通过 DisplayManager 接口动态创建虚拟屏或者把不同 UIAbility 投到不同屏幕。对系统移植工程师而言,你要做的最重要的事情就是保证底层把两块屏都“亮出来、显示正常”,上层的业务分流是应用工程师的事。

如果你的产品只需要“同显”,那简单很多,系统通常默认支持镜像模式,你只要在底层保证两个屏都能出画面即可。异显则要关注两个屏幕的分辨率和刷新率差异,如果一块 4K 一块 800x480,合成器把内容从 4K 缩放到小屏上,容易出现锯齿和布局错乱。

4.3 开机亮度、屏幕方向与触摸校准

多屏设备还有一个绕不开的细节:副屏的方向和触摸坐标。设备树里 VOP 输出的画面顺序和面板物理安装方向如果不一致,就会出现“开机画面横的、触摸坐标竖的”的诡异问题。

方向修正一般在 HDF 显示配置里做,有些 RK3568 工程支持在display_device_config里配置旋转角度。触摸坐标的映射则复杂一些,因为触摸 IC 驱动报出来的是原始坐标,指示的是触摸面板的物理方向,系统在不做任何处理时,默认认为触摸方向和显示方向一致。你把屏幕旋转了 90 度,但触摸没跟着转,就会出现点 A 出 B 的错乱。

这种情况我会在 HDF 或内核 input 层面做坐标变换。注意,触摸和显示是两条独立的链路,一定分别验证:先用系统的触屏测试页面画线,看笔画是否跟手、方向是否正确,再调整坐标映射参数。我见过太多工程师改了一下午显示方向,最后发现问题根本在触摸方向没同步。

5. 联调实战与排查:黑屏、花屏、顺序错乱一次讲透

5.1 多路显示从设备树到开机亮屏的完整联调步骤

三路显示都配好后,我按下面的顺序做了联调,每步都有明确的验证手段,强烈建议你也按这个顺序来:

  1. 确认设备树编译通过,烧录后dmesg | grep -iE "drm|hdmi|dsi|edp"没有任何 fatal error;
  2. 查看/sys/class/drm/,确认 HDMI、DSI 等 connector 节点都枚举出来,statusconnected
  3. 先断开 MIPI 屏,只留 HDMI,确认 HDMI 单独能出画面且分辨率正确;
  4. 再断开 HDMI,只留 MIPI 屏,确认 MIPI 能起来,背光亮度正常,触摸可用;
  5. 双屏同时接上,观察主屏是哪一个,确认开机 Logo 和桌面在预定的主屏上;
  6. 最后接 BT1120 后端设备,确认第三路视频信号有稳定的同步信号和画面帧。

第 5 步最容易出问题。两个屏都接上后,如果主屏不是你想要的那块,先别急着改代码,用cat /sys/class/drm/card0-HDMI-A-1/status这类命令确认每个 connector 的连接状态,再看内核日志里 VOP 绑定的打印顺序。排查思路是“先确认设备树绑定的 VOP 对不对,再调整 HDF 或 init 侧的主屏优先级”。

5.2 高频问题速查表

下面这张表是我这次移植和以往给 RK 平台做显示适配时,总结出来的最高频问题集合,每一行都对应一个真实踩过的坑:

现象可能原因排查命令/手段处理建议
开机后所有屏黑屏内核 .config 缺少 DRM/显示驱动ls /dev/dri核对 Kconfig,重编内核
HDMI 有信号但分辨率很低EDID 读取异常dmesg 搜 edid检查 HDMI 线材/座子焊接,或用 video= 强制分辨率
MIPI 屏黑但背光亮panel 初始化时序不对dmesg 搜 dsi核对 enable/reset GPIO 时序,确认 init 序列
屏亮但显示花屏时序参数不对或像素时钟误差对比屏规格书 timing核对 hactive/hback-porch 等参数
双屏同时开只有一个亮VOP 绑定冲突或带宽不够dmesg 搜 vop/dclk检查 route 是否重复指向同一 VOP
副屏显示主屏内容,异显失败系统层未做多屏模式设置应用层查 DisplayManager应用侧调用多屏接口,或确认系统版本支持异显
屏幕方向不对面板安装方向与 VOP 输出不一致旋转配置测试在 HDF 显示配置里做旋转
触摸坐标与画面方向不一致触摸驱动未做坐标变换触屏画线测试调整 input 坐标映射
屏幕偶尔闪一下PWM 背光频率偏低或干扰观察闪烁频率调整背光 PWM 频率

其中“双屏同时开只有一个亮”是我在所有 RK 多屏项目上遇到最多的问题。不只是 RK3568,RK3588、RK3399 上同样存在。多数情况是route_xxx节点的connect属性写重复了,两个接口都指向了同一个 VOP 的同一个 port,导致另一个 VOP 没有可用的数据源。你可以用 dmesg 搜索vop相关的 bind 日志,确认每个 VOP 到底绑了哪个显示接口。

5.3 容易忽略的硬件与资源冲突

设备树改到“看起来全对”,但屏幕就是不亮,这类问题十有八九出在硬件资源冲突上。RK3568 的不少引脚是复用的,一个 GPIO 可能既支持 I2C 又支持 PWM 又支持 GPIO 中断,一旦某个外设驱动先 claim 了这个引脚,显示链路再去申请同一个引脚就会失败。

比如,我这次调试时发现 BT1120 的某个数据引脚和板子上一个 LED 的 GPIO 冲突,导致 BT1120 一直初始化失败。这类问题查起来特别费时间,因为软件日志不会直接告诉你“引脚被占了”,只会显示一个模棱两可的 timeout。排查时试着把不相关的外设节点先 disable 一批,逐步二分定位。

另外,多路显示对电源的瞬态功耗要求更高。两块屏同时点亮的时候,瞬间电流可能比单屏大很多,如果板子的 3.3V/5V 电源余量不足,会出现“单屏没问题、双屏总有一颗不亮”的诡异现象。遇到这种问题先量电压,不要一上来就怀疑软件。

最后再提醒一点,多路显示联调时,确认每块屏的复位 GPIO 要有足够的延时。我的经验是上电时序硬性要求:先供屏电源,再拉复位,再发初始化序列,最后打开背光。顺序反了很伤屏,也会导致随机黑屏。

写在最后

多路显示移植这件事,本质上是在硬件能力、内核驱动、系统框架三个层面之间找平衡。RK3568 的硬件能力非常强,OpenHarmony 的显示架构也足够现代,双方接驳的难点反而不是某一项技术的“深水区”,而是那些细碎的节点名、配置项、时序参数、引脚复用问题。你只要按“先单屏、再多屏、再异显”的顺序一步步来,大多数问题都能在日志里找到答案。

我个人的一个体会是:在做系统移植时,别急着把全部功能一次性打开,先把一条最小路径跑通,再逐步叠加。以显示为例,就是先让一块屏完美点亮,然后增加第二块、第三块。每增加一路,只改一个变量,验证一个变量,这样就算踩坑也能迅速定位。如果你在 RK3568 的 OpenHarmony 多屏移植上也遇到类似问题,欢迎按我上面整理的排查思路去试,多数情况下问题都能锁定在设备树和资源冲突这两个方向。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询