当前位置: 首页 > news >正文

●从零理解 DSI 屏幕撕裂:一条数据流水线的故事

1. 整个系统在干什么

你的板子在做一件事:把 HDMI 输入的画面缩小后,显示在一块 MIPI DSI 小屏幕上。

数据流是这样的:

HDMI 源(笔记本) → rk628 芯片 → DSI 面板
720×720 (缩小到) 360×360
41.877 MHz 360×360 11 MHz

rk628 内部有一个缩放器(Scaler),负责把 720×720 的帧缩小成 360×360。缩放器输入侧跑 HDMI
时钟(41.877MHz),输出侧跑 DSI 时钟(11MHz)——这就是一切撕裂的根源。

---
2. 为什么要缩放?为什么时钟不一样?

HDMI 源输出的是 720×720@60fps,像素时钟 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,右边跑 11
km/h。你在左边的跑步机上画一幅画,画完传给右边继续画。左边的人画得快,右边的人画得慢。如
果两边没有任何同步信号,右边的人可能在你画到一半就开始往面板上"发表"——结果就是:

面板显示的画面:
┌──────────────────┐
│ ← 第 N 帧内容 │ ← 上半部分正常
│ │
├──────────────────┤ ← 这就是"撕裂线"
│ ← 第 N+1 帧内容 │ ← 下半部分是下一帧
└──────────────────┘

在 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 指令时才发一帧数据
- 面板刷完一帧后通过 TE(Tearing 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
- 最终目标:把撕裂线推到 vfp+vsync+vbp 覆盖的区域里,不让它在显示区出现

---
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
就是在移动盖子。

http://www.gsyq.cn/news/1618855.html

相关文章:

  • [测试技术] Obsidian 是什么?一个适合长期沉淀知识的本地笔记工具
  • 浔川代码编辑器 V4.2.0 全新功能发布:轻量化刷题专用编辑器,专为学生编程练习打造
  • 微信聊天记录备份指南:如何安全保存你的数字记忆?
  • 居民社区小程序积分系统模板分享
  • KLayout完整指南:如何免费打造专业级版图设计流程
  • Diablo Edit2:5大核心技术突破重塑暗黑破坏神II角色编辑体验
  • python Flask开发基础教程
  • Shell脚本精读 · S06-03 | 条件与控制流综合:读 30 行脚本的判断链
  • 高光谱相机全解析:技术分类、主流品牌与选型指南
  • 【课程设计/毕业设计】基于 SpringBoot 的校园日常行为规范评分归档系统的设计与实现 基于 SpringBoot 的中小学学生品行综合考评管理系统【附源码、数据库、万字文档】
  • Windows系统文件AutomaticAppSignInPolicy.dll丢失找不到问题解决
  • 第一章Netty,Selector写入内容过多问题
  • 技术人转型项目管理:30岁前后如何用PMP完成思维切换
  • 免费开源桌面分区神器:5分钟彻底告别杂乱Windows桌面
  • 云手机技术详解:原理、自动化 API 实战代码与商用选型指南
  • 【毕业设计】基于 SpringBoot 的学生日常表现评分登记管理系统的设计与实现 基于 SpringBoot 的中小学行为规范考核管理系统(源码+文档+远程调试,全bao定制等)
  • 3分钟掌握OFD转PDF:免费开源工具Ofd2Pdf完全指南
  • Claude 实战: AI 自动帮你“加班“:/loop 完全指南
  • ISP算法工程师面试--3A之AE篇
  • 陕西市场靠谱的电瓶观光车制造商找哪家
  • 慈溪珠宝定制哪家靠谱
  • 国内可用电商AI作图工具技术横评与选型方案:从实测数据到自动化工作流
  • lru记录的是对象最后一次被命令程序访问的时间,占据的比特数不同的版本有所不同(如4.0版本占24比特,2.6版本占22比特)。
  • LV3296与PIC24HJ256GP610嵌入式数据采集系统设计
  • 3步掌握WeChatMsg:让你的聊天记忆永远留存
  • 七部门力挺“AI一人公司”:风口之下,我们该如何重塑个体的商业价值?
  • 瑞芯微RV1126B开发板(EASY-EAI-PI2) OCR文字识别
  • KES数据库国产化全栈适配与迁移改造落地规范
  • Python实现AES-256加解密:从原理到实战的完整指南
  • 工程现场施工管理系统怎么选?落地避坑实用指南