I.MX6ULL 裸机开发:LCD Framebuffer 与 RGB888 学习笔记

最近在 I.MX6ULL 裸机开发中学习 LCD 屏幕驱动,搞懂了 Framebuffer 显存原理、RGB 色彩格式,并且完成了实操代码:配置 LCD 引脚、时钟,初始化 LCDIF 控制器,最后接入 LM75 温度传感器,在屏幕上实时显示采集到的温度数据。

一、基础概念:像素、分辨率与 RGB888

屏幕画面本质是由大量像素点 构成的矩阵。我们这块 LCD 分辨率为800*480,代表横向 800 个像素,纵向 480 个像素。 分辨率是屏幕横向像素数量 × 纵向像素数量。分辨率相同,屏幕尺寸越小,PPI 越高,画面越细腻;尺寸相同,分辨率越高,图像效果越好。

每个像素点依靠 RGB 三原色混合出不同颜色,常见色彩格式有 RGB888、RGB565、ARGB8888:

  • RGB888:R、G、B 三个通道各占 8bit(0~255),一个像素占用 3 字节,可以表达 1670 万种颜色,色彩丰富;
  • RGB565:R 占 5bit、G 占 6bit、B 占 5bit,单个像素 2 字节,色彩较少,但占用内存更小;
  • ARGB8888:在 RGB 基础上增加 Alpha 透明通道,单个像素 4 字节,也就是我们代码里使用的格式。

我们代码中使用unsigned int保存颜色,就是 ARGB 格式,A 通道 0,后面 24bit 存放 RGB。

二、Framebuffer(显存)核心原理

Framebuffer,也就是显存,是内存中专门存放图像像素数据的一块空间。 显存起始地址固定,0x89000000,像素坐标(x,y)对应的显存地址计算公式:

复制代码
*(p + 800 * y + x) = color;
  • p:显存首地址
  • y:纵向行号,800是每行像素个数
  • x:横向列号

简单理解:CPU 不用直接和 LCD 屏幕打交道,只需要往显存内存地址写入像素颜色值 。硬件 LCDIF 控制器会自动读取显存里的数据,按照时序源源不断把像素送到屏幕上显示。 这就是裸机 LCD 绘图的核心:写内存 = 画屏幕。 我们写的lcd_drawpoint画点函数,底层就是这个公式。

三、LCD 时序信号

LCD 屏幕正常工作,依靠 4 根关键时序信号线:

  1. PCLK(像素时钟):Pixel Clock。同步每一个像素点发送的时间间隔,每来一个时钟,传输 1 个像素;
  2. HSYNC(行同步信号):Horizontal Sync。同步每一行图像,一行像素扫描完成,产生行同步脉冲,切换到下一行;
  3. VSYNC(帧同步信号):Vertical Sync。同步整幅图像,一整屏图像扫描完毕,触发帧同步,刷新下一帧;
  4. DE(Data Enable):数据使能信号。DE 为高的时候,当前传输的数据是有效的像素图像数据。

在 LCD 初始化代码中,我们配置的 hspw/hfp/hbp、vspw/vfp/vbp 这些参数,就是行场同步的前后肩、同步脉冲宽度,必须和屏幕手册匹配,否则屏幕会花屏、无法点亮。

四、代码实现讲解

1. LCD 硬件初始化

复制代码
void lcd_pin_init(void)

使用IOMUXC_SetPinMux把 24 根 LCD 数据线、PCLK、HSYNC、VSYNC、DE 等引脚复用为 LCDIF 外设功能;IOMUXC_SetPinConfig配置引脚电气属性,同时配置背光 GPIO 引脚。

复制代码
void lcd_clock_init(void)

配置 LCD 视频 PLL 时钟,为 LCDIF 控制器提供像素时钟 PCLK,是屏幕正常输出时序的基础。

复制代码
void lcd_init(void)

LCD 总初始化函数:引脚初始化→时钟初始化→LCDIF 复位→填写屏幕时序参数,指定 framebuffer 显存地址,最后开启 LCDIF,硬件开始输出图像。

2. 绘图基础函数

复制代码
// 画像素点
void lcd_drawpoint(int x, int y, unsigned int col)
{
    unsigned int *p = (unsigned int *)lcd_dev.frame_buffer;
    if (x > lcd_dev.width || y > lcd_dev.height)
    {
        return;
    }
    *(p + lcd_dev.width * y + x) = col;
}

这个函数就是显存公式的直接实现,给对应坐标的显存地址写入颜色,屏幕对应坐标就会点亮。lcd_clear_screen清屏函数,就是循环遍历全部显存,统一填充同一个颜色。

3. 项目实战:LCD 显示 LM75 实时温度

主循环代码:

复制代码
while (1)
{
    float f = get_lm75_temp();
    int k = f * 10;
    int m = k / 10;
    int n = k % 10;
    sprintf(buffer, "%d.%d", m, n);
    lcd_show_string(400, 240, 16 * strlen(buffer), 32, 32, buffer);
}

逻辑:I2C 读取 LM75 温度传感器浮点温度,放大十倍拆分整数、小数部分,用 sprintf 拼接字符串,调用lcd_show_string在屏幕坐标(400,240)位置打印温度。

当前代码存在小问题:每次刷新文字没有擦除旧文字,温度变化时会出现文字重叠拖影。解决方案:刷新前,在文字区域填充背景色矩形,覆盖上一次的文字。也可以增加delay_ms降低刷新频率,减少 CPU 占用。

五、学习小结

这次学习打通了 I.MX6ULL 裸机 LCD 驱动的完整流程:从 RGB 像素基础、显存 Framebuffer 原理,到 LCD 行场时序,再到寄存器配置、代码绘图,最后结合 I2C 温度传感器做了一个完整的小项目。 Framebuffer 模型非常关键,后续 Linux 系统下的 LCD 显示、Qt 界面,底层也沿用这套显存思想,裸机的学习相当于打好了底层基础。

相关推荐
wuyk5556 小时前
Keil工具链-第05讲-启动文件与__main到底做了什么
c语言·stm32·单片机·嵌入式硬件·物联网
La Pulga9 小时前
【FreeRTOS源码学习笔记】任务延时列表
笔记·mcu·学习·嵌入式·freertos·实时操作系统
楚山之石11 小时前
【JCO】mpMRI 先行替代 TURBT 初始分期:BladderPath 随机试验让 MIBC 患者提前 45 天得到正确治疗
人工智能·学习·mri·医学影像
shijuejianceliu12 小时前
传统规则视觉与嵌入式AI智能相机的技术差异
人工智能·嵌入式硬件·视觉检测·相机
Peter-OK14 小时前
PostgreSQL学习笔记(入门-进阶-精通说明)
笔记·学习·postgresql
承渊政道15 小时前
Linux网络学习【Reactor反应堆模式】
linux·网络·学习·ubuntu·reactor
不脱发的程序猿15 小时前
GD32串口数据收进内存之后DMA如何处理?
单片机·嵌入式硬件·dma·嵌入式·串口通信·gd32
橙橙笔记16 小时前
具身智能的学习 - 完成一个机械臂 第1节
python·学习·机械臂·具身智能
成都蜀味缘餐饮技术培训学校16 小时前
手撕烤兔技术培训实战指南,秘制腌料配方比例与调制手法
大数据·经验分享·笔记·其他·微信公众平台
希和202717 小时前
免费AI视频生成工具汇总(国内优先,适合做漫剧、短视频,Obsidian笔记版)
人工智能·笔记·音视频