LCD驱动开发:行场扫描与时序

一、基本显示原理

分辨率与像素

分辨率:800 × 480,表示屏幕由 800 列 × 480 行的像素点组成。

每个像素点由 红(R)、绿(G)、蓝(B) 三个子像素构成,通常采用 RGB888 格式(每通道 8 位),共 24 位颜色深度。

二、接口通信方式

i.MX6ULL 通过 eLCDIF(Enhanced LCD Interface) 控制器与 LCD 屏幕进行通信,采用 单工并行同步传输方式:

信号类型 数量 功能说明
数据线 (data) 24 根 传输 RGB 数据(8r+8g+8b),即每个像素 24 位
控制线 4 根 包括 DE、HSYNC、VSYNC、PCLK
地址总线 32 位 用于 DMA 地址映射(可选)
片选/控制总线 1 根 (nRST) 复位或使能控制

三、核心时许信号

LCD 的刷新过程依赖于精确的时钟和同步信号。

1. PCLK(Pixel Clock,像素时钟)
  • 是整个系统的基准时钟;
  • 每个 PCLK 周期传输一位数据;
2. DE(Data Enable,数据有效)
  • 表示当前数据是否有效;
  • 在 HSYNC 和 VSYNC 有效期间,DE 为高电平时,数据才被采样;
3. HSYNC(Horizontal Sync,水平同步)
  • 控制每一行的开始;
  • 低电平有效(负脉冲),持续时间固定;
  • 用于同步行扫描。
4. VSYNC(Vertical Sync,垂直同步)
  • 控制每一帧的开始;
  • 低电平有效,周期长;
  • 用于同步场扫描。

四、核心机制

1.行扫描(Horizontal Scan)

工作原理:
  • 制器从左到右输出一行像素数据;
  • 每个 PCLK 周期传输一个像素;
  • 行结束时发出 HSYNC 脉冲,准备下一行。
参数 含义
HSPW 水平同步脉宽 40
HBP 水平后沿 88
HFP 水平前沿 48
总行周期 HBP + 800 + HFP + HSPW 976 像素

2.场扫描

工作原理:
在完成全部 480 行后,发出 VSYNC 脉冲,标志一帧结束;
控制帧与帧之间的切换,决定刷新率(如 60Hz)。
参数 含义
VSPW 垂直同步脉宽 3
VBP 垂直后沿 32
VFP 垂直前沿 13
总场周期 VBP + 480 + VFP + VSPW 528 行

行场时序图

五、LCD代码实现

1. 引脚配置(lcd_pad_init())

将 GPIO 复用为 eLCDIF 功能,配置 24 根 RGB 数据线及 HSYNC/VSYNC/DE/PCLK 控制信号。

设置背光控制引脚为输出高电平,并配置高速电气特性(如驱动强度和压摆率)。

cs 复制代码
void lcd_pad_init(void)
{
    //复用功能
    IOMUXC_SetPinMux(IOMUXC_LCD_DATA00_LCDIF_DATA00, 0);
    ...
    IOMUXC_SetPinMux(IOMUXC_LCD_CLK_LCDIF_CLK, 0);
    IOMUXC_SetPinMux(IOMUXC_LCD_HSYNC_LCDIF_HSYNC, 0);
    IOMUXC_SetPinMux(IOMUXC_LCD_VSYNC_LCDIF_VSYNC, 0);
    IOMUXC_SetPinMux(IOMUXC_LCD_ENABLE_LCDIF_ENABLE, 0);
    IOMUXC_SetPinMux(IOMUXC_GPIO1_IO08_GPIO1_IO08, 0);

    //电气特性
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA00_LCDIF_DATA00, 0xB9);
	...
    IOMUXC_SetPinConfig(IOMUXC_LCD_CLK_LCDIF_CLK, 0xB9);
    IOMUXC_SetPinConfig(IOMUXC_LCD_HSYNC_LCDIF_HSYNC, 0xB9);
    IOMUXC_SetPinConfig(IOMUXC_LCD_VSYNC_LCDIF_VSYNC, 0xB9);
    IOMUXC_SetPinConfig(IOMUXC_LCD_ENABLE_LCDIF_ENABLE, 0xB9);
    IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO08_GPIO1_IO08, 0xB9);

    //将背光引脚输出高电平
    GPIO1->GDIR |= (1 << 8);
    GPIO1->DR |= (1 << 8);
}

2.时钟配置(lcd_clk_init())

启用 PLL5(VIDEO PLL)作为 LCD 像素时钟源,并通过分频器生成目标 PCLK(如 ~33 MHz)。

配置时钟选择寄存器,将 LCDIF 时钟路径切换至 PLL5 输出。

cs 复制代码
void lcd_clk_init(void)
{
    //1. PLL5 output frequency = Fref(24M) * (DIV_SELECT(D(31)) + NUM(0)/DENOM(1))
    CCM_ANALOG->PLL_VIDEO_NUM = 0;
    CCM_ANALOG->PLL_VIDEO_DENOM = 1;
    unsigned int t = CCM_ANALOG->PLL_VIDEO;
    t &= ~(3 << 19);
    t |= (2 << 19);

    t &= ~(0x7F << 0);
    t |= (31 << 0);
    CCM_ANALOG->PLL_VIDEO = t;  
    CCM_ANALOG->PLL_VIDEO |= (1 << 13);     //使能PLL5
    CCM_ANALOG->MISC2 &= ~(3 << 30); //CCM_ANALOG_MISC2n[VIDEO_DIV]
    
    t = CCM->CSCDR2;
    //t &= ~(7 << 15);
    t |= (2 << 15);     //CSCDR2[LCDIF1_PRE_CLK_SEL]
    t &= ~(7 << 12);
    t |= (3 << 12);     //CSCDR2[LCDIF1_PRED

    t &= ~(7 << 9);     //CSCDR2[LCDIF1_CLK_SEL]
    CCM->CSCDR2 = t;
 
    CCM->CBCMR &= ~(7 << 23);   //CBCMR[LCDIF1_PODF]
    CCM->CBCMR |= (5 << 23);
}

3. LCD 控制器配置(lcd_init())

填充分辨率与时序参数(HSPW/HBP/HFP/VSPW/VBP/VFP),并写入 eLCDIF 寄存器。

设置帧缓冲地址(CUR_BUF/NEXT_BUF),启用控制器并启动显示输出。

cs 复制代码
void lcd_init(void)
{
    //IOMUXC
    lcd_pad_init();
    //模块复位
    reset_lcd();
    //clock PLL5 ->31M
    lcd_clk_init();
    delay_ms(50);
    lcd_dev.width = 800;
    lcd_dev.height = 480;
    lcd_dev.pix_size = 4;
    lcd_dev.hspw = 48;
    lcd_dev.hbp = 88;
    lcd_dev.hfp = 40;
    lcd_dev.vspw = 3;
    lcd_dev.vbp = 32;
    lcd_dev.vfp = 13;
    lcd_dev.frame_addr = _FRAME_RAM_ADDRESS;
    lcd_dev.fore_color = 0x00FF0000;
    lcd_dev.back_color = 0xFFFFFFFF;

    LCDIF->CTRL |= (1 << 19) | (1 << 17) | (3 << 10) | (3 << 8) | (1 << 5);
    LCDIF->CTRL1 &= ~(0xF << 16);
    LCDIF->CTRL1 |= (0x7 << 16);

    LCDIF->TRANSFER_COUNT = (lcd_dev.height << 16) | (lcd_dev.width << 0);
    LCDIF->CUR_BUF = lcd_dev.frame_addr;
    LCDIF->NEXT_BUF = lcd_dev.frame_addr;

    LCDIF->VDCTRL0 = (1 << 28) | (1 << 24) | (1 << 21) | (1 << 20) | (lcd_dev.vspw << 0);
    LCDIF->VDCTRL1 = lcd_dev.height + lcd_dev.vspw + lcd_dev.vbp + lcd_dev.vfp;
    LCDIF->VDCTRL2 = (lcd_dev.hspw << 18) | (lcd_dev.width + lcd_dev.hspw + lcd_dev.hbp + lcd_dev.hfp);
    LCDIF->VDCTRL3 = ((lcd_dev.hspw + lcd_dev.hbp) << 16) | ((lcd_dev.vspw + lcd_dev.vbp) << 0);
    LCDIF->VDCTRL4 = (1 << 18) | (lcd_dev.width << 0);

    LCDIF->CTRL |= (1 << 0);     //run

    delay_ms(50);

    screen_clear(0xFFFFFFFF);
}
相关推荐
世微 如初14 天前
AP5125大功率LED恒流驱动实战:地摊灯项目从原理图到调试笔记
驱动开发·芯片·led电源驱动·降压恒流ic
ScilogyHunter14 天前
Zephyr串口驱动开发及构建完全指南
驱动开发·uart·zephyr
_Emma_14 天前
【DRM&Graphic】Linux图形与显示框架
linux·驱动开发·图形渲染·显示器
董厂长14 天前
Loop Engineering:停止手动提示,开始设计自动提示的系统
大数据·人工智能·驱动开发·llm
Saniffer_SH15 天前
【高清视频】Gen6 服务器还没到,Gen6 SSD 怎么测?Emily 现场演示三种测试环境
人工智能·驱动开发·测试工具·缓存·fpga开发·计算机外设·压力测试
暮云星影15 天前
全志linux开发屏幕适配(二)`HDMI`驱动适配说明
linux·arm开发·驱动开发
charlie11451419115 天前
嵌入式Linux驱动开发——从轮询到中断
linux·开发语言·驱动开发·嵌入式
暮云星影15 天前
瑞芯微rk3566开发FIT Secure Boot
linux·arm开发·驱动开发·安全
暮云星影15 天前
全志linux开发 USB接口设置
linux·arm开发·驱动开发
sukalot15 天前
windows显示驱动开发-CCD DDI的其它技术
windows·驱动开发