1. 项目概述为什么要在RK3568上折腾双屏同显最近在做一个基于瑞芯微RK3568的工控项目客户要求在同一个操作界面上一块屏幕给操作员看另一块屏幕给现场的工程师或者质检员同步查看。说白了就是需要“双屏同显”。这个需求在数字标牌、工业控制台、互动展示柜里其实挺常见的但真动手去配才发现从硬件连接到软件配置中间有不少细节需要捋清楚。RK3568这颗芯片本身支持多路显示输出硬件底子没问题但怎么把系统配置成我们想要的样子就是另一回事了。所谓“双屏同显”专业点叫“克隆显示”Clone Display或“镜像显示”Mirror Display指的是两个或多个物理显示器上呈现完全相同的图像内容。这和“扩展显示”Extended Display是两码事扩展显示是把桌面空间拉大每个屏幕显示不同内容。同显的核心价值在于信息同步和展示冗余比如在零售店收银台和顾客屏显示同样的金额在工厂控制室大屏和现场工位屏同步展示生产状态确保信息传递零误差。选择RK3568来实现这个功能看中的就是它集成的强大显示子系统。它内置了三个独立的视频输出端口Video Port简称VP理论上能同时驱动三块屏幕。我们这次的目标就是利用其中两个VP让两块屏幕亮起来并且显示一模一样的东西。整个过程会涉及到设备树DTS的修改、内核的配置与编译以及一些显示参数的调试。下面我就把这次从零开始配置RK3568双屏同显的完整过程、踩过的坑和最终验证有效的方案详细拆解一遍。2. 核心思路与硬件方案选型在动手改代码之前得先把硬件连接和软件层面的实现路径想明白。RK3568的多显示能力核心在于其VOPVideo Output Processor模块和后端的Video Port。2.1 RK3568显示架构浅析你可以把VOP想象成一个功能强大的“视频调度中心”。它的工作是从内存里拿到要显示的图像数据帧缓冲区然后进行一系列处理比如叠加图层、色彩空间转换、缩放等最后把处理好的视频流送出去。关键点在于这个“调度中心”后面接了多个“出站通道”这就是Video Port。RK3568有三个VPVP0, VP1, VP2。每个VP都是独立的可以连接不同的物理显示接口比如HDMI、LVDS、MIPI-DSI、eDP甚至RGB接口。对于“同显”在软件上有两种主流实现思路帧缓冲复制应用程序向一个帧缓冲区fb0写入数据驱动层自动将这份数据复制到另一个帧缓冲区fb1分别由两个VP输出。这种方式对应用透明但可能增加内存带宽和功耗。单一帧缓冲多VP输出更高效的方式是让两个VP直接指向内存中同一块帧缓冲区。两个VP同步地从同一块内存区域读取数据并输出。RK3568的驱动通常支持这种模式也是我们本次采用的目标方案。2.2 硬件连接方案确定你的开发板具体有哪些显示接口决定了你的双屏组合。常见的RK3568开发板比如迅为、Firefly的型号通常会引出多个接口。你需要查阅你的开发板原理图或用户手册确认哪两个接口是连接到不同的VP上的。注意非常重要的一点是要实现双屏输出两块屏幕必须连接到不同的Video Port上。你不能把两个HDMI显示器都插在同一个VP衍生的两个HDMI口上如果板子有多个HDMI的话因为它们底层可能共享同一个VP无法独立驱动。务必确认你的硬件连接对应不同的VP。举个例子假设你的板子有如下接口HDMI0通常固定在VP0或VP1。LVDS或MIPI-DSI通常占用另一个VP。eDP可能占用第三个VP。那么一个典型的双屏同显组合就是HDMI LVDS或者HDMI MIPI。你需要根据手头实际的屏幕类型HDMI显示器、LVDS屏、MIPI屏来决定。我这次使用的环境是一块普通的1080P HDMI显示器和一块1024x600分辨率的LVDS屏。2.3 软件准备内核与设备树RK3568的显示驱动主要在内核中配置信息则集中在设备树Device Tree文件里。我们的核心工作就是修改设备树告诉内核“请启用VP0和VP1举例分别驱动HDMI和LVDS并且让它们显示同样的内容。”你需要准备RK3568的Linux SDK从芯片原厂或开发板供应商处获取里面包含了内核源码、编译工具链等。确保版本相对较新对显示驱动支持完善。编译环境一个Linux开发机Ubuntu 20.04/22.04比较常见安装好必要的编译工具。串口调试工具用于查看内核启动日志这是排查问题的生命线。3. 设备树DTS配置详解与修改设备树是描述硬件拓扑和配置的文本文件内核通过它来知道板子上有什么设备、怎么工作。RK3568的多屏配置主要修改两个地方一是选择启用哪些屏幕的“宏定义”文件二是具体屏幕的参数文件。3.1 定位关键设备树文件在你的内核源码目录下通常是kernel/arch/arm64/boot/dts/rockchip/找到你的板级设备树文件例如rk3568-evb.dts或rk3568-topeet.dts。这个文件会包含很多#include语句引用其他.dtsi文件。我们需要关注的是与屏幕选择相关的文件。根据网络资料和常见方案通常会有一个类似topeet_screen_choose.dtsi或rk3568-lcd.dtsi的文件。这个文件的作用就是用“宏定义”其实是设备树的条件编译来控制启用哪块屏幕。我们以迅为的方案为例找到这个文件内容结构通常如下// 示例topeet_screen_choose.dtsi / { // HDMI 屏幕使能宏 #ifdef HDMI_ENABLE #include rk3568-hdmi.dtsi #endif // LVDS 屏幕使能宏 #ifdef LVDS_ENABLE #include rk3568-lvds.dtsi #endif // MIPI 屏幕使能宏 #ifdef MIPI_ENABLE #include rk3568-mipi.dtsi #endif // EDP 屏幕使能宏 #ifdef EDP_ENABLE #include rk3568-edp.dtsi #endif };3.2 启用双屏宏定义我们的目标是同时启用HDMI和LVDS。那么就需要定义HDMI_ENABLE和LVDS_ENABLE这两个宏。关键点来了你必须确保它们分配到了不同的Video Port怎么知道分配给了哪个VP你需要打开对应的rk3568-hdmi.dtsi和rk3568-lvds.dtsi文件查看。在里面搜索vop或ports关键字。你会看到类似这样的配置// 在 hdmi.dtsi 中 hdmi { status okay; }; hdmi_in_vp0 { // 注意这里hdmi 输入源来自 VP0 status okay; }; hdmi_in_vp1 { status disabled; }; hdmi_sound { status okay; };// 在 lvds.dtsi 中 lvds { status okay; }; lvds_in_vp1 { // 注意这里lvds 输入源来自 VP1 status okay; }; lvds_in_vp0 { status disabled; };上面这段配置清晰地表明HDMI使用VP0LVDS使用VP1。这符合我们的要求不同VP。如果发现你想用的两个屏幕配置在了同一个VP上比如都配置成了xxx_in_vp0那么同显将无法实现你必须修改其中一个将其分配到空闲的VP如VP1或VP2。修改时需谨慎要结合硬件连接原理图确认该物理接口是否真的连接到那个VP。现在我们修改屏幕选择文件。通常不是在原文件上改而是在板级设备树文件如rk3568-evb.dts的开头或通过编译系统的配置来定义这些宏。一个直接的方法是在板级.dts文件的最前面添加宏定义// 在 rk3568-mybroad.dts 文件顶部include语句之前 #define HDMI_ENABLE #define LVDS_ENABLE //#define MIPI_ENABLE // 注释掉不需要的屏幕3.3 配置同显模式与显示参数仅仅启用两个屏幕默认可能是“扩展模式”。我们需要配置为“同显模式”。这通常在一个系统级的显示配置文件里也可能是通过内核启动参数cmdline或特定的驱动参数设置。方法一通过内核驱动参数常见于Rockchip平台在设备树中找到VOP视频输出处理器的节点或者查找是否有全局的显示相关参数。Rockchip内核通常通过drm驱动的video命令行参数来配置。你可以修改bootloader如U-Boot的启动参数或者在内核的设备树中设置chosen节点的bootargs。在设备树中添加或修改/ { chosen { bootargs ...原有参数... drm_kms_helper.videoHDMI-A-1,LVDS-1:clone; }; };这里的HDMI-A-1和LVDS-1是你的显示输出接口名称启动后可以在/sys/class/drm/下看到。clone关键字就是指示克隆/同显。不过参数格式可能因内核版本而异这需要你查阅内核文档或驱动源码。方法二通过修改VOP绑定更底层的方法更直接的方式是强制让两个VP输出同样的数据。这可以通过修改设备树让两个VP的输入源vop_out指向同一个端点或者配置显示管道来实现。这需要对RK3568的显示架构有更深理解一般板厂提供的SDK里可能会有预设的同显配置片段。你可以搜索SDK中是否有dual-display或mirror相关的.dtsi文件。方法三启动后通过软件配置灵活但非永久如果上述方法复杂可以先将双屏点亮即使是扩展模式然后在系统启动后使用命令行工具配置同显。例如使用xrandrX Window系统或westonWayland合成器的命令。但这要求你的文件系统已经包含了这些工具和相应的桌面环境。实操心得对于嵌入式Linux尤其是无桌面的系统方法一内核参数是最干净、最彻底的方案。它在内核初始化显示子系统时就完成配置不依赖用户态服务。我建议优先尝试这个方法。你可以先不设clone参数确保两块屏都能独立点亮并显示内容可能是控制台滚屏信息然后再添加克隆参数。3.4 调整屏幕分辨率与时序两块屏幕的分辨率、刷新率可能不同。在同显模式下输出分辨率通常会以第一个被初始化或指定的主屏幕为准。另一块屏幕会接受这个分辨率信号如果它不支持可能会黑屏或显示异常。因此你需要在对应的屏幕设备树文件如rk3568-lvds.dtsi中检查并确认其display-timings节点配置是否正确。特别是LVDS屏幕它的时序参数像素时钟、前后肩、同步脉冲宽度需要严格按照屏幕规格书来填写。HDMI通常是自适应的问题不大。例如在LVDS的设备树节点中lvds { status okay; ports { port1 { reg 1; lvds_out_panel: endpoint { remote-endpoint panel_in_lvds; }; }; }; }; panel: panel { compatible simple-panel; status okay; // 关键显示时序 display-timings { native-mode timing0; timing0: timing0 { clock-frequency 51200000; // 像素时钟单位Hz hactive 1024; // 有效水平像素 vactive 600; // 有效垂直像素 hfront-porch 160; // 水平前肩 hsync-len 20; // 水平同步脉冲宽度 hback-porch 140; // 水平后肩 vfront-porch 12; // 垂直前肩 vsync-len 3; // 垂直同步脉冲宽度 vback-porch 20; // 垂直后肩 hsync-active 0; // 同步极性 vsync-active 0; de-active 1; pixelclk-active 0; }; }; };务必根据你的实际屏幕手册修改这些值填错了轻则花屏重则烧坏屏幕背光驱动虽然概率低。4. 内核编译与系统烧录配置好设备树后下一步就是编译内核并打包系统镜像。4.1 编译内核与设备树进入你的内核源码目录。指定编译工具链确保环境变量已设置好例如export PATH/path/to/your/gcc-aarch64-linux-gnu/bin:$PATH export CROSS_COMPILEaarch64-linux-gnu- export ARCHarm64加载默认配置通常使用板级配置。make rockchip_linux_defconfig # 或 make rk3568-evb-defconfig具体看你的SDK可选进行内核图形配置如果你不确定显示驱动是否选好可以检查一下。make menuconfig确保以下选项被启用通常默认已启用Device Drivers - Graphics support - Direct Rendering Manager (DRM) - DRM Support for Rockchip对应的显示接口驱动如Rockchip HDMIRockchip LVDSRockchip MIPI DSI等。编译内核与设备树make -j$(nproc) Image dtbs编译完成后在arch/arm64/boot/下得到Image内核镜像在arch/arm64/boot/dts/rockchip/下得到rk3568-your-board.dtb设备树二进制文件。4.2 打包与烧录不同的SDK和bootloader打包方式不同。常见的是使用Rockchip提供的rkbin工具和mkimage脚本将内核、设备树、根文件系统等打包成统一的固件如update.img。或者如果你的系统是使用U-Boot引导并且已经有一个可运行的SD卡或eMMC系统你可以只更新内核和设备树将编译好的Image重命名为kernel.img根据你的U-Boot预期文件名。将编译好的rk3568-your-board.dtb放到boot分区的指定位置。将这两个文件拷贝到开发板存储设备的对应分区。更通用的方法是使用SDK提供的打包脚本例如./build.sh或mkupdate.sh生成完整的固件包然后通过Rockchip的AndroidToolWindows或upgrade_toolLinux工具烧录到开发板。5. 上电调试与问题排查实录烧录完成连接好HDMI和LVDS屏幕上电启动。这时最紧张的时刻来了大概率不会一次成功。串口终端是你的眼睛。5.1 查看内核启动日志通过串口工具如minicom,picocom,PuTTY连接开发板查看启动信息。重点关注以下几点VOP和VP初始化搜索日志中的vopvp0,vp1,hdmi,lvds等关键字。成功迹象看到类似rockchip-drm display-subsystem: vp0: HDMI-A-1 connected和vp1: LVDS-1 connected的日志并且没有failed、error或timeout。失败迹象某个接口显示disabled、failed to bind或cannot find...。DRMDirect Rendering Manager初始化DRM是Linux内核的图形驱动框架。看到rockchip-drm display-subsystem bound之类的成功绑定信息是好的。屏幕时序与EDID对于HDMI会打印[drm] Supports和[drm] Driver信息显示检测到的分辨率。对于LVDS会打印你设备树里配置的时序参数核对是否正确。5.2 常见问题与解决方案下面是我在调试过程中遇到的一些典型问题及解决方法整理成了速查表问题现象可能原因排查步骤与解决方案只有一块屏幕亮另一块黑屏1. 设备树中另一块屏的status未设为“okay”。2. 两个屏幕配置到了同一个VP。3. 屏幕时序参数错误。4. 屏幕背光未开启针对LVDS/MIPI屏。1. 检查设备树确认两个屏幕节点status “okay”。2. 检查xxx_in_vpX节点确保是vp0和vp1或vp2的不同组合。3. 仔细核对LVDS屏幕规格书修正display-timings里的所有参数特别是clock-frequency。4. 检查背光控制GPIO配置。在设备树中LVDS屏节点下可能有enable-gpios或backlight子节点确保其指向正确的GPIO控制器和引脚并且状态为启用。屏幕花屏、闪烁、撕裂1. 时序参数错误尤其是像素时钟clock-frequency。2. 内存带宽不足或显存分配问题。3. 屏幕物理连接不良LVDS线松动。1.这是最常见原因。使用屏幕厂商提供的精确时序参数。可以尝试微调hfront-porch,hsync-len,hback-porch等值。2. 尝试在内核启动参数中增加cma连续内存分配器的大小例如cma128M。确保系统有足够连续内存供帧缓冲区使用。3. 重新插拔并固定LVDS排线。系统启动后两块屏显示不同内容扩展模式未成功配置同显克隆模式。1. 确认内核启动参数是否包含drm_kms_helper.videoxxx:clone配置。2. 如果没有在U-Boot命令行或设备树chosen节点中添加。3. 如果内核参数不生效尝试在系统启动后使用cat /sys/class/drm/card0-DP-1/status等命令查看连接状态并使用echo clone /sys/class/drm/card0-DP-1/desired_mode路径和命令可能不同进行动态设置。这需要内核和驱动支持sysfs接口。内核启动卡住或提示显示相关错误后停止1. 设备树语法错误。2. 驱动编译进内核时冲突。3. 关键资源如时钟、电源配置错误。1. 使用dtc设备树编译器检查设备树文件语法dtc -I dts -O dtb -o /dev/null your.dts。2. 尝试将显示驱动编译为模块m而不是内置y看看能否绕过初始化顺序问题。3. 检查设备树中VOP、HDMI、LVDS节点的时钟clocks和电源supplies引用是否正确这些节点的父节点如i2c控制器是否启用。HDMI屏幕无信号但LVDS正常1. HDMI的PHY物理层电源或时钟未正确配置。2. HDMI的DDC显示数据通道用于读取EDIDI2C通信失败。3. 热插拔检测HPD信号有问题。1. 检查设备树中hdmi节点的avdd-0v9,avdd-1v8等电源 regulator 是否被正确引用和启用。2. 查看启动日志中是否有ddc i2c transfer error。检查连接HDMI的I2C总线是否正常。3. 测量HDMI接口的HPD引脚电压或在设备树中尝试强制使能HPD不推荐长期使用。5.3 验证同显成功当两块屏幕都点亮后如何确认是同显而非扩展视觉验证在屏幕上运行一个简单的图形应用比如用fbv显示一张图片或者运行一个带界面的Qt程序观察两块屏幕上的内容是否完全同步包括鼠标指针如果有的话。系统信息验证在终端输入cat /sys/class/drm/*/status查看所有显示接口的状态。输入cat /sys/kernel/debug/dri/0/state需要内核开启DEBUG_FS可以查看更详细的DRM状态信息包括每个crtc对应VP驱动的模式。帧缓冲区验证使用ls -l /dev/fb*查看有几个帧缓冲设备。在标准的同显配置下你可能只看到一个fb0因为两个VP共享同一个缓冲。如果看到fb0和fb1则可能是扩展模式或复制缓冲模式。6. 性能考量与进阶优化双屏同显功能实现后还需要关注其稳定性和性能。6.1 内存带宽与CMA配置同时驱动两块屏幕尤其是高分辨率屏幕如双1080P对内存带宽有一定压力。帧缓冲区需要存储在连续的内存中。RK3568的Linux内核通常使用CMA来分配连续内存。如果遇到显示卡顿或内存分配失败可以尝试增大CMA区域。修改内核启动参数在bootargs中添加或修改cma参数例如cma256M这会将CMA区域设置为256MB。具体大小需要根据你的屏幕分辨率宽x高x像素字节数x2估算双缓冲和系统其他需求来定不宜过大而挤占系统内存。6.2 功耗管理两块屏幕同时工作功耗会显著增加。在电池供电的设备上需要特别注意。动态调频确保CPU和GPU的频率调节策略cpufreq, devfreq是激活的在负载低时能降频。屏幕背光控制如果屏幕支持PWM调光在不需要高亮度时通过软件调低背光可以省很多电。可以通过sysfs接口如/sys/class/backlight/控制背光亮度。VP时钟门控在驱动层面当屏幕显示静态内容时理论上可以降低VP的时钟频率以省电但这需要驱动支持通常不是默认行为。6.3 应用层适配对于你自己编写的应用程序在双屏同显环境下基本无需特殊处理因为应用只向一个逻辑显示区域主屏幕绘制内容。但需要注意全屏处理确保应用的全屏窗口覆盖的是正确的显示区域。鼠标指针如果运行了桌面环境确保鼠标指针能在两个屏幕间同步显示克隆模式下应该自动同步。多显示信息查询如果你的应用需要查询显示设备信息使用如libdrm等库时可能会枚举到多个显示器逻辑上需要能正确处理。配置RK3568双屏同显是一个从硬件认识到软件配置的完整链路。核心在于理解Video Port的概念并正确地在设备树中分配和启用它们。修改设备树是重中之重每一个参数都可能影响最终显示效果。调试过程离不开串口日志耐心分析日志中的每一行错误信息是解决问题的关键。当两块屏幕终于同步亮起显示着相同的内容时那种成就感是对之前所有折腾的最佳回报。这个配置一旦稳定下来就可以作为你项目的基础镜像为各种需要双屏展示的场景提供可靠支持。