嵌入式显示休眠唤醒编程:实现屏幕快速唤醒同时避免画面闪屏
闪屏不是屏驱“质量差”,是顺序错了。最常见现象:唤醒瞬间“咔”一下白屏/花屏/旧画面残影,再变成正常图。根因就两条——背光开得太早,或 Sleep Out 后没等屏内部振荡器稳定就开始刷 GRAM。 正确做法是把“停刷新→关显示→进休眠→关背光”和“开屏驱→等稳定→回写显存→开背光”两套顺序钉死。
一、休眠顺序:先停数据再睡
很多人直接发 0x10(Sleep In) 就完事,这时候 GUI 任务还可能半帧在刷,DMA 也没停,屏驱内部状态切换会和主机写冲突。
标准进入流程(SPI/RGB屏通用):
通知GUI任务停止刷新
等当前 flush/DMA 完成
发 0x28 Display Off(关显示输出)
延时几帧(一般 10~20ms)
发 0x10 Sleep In
最后关背光 GPIO/PWM
void lcd_enter_sleep(void){
gui_refresh_stop(); // 不再提交新帧
while(dma_busy); // 等当前传输结束
lcd_cmd(0x28); // Display OFF
mdelay(20);
lcd_cmd(0x10); // Sleep In
mdelay(10);
backlight_off(); // 背光最后关
spi_pins_idle(); // SPI脚设输入,避免漏电
}
SPI 脚休眠时别一直输出高电平,否则通过屏驱保护二极管漏电,休眠电流从 5μA 飙到 20μA。
二、唤醒顺序:背光必须最后
唤醒最容易踩的坑就是“一醒来先开背光”。带 GRAM 的屏 Sleep Out 后会立刻从内部 RAM 读旧数据上屏,背光要是已经亮了,人眼看到的就是残影/花屏。
正确顺序:
开屏驱电源/IO
0x11 Sleep Out
等 120ms(MIPI DCS 规范,屏厂可能要 150ms)
重发私有初始化/Gamma(部分屏休眠会丢)
回写整帧或脏区域到 GRAM
0x29 Display On
再开背光
void lcd_wakeup(void){
backlight_off();
spi_pins_active();
lcd_cmd(0x11); // Sleep Out
mdelay(120); // 振荡器稳定,别省
lcd_panel_reinit(); // gamma/电压等私有序列
lcd_restore_gram(); // 把逻辑帧缓冲重写进屏
lcd_cmd(0x29); // Display On
mdelay(20);
backlight_on(); // 背光最后开
gui_refresh_resume();
}
关键:背光使能放在 Display On 之后,且 GRAM 已经是正确的目标帧,唤醒就是“直接出图”,没有中间帧。
三、GRAM 是否保留
不同屏行为不一样:
ST7735/部分 ST7789:Sleep In 不清 RAM,但长时间漏电会乱
ILI9341:唤醒后建议重初始化显示参数
段码/小 COG LCD:RAM 常保,唤醒快但别依赖
MIPI DSI CMD 屏:有的屏驱自刷,有的主机职责
工程上别赌“RAM 还在”,唤醒统一做一次整帧回写最稳;静态界面也可只回写脏矩形。
void lcd_restore_gram(void){
lcd_set_window(0,0,W-1,H-1);
lcd_write_pixels(fb_logical, W*H); // 逻辑帧缓冲
}
前提是逻辑帧缓冲(MCU侧)一直没释放,屏睡了它也得留着。
四、LVGL/RTOS 场景
LVGL 项目别在 refr_task 跑一半进休眠,否则 flush_cb 里 DMA 被掐断状态机乱掉。
做法:
设 gui_suspending=1,refr_timer 不再触发
等 lv_display_flush_ready 已返回
再发 0x28/0x10
唤醒后先 lcd_restore_gram() 再放开 LVGL
if(gui_suspending){
return; // refr_task 直接跳过
}
中断唤醒源(按键/触摸/I2C)只置标志,真正恢复在任务上下文做,别在 EXTI 中断里发 SPI。
五、MIPI DSI 补充
DSI 屏走 D-PHY LP/HS 切换,Sleep Out 后还要等链路回到 HS 稳定,reg_wakeup_time 不能压到一行时间内,否则 FIFO 下溢花屏。 但应用层代码仍是那套顺序:关背光→Sleep In→停传输;唤醒 Sleep Out→等→重初始化→Display On→背光。
六、落坑清单
背光在 Display On 前开→花屏残影
Sleep Out 不等 120ms→首帧异常
休眠时 GUI 还在刷→DMA 半截被掐
假设 GRAM 一定保留→长时间休眠乱码
SPI 脚休眠仍输出→漏电下不去
在中断里发屏驱命令→SPI 时序被抢占
只发 0x11 不重发 gamma→亮度/色偏
唤醒不回写帧→旧界面闪一下才更新
RGB/LTDC 屏没停时序→控制器还在扫
七、快速判定闪屏来源
闪一下旧画面 → 背光早于 GRAM 回写
白屏/雪花 → Sleep Out 延时不够或初始化没重发
残影拖尾 → Display Off 没发,直接 Sleep In
唤醒后不动 → RESET 脚休眠被拉低没恢复
电流下不来 → 背光单独供电没关,或 SPI 脚漏电
八、落地顺序
休眠前停 GUI + 等 DMA 完成
0x28 → 0x10 → 关背光
SPI/通信脚设空闲
唤醒先 Sleep Out,死等 120ms
重发屏厂初始化序列
整帧回写 GRAM
0x29 Display On
最后开背光
恢复 GUI 刷新
嵌入式显示休眠的本质不是“发两条命令”,是显示输出链路按顺序断电、按对称顺序上电。闪屏几乎都出在“背光抢跑”或“Sleep Out 没等稳”这两处;把背光放到 Display On 之后、把 GRAM 回写放到背光之前,唤醒就是无感出图。快速唤醒 ≠ 跳过延时,120ms 换的是没有闪屏,值。





