裸奔之LCD
转载:http://blog.chinaunix.net/uid-26833883-id-3448142.html
一、LCD的介绍
LCD 液晶显示器是 Liquid Crystal Display 的简称,LCD 的构造是在两片平行的玻璃基板当中放置液晶盒,下基板玻璃上设置TFT(薄膜晶体管),上基板玻璃上设置彩色滤光片,通过TFT上的信号与电压改变来控制液晶分子的转动方向,从而达到控制每个像素点偏振光出射与否而达到显示目的。现在LCD已经替代CRT成为主流,价格也已经下降了很多,并已充分的普及。
上面的这种定义方式说的是LCD众多类型中的TFT-LCD,LCD按其控制方式不同,有多种类型。比如:STN、TFT、LTPS,OLED等,各有优缺点.这里简单介绍一下STN-LCD(Super Twisted Nematic-Liquid Crystal Display)和TFT-LCD(Thin Film Transistor-Liquid Crystal Display)两类显示器的工作原理,其他的读者自行了解.
二、TFT和LCD
STN-LCD和TFT-LCD都使用一种被称为"向列型"的丝状液晶物质,利用电场来控制"丝状"液晶的方向。通常液态晶体包在两片玻璃中间,在玻璃的表面上先镀有一层透明而且导电的薄膜以作电极之用,然后在有薄膜的玻璃上镀一层称为配向剂的物质,以使液晶随着一个特定且平行于玻璃表面的方向扭转。
STN-LCD显示屏中的液晶,其自然状态具有90度的扭转,利用电场可使液晶再进行旋转,液晶的折射系数随液晶的方向改变而改变,光经过STN型液晶后,偏极性发生变化,只要选择适当,使光的偏极性旋转到180度到270度,就可以利用两个平行偏光片使光完全不能通过。若使液晶方向和电场方向平行,这样光的偏极性就不会改变,光就可以通过第二个偏光片。于是,就可以控制光的明暗了。而STN液晶之所以可以显示彩色,那是因为它在STN液晶显示屏上加了一个彩色的滤光片,并将单色显示矩阵中的每一个像素分成三个子像素,分别通过彩色滤光片显示红,绿,蓝三原色,就可以显示出彩色。STN型液晶属于放射式LCD器件,它的好处是功耗小,但在比较暗的环境中清晰度很差,所以不得不配置外部照明光源。
而TFT液晶显示技术采用了"主动式矩阵"的方式来驱动。方法是利用薄膜技术所做成的电晶体电极,利用扫描的方法"主动的"控制任意一个显示点的开和关。电极通过时,液晶分子就像STN液晶的排列状态一样会发生改变,也通过折光和透光来达到显示的目的。看起来和STN原理差不多。但不同的是,由于 TFT 晶体管具有电容效应,能够保持电位状态,已经透光的液晶分子会一直保持这种状态,知道TFT电极下一次再加电改变其排列方式为止,而STN型液晶就没有找个特性,液晶分子一旦没有电场,立刻就返回了原来的状态,这是TFT液晶和STN液晶显示原理的最大不同之处。
三、FrameBuffer机制
FrameBuffer也叫帧缓存,它的意思是在我们的内存中开辟出以块内存,当作显存用。我们只需要将我们要显示的一副图片像素数据存放到这一块内存中,就能在LCD上显示我们的图片了。
这里以S3C2410为例,LCD控制器内部有一个专用的DMA。在这里我们只需要配置好LCD控制器就可以了,将显存的地址告诉LCD控制器。当LCD内部DMA的FIFO为空时,LCD控制器会自动发起DMA传输从内存中获取图像数据。
四、TFT-LCD的时序
要想很好的操作TFT-LCD显示屏,首先得搞清楚其时序:
每个VSYNC信号表示一帧数据的开始,每个HSYNC信号表示一行数据的开始,每个VCLK表示正在传输一个像素的数据。LCD根据VSYNC、HSYNC、VCLK不停地读取总线数据、显示。
下面我们简单来说一下时序图:
(1)VSYNC信号有效时,表示一帧数据的开始
(2)VSPW表示VSYNC信号的脉冲宽度为(VSPW 1)个HSYNC信号周期,即(VSPW 1)行,这(VSPW 1)行数据无效
(3)VSYNC信号脉冲之后,还要经过(VBPD 1)个HSYNC信号周期,有效的行数据才出现。所以,在VSYNC信号有效之后,总共还要经过(VSPW 1 VBPD 1)个无效的行,第一个有效的数据才会出现。
(4)随后即连续发出(LINEVAL 1)行的有效数据。
(5)最后是(VFPD 1)个无效的行,完整的一帧结束,紧接着就是下一个帧的数据了(即下一个VSYNC信号)
现在深入一行中像素数据传输的过程:
(1)HSYNC信号有效时,表示一行数据的开始
(2)HSPW表示HSYNC信号的脉冲宽度为(HSPW 1)个VCLK信号周期,即(HSPW 1)个像素,这(HSPW 1)个像素的数据无效。
(3)HSYNC信号脉冲之后,还要经过(HBPD 1)个VCLK信号周期,有效的像素数据才出现。所以,在HSYNC信号有效之后,总共还要经过(HSPW 1 HBPD 1)个无效的像素,第一个有效的像素才出现。
(4)随后即连续发出(HOZVAL 1)个像素的有效数据
(5)最后是(HFPD 1)个无效的像素,完整的一行结束,紧接着下一行的数据了(即下一个HSYNC信号)
这里需要注意的是上图给出的时序是S3C2410数据手册给出的一个范例,具体的LCD屏时序需要根据屏的数据手册获得。我使用的是
东华WXHAT35-TG2 320X240的TFT屏,时序如下:
可以看到和标准的时序很像,我们只需要配置LCD控制器,让其发出上图的时序,我们的屏就可以很好的工作了。
五、核心实验代码
如何配置其控制器,这里我就不再赘述了,网上的资料很多,说的都很详细。这里简单的说一下实验代码:
//初始化LCD控制器
int tft_lcd_init()
{
unsigned int addr = (unsigned int )LCD_BUFER;
/*
*LCDCON1:
*设置VCLK的频率:VCLK(HZ) = HCLK/[(CLKVAL + 1) x 2]
*选择LCD类型:TFT LCD
*设置显示模式:16 BPP
*先禁止LCD信号输出
*/
LCDCON1 = (CLKVAL << 8) | (PNRMODE << 5) | (BPPMODE << 1) | VID_DIS;
/*
*LCDCON2:设置LCD的垂直同步信号时序参数
*VBPD:垂直同步信号的后肩
*LINEVAL:LCD屏上有效的行数
*VFPD:垂直同步信号的前肩
*VSPW:垂直同步信号的脉宽
*/
LCDCON2 = S3C2410_LCDCON2_LINEVAL(LCD_Y_SIZE - 1) |\
S3C2410_LCDCON2_VBPD(UPPER_MARGIN - 1) |\
S3C2410_LCDCON2_VFPD(LOWER_MARGIN - 1) |\
S3C2410_LCDCON2_VSPW(VSYNC_LEN - 1);
/*
*LCDCON3:设置LCD的水平同步信号时序参数
*HBPD:水平同步信号的后肩
*HOZAL:LCD屏图像显示的宽度
*HFPD:水平同步信号的前肩
*/
LCDCON3 = S3C2410_LCDCON3_HBPD(RIGHT_MARGIN - 1) |\
S3C2410_LCDCON3_HFPD(LEFT_MARGIN - 1) |\
S3C2410_LCDCON3_HOZVAL(LCD_X_SIZE - 1);
/*
*LCDCON4:水平同步信号的脉宽
*/
LCDCON4 = S3C2410_LCDCON4_HSPW(HSYNC_LEN - 1);
/*
*LCDCON5:
*设置显示模式为16BPP时的数据格式: 5:6:5
*设置HSYNC,VSYN脉冲的极性(这需要参考具体LCD的接口信号)
*/
LCDCON5 = (FORMAT_565 << 11) | (GET_DATA << 10) | (HSYNC_INV << 9)\
| (VSYNC_INV << 8) | (HWSWP << 1);
/*
*设置LCD控制器的地址寄存器LCDSADDR1~3
*帧内存与视口(view point)完全吻合
*1.LCDSADDR1:
*设置LCDBANK,LCDBASEU
*
*2.LCDSADDR2:
*设置LCDBASEL:帧缓冲的结束地址A[21:1]
*
*3.LCDSADDR3:
*OFFSIZE等于0,PAGEWIDTH等于(320/2)[注意:以半字为单位]
*/
LCDSADDR1 = ((addr >> 22) << 21) | ((addr >> 1) & 0x1fffff);
LCDSADDR2 = ((addr + LCD_X_SIZE * LCD_Y_SIZE * 2) >> 1) & 0x1fffff;
LCDSADDR3 = (0 << 11) | (LCD_X_SIZE / 2);
//禁用条色板
TPAL = 0;
//MASK LCD sub Interrupt
LCDINTMSK = 3;
//Disable LPC3480
LPCSEL &= ~7;
return 0;
}
/*在LCD屏幕的指定坐标点绘制一幅图像*/
static void paint_bmp(int x0,int y0,int x1,int y1,unsigned char bmp[])
{
int x,y;
unsigned short c;
int p = 0;
unsigned int addr = (unsigned int)LCD_BUFER;
for(y = 0;y < y1;y ++)
{
for(x = 0;x < x1; x ++)
{
c = bmp[p+1] | ( bmp[p] << 8);
*(unsigned short *)(addr +((x + x0 + ((y + y0) * 320)) << 1)) = c;
#if 0
/*特别奇怪,使用二维数组的方式,LCD显示图片的时候有重叠,不清晰
*但是用上面的一种写法就能正常显示,我感觉两种写法应该都可以,希望知道的
*大神跟小弟说一下,不胜感激...
*/
if((x0 + x) < LCD_X_SIZE && (y0 + y) < LCD_Y_SIZE)
{
LCD_BUFER[y0 + y][x0 + x] = c;
}
#endif
p = p + 2;
}
}
return;
}
最后附上整个实验的代码
https://files.cnblogs.com/files/pengdonglin137/LCD.zip
本文来自博客园,作者:摩斯电码,未经同意,禁止转载