1.什么是LCD?
LCD(Liquid Crystal Display)俗称液晶,电信号的驱动下液晶分子进行旋转,旋转时会影响透光性,可以通过不同电信号让液晶分子进行选择性的透光,此时在液晶面板前面看到的就是各种各样不同的颜色,这就是LCD显示。
2.学习LCD需要搞懂的概念
-> 像素(pixel):
组成图像的最基本元素,或者说显示中可以被控制的最小单位,整个图像就是由很多个像素组成的,像素很重要,整个显示图像是由一个个的像素组成的。
-> 扫描:
扫描就是依次将颜色数值放入屏幕中所有的像素的这个过程,显示器的扫描显示原理依赖于人眼的视觉暂留。只要显示器扫描频率大于人眼的发现频率,人眼看到的图像就是恒定的。如果扫描频率偏小人眼就会看到闪动。
-> 驱动器&控制器:
LCD驱动器一般和LCD显示面板集成在一起,LCD驱动器芯片负责给面板提供控制液晶分子的模拟电信号,驱动器的控制信号(数字信号)来自于自己的数字接口,这个接口就是LCD屏幕的外部接口。
-> 显示内存(简称:显存):
SoC在内存中挑选一段内存,然后通过配置将LCD控制器和这一段内存(以后称为显存)连接起来构成一个映射关系。一旦这个关系建立之后,LCD控制器就会自动从显存中读取像素数据传输给LCD驱动器。这个显示的过程不需要CPU的参与。
-> 像素间距(pitch):
pitch是连续2个像素的像素中心的距离。
-> 分辨率(resolution):
整个屏幕的横向和纵向的像素个数就叫分辨率,譬如X210开发板用的屏幕是1026×400。
-> 清晰度:
清晰度由分辨率和像素间距共同决定。一般的,屏幕尺寸固定时分辨率越高越清晰,分辨率越低就越不清晰;分辨率固定下,屏幕尺寸越小越清晰,越大越不清晰。
-> 像素深度(bits per pixel,简称bpp):
计算机中用二进制位来表示一个像素的数据,用来表示一个像素的数据位越多,则这个像素的颜色值更加丰富,像素深度有这么几种:1位、8位、16位、24位、32位。
3.LCD的接口技术
-> 电平角度来讲本质上都是TTL信号:
+5V表示逻辑1,0V表示逻辑0。
-> RGB接口:
24根数据线VD[23:0]:用来传输图像信息。可见LCD是并行接口,速率才够快。
水平同步信号HSYNC
垂直同步信号VSYNC:时序信号线,为了让LCD能够正常显示给的控制信号。
像素时钟VCLK:LCD工作时需要主板控制器给LCD模组一个工作时钟信号,就是VCLK。
数据有效标志VDEN:时序信号,和HSYNC、VSYNC结合使用。
行结束标志,不是必须的LEND:时序信号,非必须,譬如X210接口就没有。
4. S5PV210的LCD控制器
-> 控制器FIMD:
210的LCD控制器叫FIMD,FIMD是210内部和图像处理相关的一些部件,FIMD在内部与AHB总线等相连接,在外部提供RGB接口。
-> 虚拟屏幕叠加:
平时看到的屏幕上显示出来的场景实际是很多个屏幕显示叠加在一起的效果,像S5PV210的LCD控制器中有5个虚拟屏幕,
5.LCD控制器初始化
#define GPF0CON (*(volatile unsigned long *)0xE0200120)
#define GPF1CON (*(volatile unsigned long *)0xE0200140)
#define GPF2CON (*(volatile unsigned long *)0xE0200160)
#define GPF3CON (*(volatile unsigned long *)0xE0200180)
#define GPD0CON (*(volatile unsigned long *)0xE02000A0)
#define GPD0DAT (*(volatile unsigned long *)0xE02000A4)
#define CLK_SRC1 (*(volatile unsigned long *)0xe0100204)
#define CLK_DIV1 (*(volatile unsigned long *)0xe0100304)
#define DISPLAY_CONTROL (*(volatile unsigned long *)0xe0107008)
#define VIDCON0 (*(volatile unsigned long *)0xF8000000)
#define VIDCON1 (*(volatile unsigned long *)0xF8000004)
#define VIDTCON2 (*(volatile unsigned long *)0xF8000018)
#define WINCON0 (*(volatile unsigned long *)0xF8000020)
#define WINCON2 (*(volatile unsigned long *)0xF8000028)
#define SHADOWCON (*(volatile unsigned long *)0xF8000034)
#define VIDOSD0A (*(volatile unsigned long *)0xF8000040)
#define VIDOSD0B (*(volatile unsigned long *)0xF8000044)
#define VIDOSD0C (*(volatile unsigned long *)0xF8000048)
#define VIDW00ADD0B0 (*(volatile unsigned long *)0xF80000A0)
#define VIDW00ADD1B0 (*(volatile unsigned long *)0xF80000D0)
#define VIDTCON0 (*(volatile unsigned long *)0xF8000010)
#define VIDTCON1 (*(volatile unsigned long *)0xF8000014)
#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
// FB地址
#define FB_ADDR (0x23000000)
#define ROW (480)
#define COL (800)
#define HOZVAL (COL-1)
#define LINEVAL (ROW-1)
#define XSIZE COL
#define YSIZE ROW
// 初始化LCD
void lcd_init(void)
{
// 配置引脚用于LCD功能
GPF0CON = 0x22222222;
GPF1CON = 0x22222222;
GPF2CON = 0x22222222;
GPF3CON = 0x22222222;
// 打开背光 GPD0_0(PWMTOUT0)
GPD0CON &= ~(0xf<<0);
GPD0CON |= (1<<0); // output mode
GPD0DAT &= ~(1<<0); // output 0 to enable backlight
// 10: RGB=FIMD I80=FIMD ITU=FIMD
DISPLAY_CONTROL = 2<<0;
// bit[26~28]:使用RGB接口
// bit[18]:RGB 并行
// bit[2]:选择时钟源为HCLK_DSYS=166MHz
VIDCON0 &= ~( (3<<26)|(1<<18)|(1<<2) );
// bit[1]:使能lcd控制器
// bit[0]:当前帧结束后使能lcd控制器
VIDCON0 |= ( (1<<0)|(1<<1) );
// bit[6]:选择需要分频
// bit[6~13]:分频系数为5,即VCLK = 166M/(4+1) = 33M
VIDCON0 |= 4<<6 | 1<<4;
// H43-HSD043I9W1.pdf(p13) 时序图:VSYNC和HSYNC都是低脉冲
// s5pv210芯片手册(p1207) 时序图:VSYNC和HSYNC都是高脉冲有效,所以需要反转
VIDCON1 |= 1<<5 | 1<<6;
// 设置时序
VIDTCON0 = VBPD<<16 | VFPD<<8 | VSPW<<0;
VIDTCON1 = HBPD<<16 | HFPD<<8 | HSPW<<0;
// 设置长宽(物理屏幕)
VIDTCON2 = (LINEVAL << 11) | (HOZVAL << 0);
// 设置window0
// bit[0]:使能
// bit[2~5]:24bpp(RGB888)
WINCON0 |= 1<<0;
WINCON0 &= ~(0xf << 2);
WINCON0 |= (0xB<<2) | (1<<15);
#define LeftTopX 0
#define LeftTopY 0
#define RightBotX 799
#define RightBotY 479
// 设置window0的上下左右
// 设置的是显存空间的大小
VIDOSD0A = (LeftTopX<<11) | (LeftTopY << 0);
VIDOSD0B = (RightBotX<<11) | (RightBotY << 0);
VIDOSD0C = (LINEVAL + 1) * (HOZVAL + 1);
// 设置fb的地址
VIDW00ADD0B0 = FB_ADDR;
VIDW00ADD1B0 = (((HOZVAL + 1)*4 + 0) * (LINEVAL + 1)) & (0xffffff);
// 使能channel 0传输数据
SHADOWCON = 0x1;
}