3. 屏幕刷新与撕裂:屏幕刷新率、垂直同步、撕裂现象成因分析
屏幕刷新这个话题,说白了就是显示系统里最基础也最容易被忽视的一环。我早年做第一块LCD驱动时,觉得只要把帧数据送出去就行了,结果画面一跑起来,那个撕裂感简直让人抓狂。后来才明白,刷新率、垂直同步、撕裂这三者之间,藏着嵌入式图形性能优化的核心秘密。
3.1 屏幕刷新率:显示系统的“心跳”
屏幕刷新率,就是显示器每秒重绘完整画面的次数,单位是Hz。60Hz意味着每秒刷新60次,每次间隔约16.67ms。这个参数决定了显示系统的时间基准。
我个人习惯把刷新率看作显示器的“心跳”。每次心跳,屏幕从左上角到右下角逐行扫描一遍。LCD虽然不像CRT那样真的用电子束扫描,但像素数据的更新逻辑仍然是逐行进行的。
关键认知:刷新率是硬件决定的固定节奏。你的MCU或MPU必须在每个刷新周期内完成帧缓冲区的更新,否则就会出问题。
常见的刷新率场景:
- 60Hz:绝大多数嵌入式LCD的标准配置,周期16.67ms
- 30Hz:低功耗场景,周期33.33ms,肉眼能感知到闪烁
- 120Hz:高端工业或游戏屏,周期8.33ms,对渲染压力极大
3.2 垂直同步:让渲染跟上硬件的节奏
垂直同步(V-Sync)是一种同步机制。它的作用很简单:让GPU或CPU的帧提交动作,与屏幕的刷新周期对齐。
为什么需要同步?你想想看,如果屏幕正在扫描第300行,你突然把帧缓冲区的内容改了,那屏幕上半部分显示的是旧帧,下半部分显示的是新帧——这就是撕裂。
我的经验:在STM32F429上做LCD驱动时,我习惯用LTDC的垂直空白中断(VBlank ISR)来触发帧交换。这个中断正好落在屏幕扫描完最后一行的瞬间,是切换缓冲区的黄金窗口。
垂直同步的实现方式:
| 方式 | 原理 | 延迟 | 适用场景 |
|---|---|---|---|
| 硬件V-Sync | 显示控制器硬件信号同步 | 低 | 高性能嵌入式 |
| 软件V-Sync | 轮询或中断等待VBlank | 中 | 通用MCU |
| 双缓冲+V-Sync | 后台缓冲区渲染,VBlank时交换 | 低 | 推荐方案 |
3.3 撕裂现象:不同步的代价
撕裂(Tearing)的本质,是帧缓冲区在屏幕扫描过程中被修改。屏幕上半部分读到了旧帧的数据,下半部分读到了新帧的数据,中间那条错位的分界线就是撕裂线。
为什么会这样?
- 单缓冲模式下,CPU/GPU随时可以写入帧缓冲区
- 屏幕控制器独立运行,按固定频率读取缓冲区
- 两者没有握手协议,读写冲突必然发生
我曾经踩过的坑:在一个工业HMI项目中,我用单缓冲+高优先级任务直接写显存。结果操作员反映屏幕上的仪表指针经常“断裂”。我一开始以为是DMA传输问题,排查了两天才意识到是撕裂。加上V-Sync同步后,问题立刻消失。
撕裂的视觉表现:
- 水平方向出现明显的错位分界线
- 快速滚动的文字或图像出现“剪切”效果
- 动画不连贯,有跳跃感
3.4 三者关系:一个时间轴上的博弈
刷新率、垂直同步、撕裂,这三者其实是在同一个时间轴上博弈。我画了一张图来展示它们的关系:
3.5 实际项目中的取舍
在实际嵌入式项目中,不是所有场景都需要垂直同步。我总结了几条经验:
- 静态界面:不需要V-Sync,单缓冲即可,省内存省功耗
- 动画/视频播放:必须用V-Sync+双缓冲,否则撕裂无法接受
- 触摸交互:建议用V-Sync,但要注意帧率不能低于30fps,否则触摸响应延迟会很明显
- 低功耗场景:可以关闭V-Sync,用软件定时器控制帧率,牺牲流畅度换续航
我的建议:如果你不确定要不要加V-Sync,先加上。在调试阶段用逻辑分析仪抓一下LTDC的VSYNC和帧缓冲区写信号,看看有没有重叠。有重叠就保留,没有重叠再考虑优化掉。
3.6 避坑指南:我曾经犯过的错
最后分享几个我实际踩过的坑,希望能帮你少走弯路:
- 坑1:以为DMA传输完成就代表帧更新完成。实际上DMA只是把数据搬到了显存,屏幕控制器可能正在读那个区域。一定要等VBlank信号。
- 坑2:在VBlank中断里做太多事情。VBlank窗口通常只有几百微秒,如果中断处理时间过长,会错过下一个刷新周期,导致帧率下降。
- 坑3:双缓冲时忘记清空后台缓冲区。新帧数据只覆盖了部分区域,残留的旧帧数据会在切换后显示出来,造成“鬼影”。
嗯,屏幕刷新与撕裂这个话题,说深了可以写一本书。但核心就一句话:让帧缓冲区的写入,永远发生在屏幕不读它的时候。 理解了这句话,你就掌握了嵌入式显示系统同步的精髓。