ARM-12-I.MX6U LCD

一、基础概念

LCD(液晶显示器)是纯输出设备,只负责显示,不含触摸功能。触摸由独立的触摸控制器实现。本项目使用 ATK4384,分辨率 800×480,RGB 接口。

分辨率

规格 像素点数量
1080P 1920×1080
2K 2560×1440
4K 3840×2160
本项目 800×480

尺寸不变 → 分辨率越高越清晰;分辨率不变 → 尺寸越小越清晰(手机比显示器细腻的原因)

像素格式(本项目使用 ARGB8888)

格式 位数 字节数 说明
RGB565 16bit 2字节 R5G6B5
RGB888 24bit 3字节 无透明通道
ARGB8888 32bit 4字节 A透明+RGB,本项目使用

ARGB8888 内存布局:

复制代码
bit31~24: Alpha(透明度)
bit23~16: RED
bit15~8:  GREEN
bit7~0:   BLUE

常用颜色值:

c 复制代码
红色  0x00FF0000
绿色  0x0000FF00
蓝色  0x000000FF
黄色  0x00FFFF00
白色  0x00FFFFFF
黑色  0x00000000
紫色  0x00FF00FF  // lcd_fill() 中使用的颜色

显存大小

复制代码
显存大小 = 800 × 480 × 4字节 = 1,536,000 字节 ≈ 1.5MB

从 DDR3 中划出,首地址写入 LCDIF_CUR_BUF,修改显存内容即可改变屏幕显示。


二、RGB LCD 硬件接口

I.MX6U-Mini 支持 RGB 接口 LCD,信号线如下:

信号线 数量 说明
R[7:0] 8根 红色数据线
G[7:0] 8根 绿色数据线
B[7:0] 8根 蓝色数据线
DE 1根 数据使能线(Data Enable)
VSYNC 1根 帧同步信号(垂直同步)
HSYNC 1根 行同步信号(水平同步)
PCLK 1根 像素时钟

驱动模式:

  • DE 模式 :需要 DE 信号,可以不接 HSYNC 也能正常工作(本项目使用
  • HV 模式:不需要 DE 信号,依赖 HSYNC/VSYNC

三、LCD 时序参数(最核心知识点)

显示一帧图像就像用一支"笔"从左到右、从上到下扫描每个像素点,扫描完最后一个点就是一帧。

3.1 行时序参数(水平方向)

复制代码
|<--HSPW-->|<---HBP--->|<------HOZVAL(有效像素)----->|<--HFP-->|
参数 全称 说明 本项目值
HSPW Horizontal Sync Pulse Width HSYNC 脉冲宽度,单位:CLK 48
HBP Horizontal Back Porch 行同步后肩(等待时间) 88
HOZVAL Horizontal Valid 有效像素宽度(屏幕宽度) 800
HFP Horizontal Front Porch 行同步前肩 40
复制代码
一行时间 = HSPW + HBP + HOZVAL + HFP = 48 + 88 + 800 + 40 = 976 个像素时钟

3.2 帧时序参数(垂直方向)

复制代码
|<-VSPW->|<--VBP-->|<--------LINE(有效行)-------->|<-VFP->|
参数 全称 说明 本项目值
VSPW Vertical Sync Pulse Width VSYNC 脉冲宽度,单位:行 3
VBP Vertical Back Porch 帧同步后肩 32
LINE Vertical Valid 有效行数(屏幕高度) 480
VFP Vertical Front Porch 帧同步前肩 13
复制代码
一帧行数 = VSPW + VBP + LINE + VFP = 3 + 32 + 480 + 13 = 528 行

3.3 像素时钟计算

复制代码
一帧时钟数 = 528 × 976 = 515,328
60帧/秒   = 515,328 × 60 = 30,919,680 ≈ 31 MHz

→ 实际配置 PLL5 输出 31.5 MHz

HBP/HFP/VBP/VFP 存在的原因: 源自 CRT 电子枪的历史设计。在 LCD 中是给屏幕内部 IC 的反应时间,让其识别换行/换帧信号,锁定有效像素数据的开始位置。不同屏幕参数不同,必须查屏幕手册,不能随意填写。


四、像素时钟配置

时钟路径

复制代码
24MHz 晶振
    ↓
PLL5(VIDEO_PLL)×42 → 1008 MHz
    ↓  LCDIF1_PRE_CLK_SEL 选 PLL5
    ↓  LCDIF1_PRED = 3 → ÷4    → 252 MHz
    ↓  LCDIF1_PODF = 7 → ÷8
    ↓
LCDIF1_CLK_ROOT = 1008 ÷ 4 ÷ 8 = 31.5 MHz

涉及的寄存器

寄存器 说明 设置值
CCM_ANALOG_PLL_VIDEO bit6:0 DIV_SELECT PLL5 倍频 42(×42=1008MHz)
CCM_ANALOG_PLL_VIDEO bit20:19 POST_DIV_SELECT 后分频 0 → 1分频
CCM_ANALOG_PLL_VIDEO bit13 ENABLE PLL5 使能 1
CCM_ANALOG_MISC2 bit31:30 VIDEO_DIV 视频分频 0 → 1分频
CCM_CSCDR2 bit17:15 LCDIF1_PRE_CLK_SEL 时钟源选择 选 PLL5
CCM_CSCDR2 bit14:12 LCDIF1_PRED 预分频 3 → ÷4
CCM_CBCMR bit25:23 LCDIF1_PODF 后分频 7 → ÷8
CCM_CSCDR2 bit11:9 LCDIF1_CLK_SEL 最终时钟选择 pre-muxed

五、eLCDIF 控制器寄存器详解

I.MX6U 的 LCD 控制器全称 Enhanced LCD Interface(eLCDIF),使用 DOTCLK 模式驱动 RGB LCD。

LCDIF_CTRL --- 主控制寄存器

名称 说明 本项目设置
bit31 SFTRST 软复位,为1强制复位 初始化时先复位再清零
bit30 CLKGATE 时钟门控,正常运行必须为0 0
bit19 BYPASS_COUNT DOTCLK模式必须为1 1
bit17 DOTCLK_MODE 为1 → DOTCLK模式 1
bit11:10 LCD_DATABUS_WIDTH 数据总线宽度,3=24位 3
bit9:8 WORD_LENGTH 像素数据宽度,3=24位/像素 3
bit5 MASTER 主模式使能 1
bit0 RUN eLCDIF 使能,最后置1 最后置1
c 复制代码
// 代码中的写法
LCDIF->CTRL = (1 << 19) | (1 << 18) | (0x3 << 10) | (0x3 << 8) | (1 << 5);
// 最后使能
LCDIF->CTRL |= (1 << 0);

LCDIF_CTRL1

只用到 BYTE_PACKING_FORMAT(bit19:16)

  • 0xF = 32位像素数据全有效(默认值)
  • 0x7 = 仅低24位有效(A通道不传输,本项目使用)
c 复制代码
tmp = LCDIF->CTRL1;
tmp &= ~(0xf << 16);
tmp |= (0x7 << 16);
LCDIF->CTRL1 = tmp;

LCDIF_TRANSFER_COUNT --- 分辨率寄存器

复制代码
bit31:16  V_COUNT = 屏幕高度(480)
bit15:0   H_COUNT = 屏幕宽度(800)
c 复制代码
LCDIF->TRANSFER_COUNT = (480 << 16) | 800;

LCDIF_VDCTRL0 --- VSYNC 控制

名称 说明
bit28 ENABLE_PRESENT DE 信号使能:1=使能
bit24 ENABLE_POL DE 极性:1=高有效
bit21 VSYNC_PERIOD_UNIT DOTCLK 模式必须为1(单位=行)
bit20 VSYNC_PULSE_WIDTH_UNIT DOTCLK 模式必须为1
bit17:0 VSYNC_PULSE_WIDTH VSPW 参数值 = 3
c 复制代码
LCDIF->VDCTRL0 = (1 << 28) | (1 << 24) | (1 << 21) | (1 << 20) | 3;

LCDIF_VDCTRL1 --- VSYNC 总周期

复制代码
值 = 高度 + VSPW + VBP + VFP = 480 + 3 + 32 + 13 = 528

LCDIF_VDCTRL2 --- HSYNC 控制

复制代码
bit31:18  HSYNC_PULSE_WIDTH = HSPW = 48
bit17:0   HSYNC_PERIOD = 宽度 + HSPW + HBP + HFP = 800 + 48 + 88 + 40 = 976
c 复制代码
LCDIF->VDCTRL2 = (48 << 18) | 976;

LCDIF_VDCTRL3 --- 等待计数

复制代码
bit27:16  HORIZONTAL_WAIT_CNT = HSPW + HBP = 48 + 88 = 136
bit15:0   VERTICAL_WAIT_CNT   = VSPW + VBP = 3  + 32 = 35
c 复制代码
LCDIF->VDCTRL3 = (136 << 16) | 35;

LCDIF_VDCTRL4

复制代码
bit18     SYNC_SIGNALS_ON = 1(使能 VSYNC/HSYNC/DOTCLK)
bit15:0   DOTCLK_H_VALID_DATA_CNT = 屏幕宽度 = 800
c 复制代码
LCDIF->VDCTRL4 = (1 << 18) | 800;

显存寄存器

寄存器 说明
LCDIF_CUR_BUF 当前帧显存地址,eLCDIF 自动读取并显示
LCDIF_NEXT_BUF 下一帧显存地址(双缓冲用,也可与 CUR_BUF 相同)
c 复制代码
#define LCD_CUR_BUF  0x88000000
LCDIF->CUR_BUF  = LCD_CUR_BUF;
LCDIF->NEXT_BUF = LCD_CUR_BUF;

六、lcd_init() 完整初始化流程

复制代码
1. lcd_io_init()    初始化 IO 引脚
       ↓  24根数据线 DATA00~DATA23,CLK/HSYNC/VSYNC/ENABLE
       ↓  引脚复用:IOMUXC 配置为 LCDIF,电气特性 0x10f9
       ↓  背光控制:GPIO1_IO08 → 输出高电平点亮

2. lcd_clk_init()   初始化像素时钟
       ↓  PLL5 × 42 = 1008MHz
       ↓  PRED ÷ 4 = 252MHz
       ↓  PODF ÷ 8 = 31.5MHz

3. lcd_reset()      复位 eLCDIF
       ↓  SFTRST=1 → delay_ms(20) → SFTRST=0, CLKGATE=0

4. 配置 LCDIF_CTRL       DOTCLK模式,24位总线,主模式(RUN 暂不置1)
5. 配置 LCDIF_CTRL1      BYTE_PACKING_FORMAT = 0x7
6. 配置 LCDIF_TRANSFER_COUNT   (480<<16)|800
7. 配置 LCDIF_VDCTRL0    信号极性,VSPW=3
8. 配置 LCDIF_VDCTRL1    VSYNC总周期=528
9. 配置 LCDIF_VDCTRL2    HSPW=48,HSYNC总周期=976
10. 配置 LCDIF_VDCTRL3   水平等待=136,垂直等待=35
11. 配置 LCDIF_VDCTRL4   使能同步信号,有效宽度=800
12. 设置显存地址          CUR_BUF = NEXT_BUF = 0x88000000
13. LCDIF_CTRL |= (1<<0)  RUN=1,开始输出像素时钟
14. GPIO1_IO08 = 高电平   开启背光,屏幕点亮 ✓

七、显存机制与 lcd_fill()

LCD 内部没有显存 。需要从 DDR3 中划出一块内存(约 1.5MB)作为显存,把首地址写入 LCDIF_CUR_BUF,eLCDIF 控制器自动循环读取这块内存,按像素格式输出到屏幕。要显示什么,直接修改显存内容即可。

c 复制代码
int lcd_fill(void)
{
    uint32_t * p = (uint32_t *)LCD_CUR_BUF;  // 指向显存起始地址
    int i = 0;
    for(i = 0; i < 800 * 300; i++)           // 填充前 300 行
    {
        *(p + i) = 0xff00ff;                  // 紫色
    }
    return 0;
}

八、图形库移植接口

移植 graphics.c / graphics.h / font.h 需要先实现三个底层接口:

c 复制代码
// 1. 在指定坐标画一个像素点
void lcd_draw_point(int x, int y, uint32_t color);

// 2. 读取指定坐标的像素值
uint32_t lcd_read_point(int x, int y);

// 3. 画一个矩形(左上角x0,y0,右下角x1,y1)
void lcd_draw_rect(int x0, int y0, int x1, int y1, uint32_t color);

图形库提供的常用函数:

c 复制代码
// 在指定位置显示字符串(最常用)
lcd_show_string(int x, int y, char *str, uint32_t color);

// 画线、画圆等
lcd_draw_line(...);
lcd_draw_circle(...);

九、LCD 设备结构体设计

将 LCD 参数封装进结构体,方便图形库调用:

c 复制代码
typedef struct {
    uint32_t  width;        // 屏幕宽度(像素)
    uint32_t  height;       // 屏幕高度(像素)
    uint32_t  hspw;         // HSYNC 脉冲宽度
    uint32_t  hbp;          // 行后肩
    uint32_t  hfp;          // 行前肩
    uint32_t  vspw;         // VSYNC 脉冲宽度
    uint32_t  vbp;          // 帧后肩
    uint32_t  vfp;          // 帧前肩
    uint32_t *framebuffer;  // 显存首地址
} Lcd_type;

extern Lcd_type dev;        // 全局变量,供图形库调用

十、关键寄存器速查表

寄存器 关键位 功能 本项目值
LCDIF_CTRL bit19 BYPASS_COUNT DOTCLK 模式必须=1 1
LCDIF_CTRL bit17 DOTCLK_MODE DOTCLK 模式使能 1
LCDIF_CTRL bit11:10 LCD_DATABUS_WIDTH 总线宽度(3=24位) 3
LCDIF_CTRL bit9:8 WORD_LENGTH 像素位数(3=24位) 3
LCDIF_CTRL bit5 MASTER 主模式 1
LCDIF_CTRL bit0 RUN eLCDIF 使能 最后置1
LCDIF_CTRL1 bit19:16 BYTE_PACKING_FORMAT 有效字节掩码(0x7=24位) 0x7
LCDIF_TRANSFER_COUNT bit31:16 V_COUNT 垂直分辨率 480
LCDIF_TRANSFER_COUNT bit15:0 H_COUNT 水平分辨率 800
LCDIF_VDCTRL0 bit28 ENABLE_PRESENT DE 信号使能 1
LCDIF_VDCTRL0 bit17:0 VSYNC_PULSE_WIDTH VSPW 值 3
LCDIF_VDCTRL1 全部 VSYNC总周期 528
LCDIF_VDCTRL2 bit31:18 HSPW 值 48
LCDIF_VDCTRL2 bit17:0 HSYNC总周期 976
LCDIF_VDCTRL3 bit27:16 HSPW+HBP(水平等待) 136
LCDIF_VDCTRL3 bit15:0 VSPW+VBP(垂直等待) 35
LCDIF_VDCTRL4 bit18 SYNC_SIGNALS_ON 同步信号使能 1
LCDIF_VDCTRL4 bit15:0 有效宽度(水平像素数) 800
LCDIF_CUR_BUF 全部 当前帧显存首地址 0x88000000
LCDIF_NEXT_BUF 全部 下一帧显存首地址 0x88000000

十一、面试常问 Q&A

Q1:LCD 的 HBP/HFP/VBP/VFP 是什么,为什么存在?

源自 CRT 电子枪的历史设计。在 LCD 中,这段时间是给屏幕内部 IC 的反应时间,让其识别换行/换帧信号,锁定有效像素数据的开始位置。不同屏幕的这四个参数不同,必须查屏幕手册获取,不能随意填写。


Q2:显存在哪里,如何显示图像?

LCD 内部没有显存,需要从 DDR3 中划出一块内存(约 1.5MB)作为显存,把首地址写入 LCDIF_CUR_BUF,eLCDIF 控制器自动把这块内存按像素格式输出到屏幕。要显示什么,直接修改显存内容即可。


Q3:像素时钟 31 MHz 是怎么来的?

由屏幕分辨率和刷新率决定:

复制代码
(VSPW+VBP+HEIGHT+VFP) × (HSPW+HBP+WIDTH+HFP) × fps
= (3+32+480+13) × (48+88+800+40) × 60
= 528 × 976 × 60
≈ 31 MHz

实际通过 PLL5 配置为 31.5MHz。


Q4:为什么用 DOTCLK 模式而不是 VSYNC 或 MPU 模式?

DOTCLK 模式就是 RGB 接口,适合直接驱动带 RGB 信号线的 LCD 屏幕(24根数据线 + 控制信号)。本项目搭载的 ATK4384 就是 RGB 接口屏幕。与 MPU 模式相比,DOTCLK 模式由控制器自动刷新,CPU 无需干预。


Q5:BYTE_PACKING_FORMAT 为什么设置为 0x7?

像素格式虽然是 ARGB8888(每像素 4字节),但 A(透明度)通道不需要输出到屏幕。BYTE_PACKING=0x7 表示每个 32bit 数据中,bit[23:0](RGB 三通道)有效,bit[31:24](A通道)无效,控制器只传输 24 位有效数据。

相关推荐
bubiyoushang8888 小时前
基于STM32的心电采集系统设计
stm32·单片机·嵌入式硬件
笨笨饿8 小时前
26_为什么工程上必须使用拉普拉斯变换
c语言·开发语言·人工智能·嵌入式硬件·机器学习·编辑器·概率论
youcans_8 小时前
【STM32-MBD】(18)Clarke / Park 坐标变换链路
stm32·单片机·嵌入式硬件·matlab·代码生成
F137298015579 小时前
WD5208S 非隔离降压功率开关:集成650V MOSFET,220V降12V,5V,700MA
stm32·单片机·嵌入式硬件·51单片机
KOYUELEC光与电子努力加油9 小时前
JAE日本航空电子推出满足汽车市场小型防水最新需求的MX80系列连接器
服务器·科技·单片机·汽车
记录无知岁月9 小时前
【STM32】HAL库常用外设使用速查
stm32·单片机·cubemx
给点sun,就shine9 小时前
示波器入门
单片机·嵌入式硬件
panamera129 小时前
通信协议SPI、IIC、UART、CAN及编码
单片机·嵌入式硬件
MC_J9 小时前
Keil之在线调试,不用重启即可在线仿真
stm32·单片机