1:LCD基本工作原理
(1) LCD(Liquid Crystal Display)液晶显示,液晶特性:在电信号的驱动下液晶分子进行旋转,旋转会影响透光性,因此整个液晶面板
后面用白光(背光)来照射,通过不同的电信号让液晶分子进行旋转性透光,此时液晶面板就会看到显示不同的颜色。液晶本身不发光,而是
位于后面的背光发的光。
(2) 白光是由多种颜色的光组合而成,光的实质是一种波,不同波长/频率的波具有不同的颜色,人眼可见光波长在390~780NM,RGB色彩模式是工业界的一种颜色标准,
是通过对红(R)、绿(G)、蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,RGB即是代表红、绿、蓝三个通道的颜色,这个标准几乎包括了人类视
力所能感知的所有颜色,是目前运用最广的颜色系统之一。
(3) 210控制器可以采用RGB888颜色编码模式,红绿蓝各8位,红色绿色蓝色又称为三原色光,用英文表示就是R(red)、G(green)、B(blue)。在电脑中,RGB的所谓“多少”
就是指亮度,并使用整数来表示。通常情况下,RGB各有256级亮度,用数字表示为从0、1、2...直到255。共256级。计算机所能表达的颜色种类个数,这个参数叫:像素深度bpp。
(4) LCD显示图像原理:LCD屏幕是由一个个像素点组成的矩阵(如resolution 1024*768,横向有1024个像素点,纵向有768个
像素点),每个像素点都可以被单独控制亮或者不亮或者亮度强弱等,LCD图像就是通过不同的颜色强度的像素点组合而成。我们可采用RGB888编码来表示每个像素
点的颜色模式(强弱、颜色等等),一帧数据就表示在LCD矩阵的每个像素点对应的颜色模式。
(5) SoC如何控制LCD显示原理:
LCD驱动器:LCD驱动器一般与LCD面板集成在一起,面板需要一定的模拟电信号来控制液晶分子,LCD驱动器芯片负责给面板提供控制液晶分子的模拟电
信号,驱动器的控制信号(数字信号)来自于LCD控制器的提供的接口。
LCD控制器:LCD控制器集成在SoC内部,它负责通过数字接口向外部的LCD驱动器提供要显示的像素数字信号。它必须按照一定的时序和LCD驱动器通信,LCD
控制器受SoC控制,SoC会从内存中拿出像素数据给LCD控制器并最终传给LCD驱动器。
显存:SoC在内存中选一段内存,用来存放颜色数据,然后通过配置将LCD控制器和这一段内存连接起来,构成一个映射关系,一旦这个关系建立以后
,LCD控制器就会自动从显存中读取像素数据传给LCD驱动器,LCD驱动器会自动的控制每个像素点的液晶分子,以形成最终的图像,建立这个映射以后
就不需要SoC在来参与任何行为了。
总结一下:SoC控制LCD液晶显示的过程分为两个部分:
(1) SoC的LCD控制器引出一定的引脚与LCD驱动器连接,按照标准设置一定的时序;
(2) 把LCD要显示的像素信息放入内存中,在通过设置LCD控制器中的寄存器,与LCD控制器建立映射;
之后过程就是LCD控制器芯片与驱动器芯片自动完成的事情了,整个LCD图像的显示过程就是这样。
(6) LCD接口技术:从电平角度来讲LCD都是TTL电平,TTL缺陷是容易受到外界影响,传输距离近,一般像手机平板等直接用软排线
连接即可,而远距离则需要转换,转换方式为:TTL--》VGA--》TTL。
(7) 补充
虚拟屏幕叠加:
(1)虚拟屏幕的意思是,我们平时看到的屏幕上显示出来的场景实际是很多个屏幕显示叠加在一起的效果(譬如新闻图像、电视台台标、下方飘动的字幕新闻)
(2)像S5PV210的LCD控制器中有5个虚拟屏幕Window0到Window4,虚拟屏幕不存在于真实而存在于内存中。(之前讲过,LCd显示时实际是显示的是对应的内存中的显存区域的数值)
虚拟屏幕其实就是一个内存中的显存区域,有几个显存区域就有几个虚拟屏幕,但是这些虚拟屏幕都被映射到一个真实的显示屏上面,所以将来真实的现实效果实际是这几个虚拟屏幕的显示内容的叠加。
(叠加时要注意上面一层会覆盖下面一层,所以要注意谁在前谁在后,设置寄存器时有这个选项)
(3)使用虚拟屏幕而不是整个LCD使用一个显存是有一定好处的:第一,可以保证不污染源图像,方便程序处理;第二,可以减少屏幕刷新,提高显示效率,减少CPU工作量。
虚拟显示
(1)如何实现在小分辨率的屏幕上(真实)显示大分辨率的图像
(2)细节上,我们需要屏幕上看到不同图像时,需要对显存区域进行刷新。即使我们只需要屏幕显示移动一点点,整个屏幕对应的显存空间也需要整个重新刷新,工作量和完全重新显示一幅图像是一样的。
这个显然不好,这样CPU刷新屏幕的工作量太大了,效率很低。
(3)如何能够在显示一个大图片的不同区域时让CPU刷新屏幕工作量减少?有,方法就是虚拟显示。具体做法就是在内存中建立显示缓存的时候实际建立一个很大的区域,然后让LCD去对应其中的一部分
区域作为有效的显示区域。将来要显示大图像时,直接将大图像全部一次性加载入显示缓存区,然后通过移动有效显示区域就可以显示大图像的不同区域了。
2:S5PV210 LCD时序
看一下核心板原理图:LCD接线为24条VD数据输出线,用来传输RGB888 24位颜色数据,VCLK时钟线,HSYNC:水平同步信号线;VSYNC:垂直同步信号线,VDEN:数据使能线;
HSPW+1:HSYNC线上不工作是为低电平,拉高HSPW+1时钟,在拉低,表示要准备开始传输颜色数据;(这个时间可以理解为切换到下一行所消耗的时间)
HBPD+1:在经过HBPD+1时钟,VDEN线拉高,表示VD线上之后的都是RGB颜色数据,所以只有当VDEN信号线为高电平是,才认为是发送的真实数据,
开始发送水平颜色信息以后就会连续发送,如1024*768分辨率LCD,会一直把水平的1024个像素点的颜色数据都发送完以后才会拉低VDEN。(这个时间理解为
准备传输水平数据所要消耗时间)
HOZVAL+1:1024-1不表示时钟,而是表示水平像素个数-1
表示传输横线颜色数据的总时钟,如一个时钟频率传输1个bit位,每个颜色数据设置为32位,横向共传输1024个b颜色数据,总的时钟为1024*32;
HFPD+1:数据传输完以后首先把VDEN拉低HFPD+1时钟,整个水平传输周期完成;(这个时间可以理解为,结束数据传输所消耗时间)
VSPW+1:同样可以理解为切换整帧图像数据所消耗时间;
VBPD+1:准备传输整帧数据消耗时间;
LINEVAL+1:768-1;
VFPD+1:结束传输整帧数据的同步时间;
要注意,这几个时序参数本身是LCD屏幕本身的参数,与LCD控制器无关。所以同一个主板如果接的屏幕不一样则时序参数设置也会不同。
3:相关寄存器
寄存器:DISPAY_CONTROL 设置为10或11;RGB模式可行即可;
VIDCON0:Video Main Control 0 Register
bit18-26选择为RGB模式
bit18:设置RGB数据传输为并行还是串行,因为有24根数据线所以为并行;
bit2选择时钟源,选HCLK 连的是HCLC_DSYS 为166MHz
bit4:开启分频;
bit13-6设置时钟大小,时钟频率要小于控制器的最大时钟,也要小于LCD驱动器的最大时钟。
bit0 bit1为使能控制信号都使能
VIDCON1寄存器 Video Main Control 1 Register
bit5 bit6设置HSYNC和VSYNC的极性,如果LCD的高低电平脉冲是相同的话,则Normal,如果极性相反则Invert。
VIDTCON0:设置时序,根据LCD数据手册中的时序来设置
VIDTCON1
VIDTCON2
WINCON0寄存器
bit1:使能window0
bit5-2选择RGB888模式
bit15:设置输出顺序为 red green blue还是 blue green red 设置为1:BGR 设置为0:RGB
VIDOSD0A VIDOSD0B这两个寄存器是用来设置内存中window0的大小;
比如设置为LCD屏幕的尺寸(即左上坐标为(0, 0) 右下坐标为(1023, 767))
VIDOSD0C也是设置内存中window0的大小
比如设置为LCD屏幕的尺寸=1024*768
VIDW0xADD0Bx设置内存中window0的起始地址的
VIDW0xADD1Bx设置内存中window0的结束地址的
SHODOWCON寄存器来设置虚拟windows显示的;
以下位可以分别设置哪个windows显示;
补充:看核心板、地板原理图相应引脚要设置为LCD的引脚模式,LCD背光要打开;
以下位详细代码:
#include "lyq.h" #define _ZLS_MODE_ #define RED (0xFF0000) #define GREEN (0x00FF00) #define BLUE (0x0000FF) #define WHITE (0xFFFFFF) //配置相关引脚 #define GPF0CON 0xE0200120 #define GPF1CON 0xE0200140 #define GPF2CON 0xE0200160 #define GPF3CON 0xE0200180 #define GPD0CON 0xE02000A0 #define GPD0DAT 0xE02000A4 #define DISPLAY_CONTROL 0xE0107008 //配置控制器 #define VIDCON0 0xF8000000 #define VIDTCON0 0xF8000010 #define VIDCON1 0xF8000004 #define VIDTCON1 0xF8000014 #define VIDTCON2 0xF8000018 #define WINCON0 0xF8000020 #define VIDOSD0A 0xF8000040 #define VIDOSD0B 0xF8000044 #define VIDOSD0C 0xF8000048 #define VIDW00ADD0B0 0xF80000A0 #define VIDW00ADD1B0 0xF80000D0 #define SHODOWCON 0xF8000034 #define _RGB_GPF0CON (*(unsigned int*)0xE0200120) #define _RGB_GPF1CON (*(unsigned int*)0xE0200140) #define _RGB_GPF2CON (*(unsigned int*)0xE0200160) #define _RGB_GPF3CON (*(unsigned int*)0xE0200180) #define _RGB_GPD0CON (*(unsigned int*)0xE02000A0) #define _RGB_GPD0DAT (*(unsigned int*)0xE02000A4) #define _RGB_DISPLAY_CONTROL (*(unsigned int*)0xE0107008) //配置控制器 #define _RGB_VIDCON0 (*(unsigned int*)0xF8000000) #define _RGB_VIDTCON0 (*(unsigned int*)0xF8000010) #define _RGB_VIDCON1 (*(unsigned int*)0xF8000004) #define _RGB_VIDTCON1 (*(unsigned int*)0xF8000014) #define _RGB_VIDTCON2 (*(unsigned int*)0xF8000018) #define _RGB_WINCON0 (*(unsigned int*)0xF8000020) #define _RGB_VIDOSD0A (*(unsigned int*)0xF8000040) #define _RGB_VIDOSD0B (*(unsigned int*)0xF8000044) #define _RGB_VIDOSD0C (*(unsigned int*)0xF8000048) #define _RGB_VIDW00ADD0B0 (*(unsigned int*)0xF80000A0) #define _RGB_VIDW00ADD1B0 (*(unsigned int*)0xF80000D0) #define _RGB_SHODOWCON (*(unsigned int*)0xF8000034) #define FB_ADDR (0x23000000) //Horizontal Pulse Width 20 //Horizontal Back Porch 140 //Horizontal Front Porch 160 //Horizontal effective Time 1024 //Vertical Pulse Width 3 //Vertical Back Porch 20 //Vertical Front Porch 12 //Vertical Valid 600 #ifdef _ZLS_MODE_ #define HSPW (40) // 1~40 DCLK #define HBPD (10 - 1) // 46 #define HFPD (240 - 1) // 16 210 354 #define VSPW (20) // 1~20 DCLK #define VBPD (10 - 1) // 23 #define VFPD (30 - 1) // 7 22 147 #else #define HSPW (20) // 1~40 DCLK #define HBPD (140) // 46 #define HFPD (160) // 16 210 354 #define VSPW (3) // 1~20 DCLK #define VBPD (20) // 23 #define VFPD (12) // 7 22 147 #endif #define ROW (600) #define COL (1024) #define FB_ADDR (0x23000000) #define HOZVAL (COL-1) #define LINEVAL (ROW-1) #define LeftTopX (0) #define LeftTopY (0) #define RightBotX (COL - 1) #define RightBotY (ROW - 1) unsigned int *pfb = (unsigned int *)FB_ADDR; void lcd_init(void) { //设置相应引脚为LCD模式 _RGB_GPF0CON = 0x22222222; _RGB_GPF1CON = 0x22222222; _RGB_GPF2CON = 0x22222222; _RGB_GPF3CON = 0x22222222; //设置背光开启,输出低电平 _RGB_GPD0CON &= ~(0xF << 0); _RGB_GPD0CON |= (0x1 << 0); _RGB_GPD0DAT &= ~(0x1 << 0); //设置FIMD的输出为RGB模式输出 _RGB_DISPLAY_CONTROL &= ~(3 << 0); _RGB_DISPLAY_CONTROL |= (2 << 0); //基本设置 _RGB_VIDCON0 &= ~(0x3 << 26); //设置为RGB模式 _RGB_VIDCON0 &= ~(0x1 << 18); //设置为RGB并行 _RGB_VIDCON0 &= ~(0x1 << 2); //设置时钟源为HCLK_DSYS _RGB_VIDCON0 |= (1 << 4); //开启分频 _RGB_VIDCON0 &= ~(0xFF << 6); //设置时钟分频为4 166/(4+1) = 33 _RGB_VIDCON0 |= (4 << 6); _RGB_VIDCON0 |= (3 << 0); //使能signal _RGB_VIDCON1 |= (3 << 5); //开启HSYNC、VSYNC极性反转 //设置时序等 _RGB_VIDTCON0 &= ~(0xFFFFFF << 0); _RGB_VIDTCON0 |= ((VSPW << 0) | (VFPD << 8) | (VBPD) << 16); _RGB_VIDTCON1 &= ~(0xFFFFFF << 0); _RGB_VIDTCON1 |= ((HSPW << 0) | (HFPD << 8) | (HBPD) << 16); _RGB_VIDTCON2 = ((HOZVAL << 0) | (LINEVAL << 11)); //设置window0 _RGB_WINCON0 |= (1 << 0); //使能window0 _RGB_WINCON0 &= ~(0xF << 2); //设置window0位RGB888模式 _RGB_WINCON0 |= (0xB << 2); //设置window0在内存中的坐标 _RGB_VIDOSD0A &= ~(0x3FFFFF << 0); _RGB_VIDOSD0A |= ((LeftTopX << 0) | (LeftTopX << 11)); _RGB_VIDOSD0B &= ~(0x3FFFFF << 0); _RGB_VIDOSD0B |= ((RightBotY << 0) | (RightBotX << 11)); _RGB_VIDOSD0C = (RightBotX + 1) * (RightBotY + 1); //设置显存的起始地址 _RGB_VIDW00ADD0B0 = (unsigned int)FB_ADDR; //设置显存结束地址 //_RGB_VIDW00ADD1B0 = (((HOZVAL )*4 + 0) * (LINEVAL + 1)) & (0xffffff); _RGB_VIDW00ADD1B0 = _RGB_VIDW00ADD0B0 + (((HOZVAL + 1)*4 + 0) * (LINEVAL + 1)); //使能channel0 _RGB_SHODOWCON = 1; } static void lcd_point_draw_func(unsigned int x, unsigned int y, unsigned int color) { unsigned int mem_val, i; mem_val = (unsigned int)FB_ADDR + (COL*(y-1) + (x-1)) * sizeof(int); *(unsigned int *)mem_val = color; } void clean_window(void) { int i = 0; for (i=0; i<614400; i++) { *pfb = 0; pfb++; } } static void lcd_bckgrd_draw(unsigned int color) { int i, j; for (j=0; j<ROW; j++) { for (i=0; i<COL; i++) { lcd_point_draw_func(i, j, color); } } } static void lcd_line_draw(unsigned int y, unsigned int color) { int i = 0; for (i=0; i<1024; i++) { lcd_point_draw_func(i, (y-1), color); } } void lcd_pic_draw(const unsigned char *pcolor) { int i, j; int color; for (j=0; j<ROW; j++) { for (i=0; i<COL; i++) { color = ((*pcolor) << 0) | ((*(pcolor+1)) << 8) | ((*(pcolor+2)) << 16); lcd_point_draw_func(i, j, color); pcolor +=3; } } } // 在像素点(x, y)处填充为color颜色 /* static inline void lcd_draw_pixel(unsigned int x, unsigned int y, unsigned int color) { *(pfb + COL * y + x) = color; } // 把整个屏幕全部填充成一个颜色color static void lcd_draw_background(unsigned int color) { unsigned int i, j; for (j=0; j<ROW; j++) { for (i=0; i<COL; i++) { lcd_draw_pixel(i, j, color); } } } */ void lcd_test(void) { lcd_init(); //clean_window(); //lcd_bckgrd_draw(RED); //delay(); lcd_pic_draw(gImage_lyq); }