1. 花屏现象的本质:什么是花屏?
说实话,做嵌入式UI这些年,我最怕半夜接到测试电话——「屏幕花了」。花屏这玩意儿,说大不大,说小不小。轻则重启就好,重则直接让你怀疑人生,从硬件到驱动到LVGL配置,挨个排查一遍。
那到底什么是花屏?说白了,就是屏幕显示的内容和预期不一致。你本来想画一个漂亮的蓝色按钮,结果屏幕上出现了一堆彩色条纹;你明明更新了温度数值,结果数字像鬼影一样拖在后面。这些,都算花屏。
我个人习惯把花屏分成两大类:「显存层面的问题」和「时序层面的问题」。前者是数据错了,后者是数据对了但没显示对。搞清楚这个分类,排查方向就清晰多了。
花屏的常见表现形式
我整理了一下,实际项目中遇到的花屏,基本逃不出下面这四种。你对照着看,很快就能定位问题类型。
| 表现形式 | 典型现象 | 常见原因 |
|---|---|---|
| 条纹 | 水平或垂直的彩色/黑色线条,像栅栏一样 | DMA传输错位、行同步参数错误 |
| 噪点 | 随机分布的彩色小点,像雪花屏 | 显存未初始化、内存越界写入 |
| 颜色错乱 | 红色变成蓝色,绿色变成紫色 | 颜色格式不匹配(RGB565 vs RGB888) |
| 图像撕裂 | 画面上下部分显示不同帧的内容,像被撕开 | 帧缓冲区切换时未同步刷新 |
条纹——最让人头疼的「栅栏效应」
条纹花屏,我在项目里遇到得最多。有一次调试一个320x240的屏幕,刷出来全是斜向的彩色条纹,像万花筒一样。查了半天,最后发现是行偏移参数(HBP)少配了2个像素。
为什么会这样?你想想看,屏幕是一行一行刷新的。如果每行的起始位置算错了,后面的数据就会整体偏移,形成条纹。LVGL本身不直接控制这些参数,但底层驱动如果配错了,LVGL再漂亮也没用。
噪点——「显存里有垃圾」
噪点花屏,说白了就是显存里的数据是乱的。我记得有一次,系统启动后屏幕左上角总有一块区域在闪烁彩色噪点。代码逻辑看起来没问题,LVGL的控件也都正常初始化了。
后来用调试器读了一下那块区域的显存,发现里面全是0xCDCDCDCD——这是编译器在Debug模式下给未初始化内存填充的「哨兵值」。问题找到了:我给LVGL分配的缓冲区太大了,超出了实际可用的SRAM范围,溢出的部分读回来全是垃圾数据。
颜色错乱——「RGB顺序搞反了」
颜色错乱这个问题,新手特别容易踩。LVGL默认用的是RGB565颜色格式,但有些屏幕驱动芯片(比如ILI9341)默认是BGR顺序。你传一个红色(0xF800)过去,它当成蓝色显示出来。
我习惯在初始化LVGL时,显式设置颜色格式:
/* 在lv_conf.h中配置 */
#define LV_COLOR_DEPTH 16
#define LV_COLOR_16_SWAP 0 /* 如果屏幕是BGR顺序,改为1 */
/* 或者在运行时设置 */
lv_display_set_color_format(disp, LV_COLOR_FORMAT_RGB565);
嗯,这里要注意:不是所有屏幕驱动都支持运行时切换RGB/BGR顺序。有些需要你在初始化SPI或并行接口时,通过写寄存器来配置。我建议你拿到一个新屏幕时,先画一个纯红、纯绿、纯蓝的色块,确认颜色顺序对不对。
图像撕裂——「帧同步没做好」
图像撕裂,说白了就是屏幕在刷新到一半的时候,你改了显存里的数据。上半部分还是上一帧的内容,下半部分已经变成下一帧了。看起来就像画面被撕开了一样。
LVGL本身提供了双缓冲机制来解决这个问题。但很多开发者图省事,只用了一个缓冲。我个人的建议是:只要硬件条件允许,一定要用双缓冲 + 垂直同步。
- LVGL在后台缓冲区绘制新帧
- 等待屏幕的垂直消隐期(VBlank)
- 在VBlank期间交换前后缓冲区指针
- 屏幕从新的缓冲区读取数据,完成刷新
你可能会问:「那我用单缓冲行不行?」行,但要做好心理准备。我在一个低成本的项目上用过单缓冲,结果只要UI更新频率超过30fps,撕裂就肉眼可见。后来加了双缓冲,问题立刻消失。
怎么快速判断是哪一类花屏?
我总结了一个简单的排查流程,你可以记一下:
- 先看花屏是否固定位置——如果是固定区域的条纹或噪点,大概率是显存问题或驱动参数问题。
- 再看花屏是否动态变化——如果画面不动时花屏消失,一动就出现撕裂,那基本是帧同步问题。
- 最后看颜色是否整体偏色——如果所有颜色都不对,先检查LVGL的颜色格式配置和屏幕驱动的RGB/BGR顺序。