像素格式

一个像素点就相当于一个 RGB 小灯,通过控制 R、G、B 这三种颜色的亮度就可以显示出各种各样的色彩。那该如何控制 R、G、B 这三种颜色的显示亮度呢?一般一个 R、G、B 这三部分分别使用 8bit 的数据,那么一个像素点就是 8bit*3=24bit,也就是说一个像素点3 个字节,这种像素格式称为 RGB888。如果再加入 8bit 的 Alpha(透明)通道的话一个像素点就是 32bit,也就是 4 个字节,这种像素格式称为 ARGB8888。

一个像素点是 4 个字节,其中 bit31bit24 是 Alpha 通道,bit23bit16 是RED 通道,bit15bit14 是 GREEN 通道,bit7bit0 是 BLUE 通道。所以红色对应的值就是0X00FF0000,蓝色对应的值就是 0X000000FF,绿色对应的值为 0X0000FF00。通过调节 R、G、B的比例可以产生其它的颜色,比如0X00FFFF00就是黄色,0X00000000就是黑色,0X00FFFFFF就是白色。

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 也可以正常工作。

lcd显示过程

RGBLCD屏幕时序

行显示时序图片:

HSYNC:行同步信号,当此信号有效的话就表示开始显示新的一行数据,查阅所使用的LCD 数据手册可以知道此信号是低电平有效还是高电平有效,假设此时是低电平有效。
HSPW:有些地方也叫做 thp,是 HSYNC 信号宽度,也就是 HSYNC 信号持续时间。HSYNC信号不是一个脉冲,而是需要持续一段时间才是有效的,单位为 CLK。
HBP:有些地方叫做 thb,前面已经讲过了,术语叫做行同步信号后肩,单位是 CLK。
HOZVAL:有些地方叫做 thd,显示一行数据所需的时间,假如屏幕分辨率为 1024*600,那么 HOZVAL 就是 1024,单位为 CLK。
HFP:有些地方叫做 thf,术语叫做行同步信号前肩,单位是 CLK。当 HSYNC 信号发出以后,需要等待 HSPW+HBP 个 CLK 时间才会接收到真正有效的像素数据。当显示完一行数据以后需要等待 HFP 个 CLK 时间才能发出下一个 HSYNC 信号,所以显示一行所需要的时间就是:HSPW + HBP + HOZVAL + HFP。
一帧图像就是由很多个行组成的,

帧显示时序图片:

VSYNC:帧同步信号,当此信号有效的话就表示开始显示新的一帧数据,查阅所使用的
LCD 数据手册可以知道此信号是低电平有效还是高电平有效,假设此时是低电平有效。
VSPW:有些地方也叫做 tvp,是 VSYNC 信号宽度,也就是 VSYNC 信号持续时间,单位为 1 行的时间。
VBP:有些地方叫做 tvb,前面已经讲过了,术语叫做帧同步信号后肩,单位为 1 行的时间。
LINE:有些地方叫做 tvd,显示一帧有效数据所需的时间,假如屏幕分辨率为 1024*600,那么 LINE 就是 600 行的时间。
VFP:有些地方叫做 tvf,前面已经讲过了,术语叫做帧同步信号前肩,单位为 1 行的时间。显示一帧所需要的时间就是:VSPW+VBP+LINE+VFP 个行时间

最终的计算公式:
T = (VSPW+VBP+LINE+VFP) * (HSPW + HBP + HOZVAL + HFP)

4.3寸屏幕参数:

显示一帧图像所要的时钟数为

= (VSPW+VBP+LINE+VFP) * (HSPW + HBP + HOZVAL + HFP)

=(480+3+32+13)*(48+88+800+40)=515328

显示一帧图像需要515328个时钟数,那么显示60帧就是:515328 * 60 = 30,919,680≈31M,所以像素时钟就是 31MHz。

①、此部分是一个选择器,用于选择哪个 PLL 可以作为 LCDIF 时钟源,由寄存器CCM_CSCDR2 的位 LCDIF1_PRE_CLK_SEL(bit17:15)来决定,LCDIF1_PRE_CLK_SEL 选择设置如表

时钟源
0 PLL2 作为 LCDIF 的时钟源。
1 PLL3_PFD3 作为 LCDIF 的时钟源。
2 PLL5 作为 LCDIF 的时钟源。
3 PLL2_PFD0 作为 LCDIF 的时钟源。
4 PLL2_PFD1 作为 LCDIF 的时钟源。
5 PLL3_PFD1 作为 LCDIF 的时钟源。

②、此部分是 LCDIF 时钟的预分频器,由寄存器 CCM_CSCDR2 的位 LCDIF1_PRED 来决定预分频值。可设置值为 07,分别对应 18 分频。
③、此部分进一步分频,由寄存器 CBCMR 的位 LCDIF1_PODF 来决定分频值。可设置值为 07,分别对应 18 分频。
④、此部分是一个选择器,选择 LCDIF 最终的根时钟,由寄存器 CSCDR2 的位LCDIF1_CLK_SEL 决定,LCDIF1_CLK_SEL 选择设置如表

时钟源
0 前面复用器出来的时钟,也就是前面 PLL5 出来的时钟作
为 LCDIF 的根时钟。
1 ipp_di0_clk 作为 LCDIF 的根时钟。
2 ipp_di1_clk 作为 LCDIF 的根时钟。
3 ldb_di0_clk 作为 LCDIF 的根时钟。
4 ldb_di1_clk 作为 LCDIF 的根时钟。

定选择 PLL5 出来的那一路时钟作为 LCDIF 的根时钟,因此 LCDIF1_CLK_SEL 设置为 0。LCDIF 既然选择了 PLL5 作为时钟源,那么还需要初始化 PLL5,LCDIF 的时钟是由PLL5 和接口时钟图片②、③这两个分频值决定的,

PLL5_CLK = OSC24M * (loopDivider + (denominator / numerator)) / postDivider

设置为24*(1+7/8)/1=45

②和③进一步分频,设置②中为 1 分频,也就是寄存器 CCM_CSCDR2 的位 LCDIF1_PRED(bit14:12)为 0。设置③中为 5 分频,就是寄存器CCM_CBCMR 的位 LCDIF1_PODF(bit25:23)为 4。设置好以后最终进入到 LCDIF 的时钟频率就是:45/1/5 =9MHz,这就是我们需要的像素时钟频率。

显存

如果采用 ARGB8888 格式的话一个像素需要 4 个字节的内存来存放像素数据,那么 1024600 分辨率就需要 1024600*4=2457600B≈2.4MB 内存。但是 RGB LCD 内部是没有内存的,所以就需要在开发板上的 DDR3 中分出一段内存作为 RGB LCD 屏幕的显存,我们如果要在屏幕上显示什么图像的话直接操作这部分显存即可。

eLCDIF 接口

eLCDIF 是 I.MX6U 自带的液晶屏幕接口,用于连接 RGB LCD 接口的屏幕,eLCDIF 接口特性如下:

①、支持 RGB LCD 的 DE 模式。
②、支持 VSYNC 模式以实现高速数据传输。
③、支持 ITU-R BT.656 格式的 4:2:2 的 YCbCr 数字视频,并且将其转换为模拟 TV 信号。
④、支持 8/16/18/24/32 位 LCD。

eLCDIF 支持三种接口:MPU 接口、VSYNC 接口和 DOTCLK 接口,这三种接口区别如下:

①MPU 接口用于在 I.MX6U 和 LCD 屏幕直接传输数据和命令,这个接口用于 6080/8080 接口的 LCD 屏幕,关于 MPU 接口的详细信息以及时序参考《I.MX6ULL 参考手册》第 2150 页的“34.4.6MPU Interface”小节

⑤VSYNC 接口时序和 MPU 接口时序基本一样,只是多了 VSYNC 信号来作为帧同步,当LCDIF_CTRL 的位 VSYNC_MODE 为 1 的时候此接口使能。关于 VSYNC 接口的详细信息请参考《I.MX6ULL 参考手册》第 2152 页的“34.4.7 VSYNC Interface”小节。

③DOTCLK 接口就是用来连接 RGB LCD 接口屏幕的, 它包括 VSYNC、HSYNC、DOTCLK和 ENABLE(可选的)这四个信号,这样的接口通常被称为 RGB 接口。

配置寄存器

配置eLCDIF接口的寄存器

SFTRST(bit31):eLCDIF 软复位控制位,当此位为 1 的话就会强制复位 LCD。
CLKGATE(bit30):正常运行模式下,此位必须为 0!如果此位为 1 的话时钟就不会进入到LCDIF。
BYPASS_COUNT(bit19):如果要工作在 DOTCLK 模式的话就此位必须为 1。
VSYNC_MODE(bit18):此位为 1 的话 LCDIF 工作在 VSYNC 接口模式。
DOTCLK_MODE(bit17):此位为 1 的话 LCDIF 工作在 DOTCLK 接口模式。
INPUT_DATA_SWIZZLE(bit15:14):输入数据字节交换设置,此位为 0 的话不交换字节也就是小端模式;为 1 的话交换所有字节,也就是大端模式;为 2 的话半字交换;为 3 的话在每个半字内进行字节交换。本章我们设置为 0,也就是不使用字节交换。
CSC_DATA_SWIZZLE(bit13:12) : CSC 数 据 字 节 交 换 设 置 , 交 换 方 式 和INPUT_DATA_SWIZZLE 一样,本章设置为 0,不使用字节交换。
LCD_DATABUS_WIDTH(bit11:10):LCD 数据总线宽度,为 0 的话总线宽度为 16 位;为1 的话总线宽度为 8 位;为 2 的话总线宽度为 18 位;为 3 的话总线宽度为 24 位。本章我们使用 24 位总线宽度。WORD_LENGTH(bit9:8):输入的数据格式,也就是像素数据宽度,为 0 的话每个像素 16位;为 1 的话每个像素 8 位;为 2 的话每个像素 18 位;为 3 的话每个像素 24 位。
MASTER(bit5):为 1 的话设置 eLCDIF 工作在主模式。
DATA_FORMAT_16_BIT(bit3):当此位为 1 并且 WORD_LENGTH 为 0 的时候像素格式为 ARGB555,当此位为 0 并且 WORD_LENGTH 为 0 的时候像素格式为 RGB565。
DATA_FORMAT_18_BIT(bit2):只有当 WORD_LENGTH 为 2 的时候此位才有效,此位为 0 的话低 18 位有效,像素格式为 RGB666,高 14 位数据无效。当此位为 1 的话高 18 位有效,像素格式依旧是 RGB666,但是低 14 位数据无效。
DATA_FORMAT_24_BIT(bit1):只有当 WORD_LENGTH 为 3 的时候此位才有效,为 0 的时候表示全部的 24 位数据都有效。为 1 的话实际输入的数据有效位只有 18 位,虽然输入的是24 位数据,但是每个颜色通道的高 2 位数据会被丢弃掉。
RUN(bit0):eLCDIF 接口运行控制位,当此位为 1 的话 eLCDIF 接口就开始传输数据,也就是 eLCDIF 的使能位。

接 下 来 看 一 下 寄 存 器 LCDIF_CTRL1 , 此 寄 存 器 我 们 只 用 到 位BYTE_PACKING_FORMAT(bit19:16),此位用来决定在 32 位的数据中哪些字节的数据有效,默认值为 0XF,也就是所有的字节有效,当为 0 的话表示所有的字节都无效。如果显示的数据是24 位(ARGB 格式,但是 A 通道不传输)的话就设置此位为 0X7。

接下来看一下寄存器 LCDIF_TRANSFER_COUNT,这个寄存器用来设置所连接的 RGB LCD 屏幕分辨率大小,寄存器LCDIF_TRANSFER_COUNT 分为两部分,高16位和低16位,高16位是V_COUNT,是 LCD 的垂直分辨率。低 16 位是 H_COUNT,是 LCD 的水平分辨率。如果 LCD 分辨率为480*272 的话,那么 V_COUNT 就是 272,H_COUNT 就是 480。

接下来看一下寄存器 LCDIF_VDCTRL0,这个寄存器是 VSYNC 和 DOTCLK 模式控制寄存器 0,

VSYNC_OEB(bit29):VSYNC 信号方向控制位,为 0 的话 VSYNC 是输出,为 1 的话VSYNC 是输入。
ENABLE_PRESENT(bit28):EBABLE 数据线使能位,也就是 DE 数据线。为 1 的话使能ENABLE 数据线,为 0 的话关闭 ENABLE 数据线。
VSYNC_POL(bit27):VSYNC 数据线极性设置位,为 0 的话 VSYNC 低电平有效,为 1 的话 VSYNC 高电平有效,要根据所使用的 LCD 数据手册来设置。
HSYNC_POL(bit26):HSYNC 数据线极性设置位,为 0 的话 HSYNC 低电平有效,为 1 的话 HSYNC 高电平有效,要根据所使用的 LCD 数据手册来设置。
DOTCLK_POL(bit25):DOTCLK 数据线(像素时钟线 CLK) 极性设置位,为 0 的话下降沿锁存数据,上升沿捕获数据,为 1 的话相反,要根据所使用的 LCD 数据手册来设置。
ENABLE_POL(bit24):EANBLE 数据线极性设置位,为 0 的话低电平有效,为 1 的话高电平有效。
VSYNC_PERIOD_UNIT(bit21):VSYNC 信号周期单位,为 0 的话 VSYNC 周期单位为像素时钟。为 1 的话 VSYNC 周期单位是水平行,如果使用 DOTCLK 模式话就要设置为 1。
VSYNC_PULSE_WIDTH_UNIT(bit20) : VSYNC 信 号 脉 冲 宽 度 单 位 , 和VSYNC_PERIOD_UNUT 一样,如果使用 DOTCLK 模式的话要设置为 1。
VSYNC_PULSE_WIDTH(bit17:0):VSPW 参数设置位。

看一下寄存器 LCDIF_VDCTRL1,这个寄存器是 VSYNC 和 DOTCLK 模式控制寄存器 1,此寄存器只有一个功能用来设置 VSYNC 总周期,就是:屏幕高度+VSPW+VBP+VFP。

接下来看一下寄存器 LCDIF_VDCTRL2,这个寄存器分为高 16 位和低 16 位两部分,高 16位是HSYNC_PULSE_WIDTH,用来设置 HSYNC 信号宽度,也就是 HSPW。低 16 位是HSYNC_PERIOD,设置 HSYNC 总周期,就是:屏幕宽度+HSPW+HBP+HFP。

看一下寄存器 LCDIF_VDCTRL3,HORIZONTAL_WAIT_CNT(bit27:16):此位用于 DOTCLK 模式,用于设置 HSYNC 信号产生到有效数据产生之间的时间,也就是 HSPW+HBP。
VERTICAL_WAIR_CNT(bit15:0):和 HORIZONTAL_WAIT_CNT 一样,只是此位用于VSYNC 信号,也就是 VSPW+VBP。

接下来看一下寄存器 LCDIF_VDCTRL4,寄存器 LCDIF_VDCTRL4 用到的重要位如下:
SYNC_SIGNALS_ON(bit18):同步信号使能位,设置为 1 的话使能 VSYNC、HSYNC、DOTCLK 这些信号。
DOTCLK_H_VALID_DATA_CNT(bit15:0):设置 LCD 的宽度,也就是水平像素数量。最后在看一下寄存器 LCDIF_CUR_BUF 和 LCDIF_NEXT_BUF,这两个寄存器分别为当前帧和下一帧缓冲区,也就是 LCD 显存。一般这两个寄存器保存同一个地址,也就是划分给 LCD的显存首地址。

驱动屏幕的步骤

配置步骤如下:
1、初始化 LCD 所使用的 IO
首先肯定是初始化 LCD 所示使用的 IO,将其复用为 eLCDIF 接口 IO。
2、设置 LCD 的像素时钟
查阅所使用的 LCD 屏幕数据手册,或者自己计算出的时钟像素,然后设置 CCM 相应的寄存器。
3、配置 eLCDIF 接口
设置 LCDIF 的寄存器 CTRL、CTRL1、TRANSFER_COUNT、VDCTRL0~4、CUR_BUF 和NEXT_BUF。根据 LCD 的数据手册设置相应的参数。
4、编写 API 函数
驱动 LCD 屏幕的目的就是显示内容,所以需要编写一些基本的 API 函数,比如画点、画线、画圆函数,字符串显示函数等。