3、LK阶段点亮:LK显示初始化流程、framebuffer配置、背光控制
好,咱们进入LK阶段。这是整个显示驱动开发中最刺激的一环——你写的第一行代码,能不能让屏幕亮起来,全看这里了。
我记得刚入行那会儿,第一次调LK点亮,折腾了整整三天。最后发现是背光PWM的极性搞反了。嗯,这种坑,我帮你提前踩一遍。
3.1 LK显示初始化流程
LK的显示初始化,说白了就是三步走:初始化硬件、配置framebuffer、点亮背光。但每一步里面都有讲究。
先看整体流程,我习惯把它画成一条线:
LK启动 → 显示驱动加载 → GPIO/CLK初始化 → MIPI DSI初始化 →
Panel初始化 → Framebuffer配置 → 背光控制 → 点亮完成
这里面最容易出问题的,是时序。你想想看,MIPI DSI的时钟还没稳定,你就去发Panel初始化命令,那肯定黑屏。
我个人习惯在每一步之间加一个短延时,比如5ms。别小看这几毫秒,它能帮你过滤掉很多硬件抖动问题。
3.2 Framebuffer配置
Framebuffer,说白了就是一块内存区域。你把像素数据写进去,硬件自动把它刷到屏幕上。
配置framebuffer,核心就三个参数:
| 参数 | 说明 | 常见值 |
|---|---|---|
| 宽度 | 屏幕水平像素数 | 1080、720 |
| 高度 | 屏幕垂直像素数 | 1920、1280 |
| 像素格式 | 每个像素占多少bit | RGB565、RGB888 |
举个例子,一块1080x1920的屏幕,用RGB565格式:
framebuffer大小 = 1080 * 1920 * 2 = 4,147,200 字节 ≈ 4MB
这里有个坑——内存对齐。我曾经遇到过,framebuffer地址没有按64字节对齐,结果刷出来的图像是花的。排查了整整一天。
配置代码大概长这样:
// 分配framebuffer内存
fb_addr = dma_alloc_coherent(fb_size, &phys_addr);
// 配置显示控制器
disp_ctrl->fb_base = phys_addr;
disp_ctrl->width = 1080;
disp_ctrl->height = 1920;
disp_ctrl->format = PIXEL_FORMAT_RGB565;
// 使能显示控制器
disp_ctrl_enable(disp_ctrl);
你可能会问,为什么要用dma_alloc_coherent?因为显示控制器是DMA设备,它直接读取内存刷屏。如果用普通内存,cache一致性会搞死你。
3.3 背光控制
背光控制,是点亮屏幕的最后一步。也是最容易翻车的一步。
背光控制通常有两种方式:
- GPIO直接控制:高低电平控制背光开关
- PWM调光:通过占空比调节亮度
我建议在LK阶段,先用GPIO直接点亮。等系统跑起来了,再调PWM。为什么?因为PWM的时钟源、极性、频率,任何一个不对,背光都不亮。
背光控制的代码示例:
// 初始化背光GPIO
gpio_set_mode(BACKLIGHT_PIN, GPIO_MODE_OUTPUT);
gpio_set_pull(BACKLIGHT_PIN, GPIO_PULL_NONE);
// 点亮背光(GPIO方式)
gpio_set_value(BACKLIGHT_PIN, 1);
// 或者用PWM方式
pwm_config(BACKLIGHT_PWM, PWM_FREQ_1KHZ, PWM_DUTY_50);
pwm_enable(BACKLIGHT_PWM);
这里有个经验——背光不要一上来就100%亮度。我见过有人这么干,结果屏幕瞬间亮瞎,电流过大把背光LED烧了。先设个30%,确认没问题再往上调。
3.4 常见问题与排查
我把LK点亮过程中最常遇到的问题列出来,你对照着查:
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| 完全黑屏 | 背光未亮、MIPI未初始化 | 先量背光电压,再看MIPI时钟 |
| 花屏 | Framebuffer地址不对、像素格式错误 | 打印fb地址,检查格式配置 |
| 图像偏移 | HBP/HFP参数错误 | 对照datasheet检查timing |
| 闪烁 | PWM频率太低、背光电源不稳 | 提高PWM频率到1kHz以上 |
我曾经遇到一个特别诡异的bug——屏幕能亮,但每隔几秒闪一下。查了三天,最后发现是framebuffer的刷新率和背光PWM频率产生了差拍。把PWM频率从200Hz改到1.2kHz,问题解决。
嗯,LK阶段点亮就这些。你按这个流程走,基本一次过。如果遇到问题,先别急着改代码,拿示波器量一下波形。很多时候,问题不在代码里,在信号上。