LCD液晶屏也是我们常用的外设,通过LCD我们可以方便的和设备进行人机交互,i.MX6 ULL提供了eLCDIF的接口。eLCDIF的全称是Enhanced LCD Interface,即增强型LCD接口。
关于LCD我们需要了解下面的几个概念:
1.显示分辨率
显示分辨率(屏幕分辨率)是屏幕图像的精密度,是指显示器所能显示的像素有多少。由于屏幕上的点、线和面都是由像素组成的,显示器可显示的像素越多,画面就越精细,同样的屏幕区域内能显示的信息也越多,所以分辨率是个非常重要的性能指标。可以把整个图像想象成是一个大型的棋盘,而分辨率的表示方式就是所有经线和纬线交叉点的数目。显示分辨率一定的情况下,显示屏越小图像越清晰,反之,显示屏大小固定时,显示分辨率越高图像越清晰。
描述分辨率的单位有:dpi(点每英寸)、lpi(线每英寸)、ppi(像素每英寸)和PPD(PPPixels Per Degree 角分辨率,像素每度)。
我们常说的720P、1080P、2K、4K就是指屏幕的分辨率。
2.像素格式
上面讲了,分辨率由若干个像素点组成,像素点越多,显示的效果就会越好。下面我们来看下像素点的组成。我们看到屏幕显示的五颜六色的图像,实际上是由R(红)、G(绿)、B(蓝)三种颜色组合而成的。一个像素点分别由一个R(红),一个G(绿),一个B(蓝)组成,R、G、B分别使用8bit的数据表示。相当于一个像素点占24bit(8bit*3),也就是3个字节,这种格式成为RGB888。如果在加入一个8bit的透明通道,一个像素点就会占用4个字节了,这种格式成为ARGB888,我们在本例程中将会使用ARGB888这种像素格式。
3.LCD屏幕的接口
LCD显示器的屏幕接口有很多种,比如RGB接口,LVDS接口,MIPI接口,EDP接口,VGA接口,DVI接口,HDMI接口等等。I.MX6 ULL处理器支持RGB接口,外部接口如图 1所示:
从上图可以看到RGB一共有24根数据线(分别对应RGB,每种8bit)。LCD_ENABLE、LCD_VSYNC、LCD_HSYNC、LCD_CLK这四个是控制信号。RGB一般有两种工作模式DE模式和HV模式。DE模式需要用到DE引脚(LCD_ENABLE),HV模式不需要使用DE(LCD_ENABLE)引脚。
4.LCD显示时间参数
首先我们来看一个LCD的分辨率是320x240的显示扫描图,如图 2所示:
我们看从上图可以看到在显示一幅图像的时候先是从左到右,扫描第一行的320个像素点,然后在从上到下,扫描第二行,第三行,直至最后一行。
在上图中的HSYNC是水平同步信号,当产生此信号的时候表示开始显示新的一行。
VSYNC是垂直同步信号,当产生此信号的时候表示要显示一幅图像。
HBP称作水平后沿,在每行或每列的象素数据开始输出时要插入的象素时钟周期数。
HFP称作水平前沿,在每行或每列的象素结束到LCD 行时钟输出脉冲之间的象素时钟数。
VBP称作垂直后沿,在垂直同步周期之后帧开头时的无效行数。
VFP称作垂直前沿,本帧数据输出结束到下一帧垂直同步周期开始之前的无效行数。
5.LCD时钟
i.MX6 ULL的eLCDIF接口时钟图,如图 3所示:
标识1是时钟源选择,由寄存器CCM_CSCDR2的LCDIF1_PRE_CLK_SEL(bit17:bit15)来选择,可选择的时钟源如图 4所示:
我们在12章i.MX6 ULL时钟章节说过有个专用的PLL5给VIDEO使用,所以参照上图选择PLL5作为时钟源,bit17:bit15的值是010,也就是十进制的2。
标识2是时钟的分频器,由寄存器CCM_CSCDR2的LCDIF1_PRED(bit14:bit12)决定,对应的分频值如图 5所示:
标识3是进一步分频,由寄存器CCM_CBCMR寄存器的LCDIF1_PODF(bit25:bit23)决定,对应的分频值如图 6所示:
标识4是选择最终的时钟源,由寄存器CCM_CSCDR2的LCDIF1_CLK_SEL(bit11:bit9)决定,取值图如图 7所示:
这里我们需要选择0(使用前面复用出来的时钟)。我们选择了PLL5作为时钟源,需要初始化视频相关的的PLL,与视频PLL频率设置有关的寄存器有四个: CCM_ANALOG_PLL_VIDEOn、CCM_ANALOG_PLL_VIDEO_NUM、CCM_ANALOG_PLL_VIDEO_DENOM、CCM_ANALOG_MISC2n。
视频PLL的时钟计算公式如下:
VIDEO PLL_CLK = OSC24M * (loopDivider + (denominator / numerator)) / postDivider
CCM_ANALOG_PLL_VIDEO_NUM和CCM_ANALOG_PLL_VIDEO_DENOM这两个寄存器是用于小数分频的,我们为了使用简单不使用小数分频,这两个寄存器可以设置成0。PLL5的之中公式可以简化为:
VIDEO PLL_CLK = OSC24M * loopDivider / postDivider
OSC24M是24MHz的晶振。然后是设置loopDivider和postDivider。
我们首先看一下CCM_ANALOG_PLL_VIDEOn寄存器,结构如图 8、图 9所示:
我们主要用到的位如下:
POST_DIV_SLECT(bit20:19):此位和CCM_ANALOG_CCMSC2 的VIDEO_DIV共同决定了postDivider的值。本例程我们设置成2(1分频)。
ENABLE(bit13):PLL时钟输出使能。
DIV_SELECT(bit6:0):这7位表示loopDivider的值,取值范围是27到54.我们的例程设置为32。
CCM_ANALOG_MISC2n的VIDEO_DIV(bit31:bit30)u寄存器CCM_ANALOG_PLL_VIDEOn的POST_DIV_SLECT(bit20:19)共同决定了postDivider,他们通过相乘的方式可以组合成2、4、8、16的分频值。我们设置CCM_ANALOG_MISC2n的VIDEO_DIV位0(1分频),CCM_ANALOG_PLL_VIDEOn的POST_DIV_SLECT我们设置的2(1分频),所以最终PLL的分频是1分频(postDivider=1),所以PLL的时钟是:
PLL = 24M * 32 / 1 = 768MHz
本例程我们使用的迅为电子的7寸RGB屏幕,该屏幕要求的RGB时钟是51.2MHz,所以我们按照PLL的需要先设置CCM_CSCDR2的LCDIF1_PRED为2(3分频),在通过设置CCM_CBCMR的LCDIF1_PODF为4(5分频),最终进入到LCDIF1的时钟是:768/3/3 = 51.2MHz。
6.分配显存
在前面讲像素格式的时候说过我们采用ARGB888的格式,那么一个像素需要占用4个字节,如果我们的屏幕分辨率是1024x600,那就有1024x600个像素点,每个像素点占用4个字节,那么一共需要1024x600x4≈2.4MB的内存空间。由于屏幕本身没有这块内存空间,所以我们需要在开发板的DDR3内存中分配出这断内存作为RGB的显存,通过操作这段内存我们就可以把需要显示的内容在LCD屏幕上显示出来了。
I.MX6 ULL的eLCDIF支持三种接口:MPU接口,VSYNC接口,DOTCLK接口。
MPU接口是指用于6080/8080接口的LCD屏幕,i.MX6 UL可以和屏幕直接传输命令和数据,比如51单片机上常用的屏幕。如果寄存器LCDIF_CTRL的位DOTCLK_MODE、DVI_MODE和VSYNC_MODE都为0的时候就表示LCDIF工作在MPU接口模式。
VSYNC接口使用和MPU相同的协议,只是多了VSYNC信号作为帧同步。我们通过LCDIF_CTRL寄存器的VSYNC_MODE位来使能VSYNC接口。关于VSYNC更详细的介绍大家可以参考《I.MX6ULL 参考手册.pdf》手册的34.4.7章节。
DOTCLK接口包含了VSYNC, HSYNC, DOTCLK和ENABLE这些信号。DOTCLK接口被大家更习惯的成为RGB接口。本例程我们连接的LCD屏幕就是RGB接口的。
如果eLCDIF驱动起RGB的屏幕,我们需要配置好前面介绍的那些关于时间的参数,这些参数可以通过配置iMX6 ULL的寄存器来实现。下面我看下eLCDIF比较重要的一些寄存器。
首先我们来看下LCDIF_CTRLn 寄存器,其结构如图 10所示:
该寄存器比较重要的位有下列这些:
SFTRST(bit31):软件复位,当设置此位为1的时候,就会复位LCD。
CLKGATE(bit30):正常运行模式下,此位必须为0。
BYPASS_COUNT(bit19):如果工作在MPU模式或VSYNC模式,此位必须为0,如果工作在DOTCLK模式,此位必须设置为1。
VSYNC_MODE(bit18):如果此位设置为1,工作在VSYNC模式。
DOTCLK_MODE(bit17):DOTCLK模式选择位,此位为1工作在DOTCLK模式。
INPUT_DATA_SWIZZLE(bit15:14):数据交换位,为0不交换(小端模式),为1交换全部(大端模式),为2交换半字,为3在半字内交换。我们本例程设置为0,不交换。
CSC_DATA_SWIZZLE(bit13:12):CSC数据交换,使用方式和INPUT_DATA_SWIZZLE(bit15:14)一样,我们本例程设置为0,不交换。
LCD_DATABUS_WIDTH(bit11:10):数据总线宽度,为0表示16位,为1表示8位,为2表示18位,为3表示24位。我们本例程设置成24位数据宽度。
WORD_LENGTH(bit9:8):数据格式,为0表示每个像素16位,为1表示每个像素8位,为2表示每个像素18位,为3表示每个像素24位。
MASTER(bit5):主模式设置位,为1表示工作在主模式。
DATA_FORMAT_16_BIT(bit3):数据格式位,此位和WORD_LENGTH(bit9:8)结合使用,此位为1,并且WORD_LENGTH为0,表示按照16位像素按照ARGB555模式;此位为0,并且WORD_LENGTH为0,表示按照16位像素RGB565模式;当WORD_LENGTH不为0的时候,此位可以忽略。
DATA_FORMAT_18_BIT(bit2):当WORD_LENGTH为2的时候,此位有效、为0表示工作在RGB666模式,低18位数据有效,高14位数据无效;为1表示工作在RGB666模式,高18位数据有效,低14位数据无效。
DATA_FORMAT_24_BIT(bit1):当WORD_LENGTH为3的时候,此位有效。为0表示全部24位数据都有效;为1表示每个字节中的高两位是无效的,实际有效数据是18位。
RUN(bit0):eLCDIF运行使能位。当软件设置该位为1后,eLCDIF开始运行。
接下来是寄存器LCDIF_CTRL1n,结构如图 11所示:
此寄存器我们使用到
BYTE_PACKING_FORMAT(bit19:16):此位表示32位数据中,哪些数据有效。默认值是0xf,表示所有数据都有效;为0表示所有数据都无效;当我们使用ARGB模式的时候,A通道没有传输数据,我们设置该位为0x7。
然后是LCDIF_CUR_BUF寄存器,结构图如下图所示:
然后是LCDIF_TRANSFER_COUNT寄存器,结构图如图 12所示:
该寄存器表示当前现实的帧数据。
然后是寄存器LCDIF_NEXT_BUF,结构图如图 13所示:
该寄存器表示eLCDIF传输一帧数据有多少像素个数。
V_COUNT(bit31:bit16):垂直方向的像素点个数
H_COUNT(bit16:bit0):水平方向的像素点个数。
实际上这个寄存器就是指屏幕的分辨率,比如我们本例程使用的屏幕分辨率是1024x600,那么H_COUNT就是1024,V_COUNT就是600。
接下来是寄存器LCDIF_VDCTRL0n,如图 15所示:
该寄存器是VSYNC和DOTCLK模式控制寄存器0。我们主要用到下面的这些位:
VSYNC_OEB(bit29):VSYNC信号的方向控制。为0表示输出;为1表示输入。
ENABLE_PRESENT(bit28):DE使能位。
VSYNC_POL(bit27):VSYNC数据线极性设置。为0表示VSYNC低电平有效;为1表示VSYNC高电平有效。
HSYNC_POL(bit26):HSYNC数据线极性设置。为0表示HSYNC低电平有效;为1表示HSYNC高电平有效。
DOTCLK_POL(bit25):DOTCLK(CLK)数据线极性设置。为0表示下降沿有效;为1表示上升沿有效。
ENABLE_POL(bit24):DE数据线极性设置。为0表示低电平有效;为1表示高电平有效。
VSYNC_PERIOD_UNIT(bit21):VSYNC周期单位。为0表示VSYNC周期单位为像素时钟;为1表示VSYNC以行为周期单位。在VSYNC模式需要使用像素时钟为周期;在DOTCLK模式下需要使用行为周期单位。
VSYNC_PULSE_WIDTH_UNIT(bit20) :VSYNC信号脉冲宽度。
VSYNC_PULSE_WIDTH(bit17:0):VSPW 参数设置位。
然后是LCDIF_VDCTRL1寄存器,结构域如图 16所示:
该寄存器用来设置VSYNC的总周期:屏幕高度+VSPW+VBP+VFP。
然后是LCDIF_VDCTRL2寄存器,结构图图 17所示:
该寄存器分为高16位和低16位两部分。高16位用来设置HSYNC信号宽度,低16位用来设置HSYNC周期。
接下来是LCDIF_VDCTRL3寄存器,结构图如图 18所示:
HORIZONTAL_WAIT_CNT(bit27:16):在DOTCLK模式下,设置HSYNC信号产生到有效数据产生之间的时间,也就是HSPW+HBP。
VERTICAL_WAIR_CNT(bit15:0):在DOTCLK模式下,设置VSYNC信号产生到有效数据产生之间的时间,也就是VSPW+VBP。
接下来是LCDIF_VDCTRL4寄存器,结构图如图 19所示:
SYNC_SIGNALS_ON(bit18):如果我们需要使用VSYNC、HSYNC、DOTCLK这些信号,需要设置此位为1。
DOTCLK_H_VALID_DATA_CNT(bit15:0):设置LCD的水平像素个数。
关于eLCDIF的寄存器我们就介绍到这里,大家可以参考《I.MX6ULL参考手册.pdf》文档查看详细的描述。我们本例程使用i.MX6ULL驱动迅为电子的7寸RGB屏幕,大致的配置如下:
1.初始化LCD对应的IO
2.初始化eLCDIF的时钟
3.初始化RGB的数据宽度,时间参数,分辨率等参数
4.设置显存地址
5.实现画点、画线、字符串显示等函数