●从零理解 DSI 屏幕撕裂:一条数据流水线的故事
1. 整个系统在干什么你的板子在做一件事把 HDMI 输入的画面缩小后显示在一块 MIPI DSI 小屏幕上。数据流是这样的HDMI 源笔记本 → rk628 芯片 → DSI 面板720×720 缩小到 360×36041.877 MHz 360×360 11 MHzrk628 内部有一个缩放器Scaler负责把 720×720 的帧缩小成 360×360。缩放器输入侧跑 HDMI时钟41.877MHz输出侧跑 DSI 时钟11MHz——这就是一切撕裂的根源。---2. 为什么要缩放为什么时钟不一样HDMI 源输出的是 720×72060fps像素时钟 41.877MHz。你的面板只有 360×360 像素它的datasheet 规定像素时钟必须是 11MHz。如果让面板直接接收 720×720的信号它根本显示不了——分辨率不匹配时钟也不匹配。所以缩放器必须介入用 41.877MHz 的速度读入一帧用 11MHz的速度缩放后写出到面板。两个速度不一样缩放器内部有一个叫 FIFO先入先出缓冲区的东西来缓冲数据。读写比值是 41.877/11 ≈ 3.8:1意味着缩放器每 1 个像素写出就要读入约 3.8 个像素其中2.8 个被缩小算法丢弃了因为 720→360 是 2:1 缩小。---3. 撕裂是怎么发生的直观类比想象两台跑步机并排放着左边跑 41.877 km/h右边跑 11km/h。你在左边的跑步机上画一幅画画完传给右边继续画。左边的人画得快右边的人画得慢。如果两边没有任何同步信号右边的人可能在你画到一半就开始往面板上发表——结果就是面板显示的画面┌──────────────────┐│ ← 第 N 帧内容 │ ← 上半部分正常│ │├──────────────────┤ ← 这就是撕裂线│ ← 第 N1 帧内容 │ ← 下半部分是下一帧└──────────────────┘在 DSI video mode 下缩放器不需要等面板说我准备好了——它按固定的 60fps节奏持续往面板灌数据。如果缩放器内部的 FIFO 在某一个瞬间恰好读完旧数据、塞入新数据的时候和面板的扫描线重合屏幕上就会出现新旧帧各占一半的撕裂。轻微撕裂是因为 FIFO 大小足够深缓存了若干行像素新旧数据切换的时机绝大多数时候落在消隐区面板不显示的区域偶尔被扫描线抓到。---4. Command Mode vs Video Mode这是 DSI 协议的两种传输模式Video Mode视频模式- DSI 控制器像 HDMI一样按固定时序hfront/hsync/hback/vfront/vsync/vback不停地发像素- 面板被动接收不受面板内部控制- 优点简单不需要额外同步信号- 缺点不理会面板内部刷新状态容易撕裂Command Mode指令模式- DSI 控制器只有收到 write_memory_start 指令时才发一帧数据- 面板刷完一帧后通过 TETearing Effect引脚发信号可以发下一帧了- 优点永不撕裂严格同步- 缺点需要 TE 引脚硬件连接你一开始的 dsi,video-mode 走的是 video mode。去掉之后走 command mode。但你没有 TE引脚——面板虽然内部配置了 TE但 rk628 芯片收不到——所以 command mode变成了没有同步信号的盲发模式撕裂仍然存在只是位置变了。---5. Blanking Porch 到底在干什么每显示一帧面板都会经历这样的过程← visible area → ← 消隐 →┌──────────────────────────────┐Scan ──→│ 显示区 │ HSync │←── 一行结束回扫└──────────────────────────────┘hdisplay hfp/hsync/hbp← visible area → ← 消隐 →┌──────────────────────────────┐Frame──→│ 显示区 │ VSync │←── 一帧结束回扫└──────────────────────────────┘vdisplay vfp/vsync/vbp消隐区Blanking 就是面板不显示的区域——电子束或数字扫描指针从一行末尾回到下一行开头、从一帧底部回到顶部的时间。那 blanking porch 和撕裂有什么关系缩放器的 FIFO 每次从旧帧→新帧切换数据时会产生一个脏数据窗口。如果这个窗口能和消隐区对齐就算新旧数据混在一起也不会显示出来——因为消隐区面板本来就不显示。这就是我调 vback-porch / vfront-porch 的原理- 调大 vback-porch让消隐区更长把撕裂线推到消隐区里藏起来- 调大 vfront-porch消隐区位置移动看撕裂线能不能被覆盖- 但 vtotal vactive vfp vsync vbp 是固定的由 clock / htotal / 60fps决定所以加大 back 就要减 front- 最终目标把撕裂线推到 vfpvsyncvbp 覆盖的区域里不让它在显示区出现---6. 为什么自测模式不撕裂rk628 的自测模式Color Bar是芯片内部生成纯色条纹直接输出到 DSI发送器——完全绕过了缩放器和 HDMI 接收器。没有跨时钟域问题没有FIFO没有新旧帧切换——所以永远不撕裂。这也反证了你的 DSI PHY、lane配置、面板本身的初始化都是对的。问题只在缩放器的跨时钟域同步上。---7. 为什么改了 hsync-active / vsync-active 撕裂位置会变缩放器内部有一个函数叫calc_dsp_frm_hst_vst它计算缩放器从输入帧的哪个位置开始读取数据。这个计算依赖于 src/dst的 hsync/vsync 极性、htotal、vtotal、时钟频率等参数。改变极性相当于改变了缩放器识别的帧起点。帧起点变了FIFO新旧数据切换的时机就变了撕裂线的位置也跟着变了。这在调试上是一个信号你对时序的任何微调都在影响撕裂位置说明你还没有找到精确的对齐点但方向是对的。---8. 最终的解决方案分层┌─────────────┬─────────────────────────────┬─────────────────┬────────────────────┐│ 方案 │ 原理 │ 效果 │ 前提 │├─────────────┼─────────────────────────────┼─────────────────┼────────────────────┤│ 接 TE 线 │ 面板每帧结束发脉冲主机严 │ 彻底消除 │ 需要硬件 TE 引线 ││ │ 格同步 │ │ │├─────────────┼─────────────────────────────┼─────────────────┼────────────────────┤│ 调 blanking │ 让 FIFO │ 可消除肉眼可见 │ 需要精确计算/反复 ││ │ 脏数据窗口落入消隐区 │ 撕裂 │ 调试 │├─────────────┼─────────────────────────────┼─────────────────┼────────────────────┤│ 改 dst │ 让输入输出时钟域成整数倍 │ 降低 FIFO │ 面板 datasheet ││ clock │ │ 碰撞概率 │ 通常不允许 │├─────────────┼─────────────────────────────┼─────────────────┼────────────────────┤│ 双缓冲/帧缓 │ 写完一帧再读 │ 彻底消除 │ rk628 ││ 冲 │ │ │ 硬件不一定支持 │└─────────────┴─────────────────────────────┴─────────────────┴────────────────────┘你的情况是TE 没有clock 不能改只能调blanking。这个调试过程本质是用消隐区去盖住撕裂线反复调 vback/vfront/vsync就是在移动盖子。