☰
ARM裸机开发-LCD
2026/10/7 10:06:15 网站建设 项目流程

目录

一.背景

像素时钟

二.实现

1.初始化

2.配置时钟

CCM_ANALOG->PLL_VIDEO

LCDIF->CTRL

CTRL1

TRANSEFR_COUNT

CUR_BUF,NEXT_BUF

VDCTRL0

VDCTRL1

VDCTRL2

VDCTRL3

VDCTRL4


一.背景

LCD 全称是 Liquid Crystal Display,也就是液晶显示器,是现在最常用到的显示器,手机、
电脑、各种人机交互设备等基本都用到了 LCD,最常见就是手机和电脑显示器了。这里需要注意的是,我们所提及的LCD不包括触摸功能,触摸功能是通过另外的设备实现的,LCD在这里只是输出设备。
百度百科对于 LCD 的原理解释如下:LCD 的构造是在两片平行的玻璃基板当中放置液晶盒,下基板玻璃上设置 TFT(薄膜晶体管),上基板玻璃上设置彩色滤光片,通过 TFT 上的信号与电压改变来控制液晶分子的转动方向,从而达到控制每个像素点偏振光出射与否而达到显示目的。我们现在要在 I.MX6U-ALPHA 开发板上使用 LCD,所以不需要去研究 LCD 的具体实现原理,我们只需要从使用的角度去关注 LCD 的几个重要点:
分辨率:提起 LCD 显示器,我们都会听到 720P、1080P、2K 或 4K 这样的字眼,这个就是
LCD 显示器分辨率。LCD 显示器都是由一个一个的像素点组成,像素点就类似一个灯(在 OLED 显示器中,像素点就是一个小灯),这个小灯是 RGB 灯,也就是由 R(红色)、G(绿色)和 B(蓝色)这三种颜色组
成的,而 RGB 就是光的三原色。1080P 的意思就是一个 LCD 屏幕上的像素数量是1920*1080 个,也就是这个屏幕一列 1080 个像素点,一共 1920 列
LCD 屏幕或者说显示器有很多种接口,比如在显示器上常见的 VGA、HDMI、DP 等等,但是
I.MX6U-Mini开发板不支持这些接口。I.MX6U-Mini 支持RGB接口的LCD,RGBLCD接口的信号线如下表:
R[7:0]、G[7:0]和 B[7:0]这 24 根是数据线,DE、VSYNC、HSYNC 和 PCLK 这四根是控制
信号线。RGB LCD 一般有两种驱动模式:DE 模式和 HV 模式,这两个模式的区别是 DE 模式需要用到DE 信号线,而 HV 模式不需要用到 DE 信号线,在 DE模式下是可以不需要 HSYNC 信号线的,即使不接 HSYNC 信号线 LCD 也可以正常工作

屏幕分辨率:横向像素点个数*纵向像素点个数(800 * 480)
1920 * 1080
1080P
2K 2560 * 1440
屏幕尺寸:inch "英寸,左上角到右下角之间的距离1" = 2.54cm
6.22" 4.3"
1920 * 1080
分辨率相同,尺寸越小,图像显示效果越好
尺寸相同,分辨率越高,图像显示效果越好
像素点颜色:
RGB888:每个像素点占3个字节8bit面板1670万色
RGB565:每个像素点占2个字节
ARGB:每个像素点占4个字节
RGB101010: 10bit面板10亿色 贵 视频剪辑8抖10bit
显存:专门存放图像数据的内存空间
800 * 480 * 4 = 1.5M(512MB 0x80000000 - 0xA0000000)
显存:0x89000000
PCLK: Pixel Clock像素时钟信号线。同步像素点发送的时间间隔,上升或下降沿采样 ,取决于手册
HSYNC:Horizontal Sync行/水平同步时钟信号线。同步每一行发送的时间间隔
VSYNC:Vertical Sync帧/垂直同步时钟信号线。同步每一帧图像的时间间隔,从头开始
DE:Data Enable数据使能信号线
imx6ull的LCD屏刷新率为60HZ
第一行重定向输出运行结果,第二行打开。

像素时钟

我们使用的alpha开发板搭载了一块由正点原子生产的RGB LCD,型号为ATK4384,分辨率为
800*480。其时间参数如下:
按照之前的推导,显示一帧图像所需要的时钟数是:
(VSPW+VBP+LINE+VFP) * (HSPW + HBP + HOZVAL + HFP)= (3 + 32 + 480 + 13) * (48 + 88 + 800 +40) =。显示一帧图像需要515328个时钟数,那么显示60帧就是:515328 * 60 = 30,919,680≈31M,所以像素时钟就是 31MHz。

二.实现

1.初始化

// 1. 设置lcd引脚复用功能 IOMUXC_SetPinMux(IOMUXC_LCD_DATA00_LCDIF_DATA00, 0); IOMUXC_SetPinMux(IOMUXC_LCD_DATA01_LCDIF_DATA01, 0); IOMUXC_SetPinMux(IOMUXC_LCD_DATA02_LCDIF_DATA02, 0); ... IOMUXC_SetPinMux(IOMUXC_LCD_CLK_LCDIF_CLK, 0); // pclk IOMUXC_SetPinMux(IOMUXC_LCD_HSYNC_LCDIF_HSYNC, 0); // HSYNC IOMUXC_SetPinMux(IOMUXC_LCD_VSYNC_LCDIF_VSYNC, 0); // VSYNC IOMUXC_SetPinMux(IOMUXC_LCD_ENABLE_LCDIF_ENABLE, 0); // DE IOMUXC_SetPinMux(IOMUXC_GPIO1_IO08_GPIO1_IO08, 0); // blt_pwm

为什么硬件叫blt_pwm,软件却配成 GPIO?

之所以注释写着blt_pwm,是因为在硬件原理图上,这个引脚确实连接到了 LCD 的背光控制电路。硬件工程师给它起名叫“背光 PWM”,是因为它最终要控制背光。但是,控制背光有两种常见做法:

  • 硬件 PWM 控制(ALT0 模式):把引脚配置成PWM1_OUT,让芯片内部的 PWM 模块输出连续方波,通过改变占空比来无级调节背光亮度(比如从 10% 调到 100%)。

  • 软件 GPIO 控制(ALT5 模式,即老师的做法):把引脚配置成普通 GPIO。软件只能输出0(低电平,背光灭)或1(高电平,背光亮)。

    • 如果只是需要开灯/关灯,配置成 GPIO 最简单。

    • 如果想调节亮度但不想用硬件 PWM,可以在 Linux 驱动里写个定时器,让 GPIO 不断拉高拉低,模拟 PWM 波形(软件模拟 PWM)。

// 2. 设置lcd引脚电气属性 IOMUXC_SetPinConfig(IOMUXC_LCD_DATA00_LCDIF_DATA00, 0xB9); IOMUXC_SetPinConfig(IOMUXC_LCD_DATA01_LCDIF_DATA01, 0xB9); IOMUXC_SetPinConfig(IOMUXC_LCD_DATA02_LCDIF_DATA02, 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);

一共设置24个数据引脚(R,G,B各8个)

// 3. 配置pwm引脚 GPIO_Type_t t = { .direction = gpio_output, .default_value = 1 }; gpio_init(GPIO1, 8, &t); gpio_set_value(GPIO1, 8, 1);

2.配置时钟

要配置31MHZ时钟, 先通过倍频让PLL5输出1008MHZ,再通过两个预分频器除以4和8输出为31.5MHZ

可设置NUM为0,DENOM为1,DIV_SELECT为42即可将24MHZ倍频为1008MHZ

预分频器默认为1分频即可。

再通过CSDR2寄存器选通PLL5时钟且配置第一个分频因子为4,通过CBCMR配置第二个分频因子为8。

CCM_ANALOG->PLL_VIDEO

是 i.MX6UL 芯片内部视频锁相环(Video PLL)的主控制寄存器

// lcd时钟初始化 void lcd_clock_init(void) { // BYPASS CCM_ANALOG->PLL_VIDEO |= (1 << 16); // Powerdown PLL CCM_ANALOG->PLL_VIDEO |= (1 << 12);//写1关闭 CCM_ANALOG->PLL_VIDEO_NUM = 0; CCM_ANALOG->PLL_VIDEO_DENOM = 1; // 设置42倍频 CCM_ANALOG->PLL_VIDEO &= ~(0x7F << 0); CCM_ANALOG->PLL_VIDEO |= (42 << 0); // 设置1分频 CCM_ANALOG->PLL_VIDEO &= ~(3 << 19); CCM_ANALOG->PLL_VIDEO |= (1 << 20); // poweron PLL CCM_ANALOG->PLL_VIDEO &= ~(1 << 12);//写0开启 // enable PLL5 output CCM_ANALOG->PLL_VIDEO |= (1 << 13); // 轮询等待时钟频率稳定 while ((CCM_ANALOG->PLL_VIDEO & (1 << 31)) == 0); // 切回 PLL5 CCM_ANALOG->PLL_VIDEO &= ~(1 << 16); // 选通门 pll5 + 4分频 unsigned int t = CCM->CSCDR2; t &= ~(7 << 15); t |= (1 << 16); t &= ~(7 << 12); t |= (3 << 12); t &= ~(7 << 9); CCM->CSCDR2 = t; // 8分频 CCM->CBCMR |= (7 << 23); }

lcd寄存器

LCDIF->CTRL

CTRL1

TRANSEFR_COUNT

CUR_BUF,NEXT_BUF

存放显存地址

VDCTRL0

VDCTRL1

VDCTRL2

VDCTRL3

VDCTRL4

18位,让VSYNC/HSYNC/DOTCLK等工作,

// lcd参数配置 lcd_dev.width = 800; lcd_dev.height = 480; lcd_dev.hspw = 48; lcd_dev.hfp = 40; lcd_dev.hbp = 88; lcd_dev.vspw = 3; lcd_dev.vfp = 13; lcd_dev.vbp = 32; lcd_dev.pix_size = 4; lcd_dev.frame_buffer = LCD_FRAMEBUF_ADDR; lcd_dev.fore_color = 0x00FF0000; lcd_dev.back_color = 0x00FFFFFF; // LCD寄存器 LCDIF->CTRL |= (1 << 19) | (1 << 17) | (3 << 10) | (3 << 8) | (1 << 5); LCDIF->CTRL1 = (7 << 16); LCDIF->TRANSFER_COUNT = (lcd_dev.height << 16) | (lcd_dev.width << 0); LCDIF->CUR_BUF = lcd_dev.frame_buffer; LCDIF->NEXT_BUF = lcd_dev.frame_buffer; LCDIF->VDCTRL0 |= (1 << 28) | (1 << 24) | (1 << 21) | (1 << 20) | (lcd_dev.vspw << 0); LCDIF->VDCTRL1 = (lcd_dev.height + lcd_dev.vfp + lcd_dev.vbp + lcd_dev.vspw); LCDIF->VDCTRL2 = (lcd_dev.hspw << 18) | (lcd_dev.width + lcd_dev.hfp + lcd_dev.hbp + lcd_dev.hspw); 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);//最后使能

注意,CTRL1位要用=,因为要置0x0111,即7,而16-19位默认为0x1111,所以若使用|=则19位仍为1.

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询