六、lcd的控制
原文地址:http://blog.csdn.net/woshidahuaidan2011/article/details/51278058
by jaosn Email: [email protected]
LCD ( Liquid Crystal Display 的简称)液晶显示器。LCD 的构造是在两片平行的玻璃基板当中放置液晶盒,下基板玻璃上设置TFT(薄膜晶体管),上基板玻璃上设置彩色滤光片,通过TFT上的信号与电压改变来控制液晶分子的转动方向,从而达到控制每个像素点偏振光出射与否而达到显示目的。现在LCD已经替代CRT成为主流,价格也已经下降了很多,并已充分的普及。
s3c2440通过lcd来显示图像,在2440内部,存在lcd控制相关的寄存器,其结构图如下:
其中,REABANK是一些寄存器组主要包含17个设置参数的寄存器和256x16的调色板内存,其每个寄存器的作用将在下文一一展开;LCDCDMA是供LCD专用的DMA通道,用于获取总线上面的图像数据;TIMEGEN和LPC3600用来产生LCD控制时序,VIDRCS,将DMA获取来的数据以设定的格式传送给LCD。LPC3600和LCC3600为三星公司生产的lcd,假如不使用三星公司生产的lcd,需要禁止LPC3600和LCC3600。
数据手册给出了两种类型的lcd,一种是STN(Super Twisted Nematic)lcd,这里不再介绍,一种是TFT LCD这里只介绍TFT LCD。
在介绍LCD显示之前,先介绍对于LCD显示的几个重要的名词,首先看图:
图中,是现实整个一幅图的概括图,其中,深蓝色的部分为实际显示出来的部分,其余的部分是非显示部分,但是非显示部分对LCD来说也是必须的。如图中的箭头部分,LCD是按照由上到下,由左到右的顺序显示的。图中HSYNC和VSYNC是跳转信号,在每一行结束,下一行开始的时候,会产生一个HSYNC信号,在一幅图(帧)显示完毕,要显示下一张图的时候,会发出VSYNC信号。
这里值得关注的是,除了深蓝色的部分外,其周围还有其他颜色的部分。也就是说当像素点扫描到每一行深蓝色部分(能显示给用户的部分)最右边的时候,还需要扫描几个无用的像素点才能跳转到下一行平且发出HSYNC信号(无用的点里对应的右边紫色的部分),此时,在发出HSYNC信号之后,仍需要扫描几个无用的点(此时的无用点是指显示不出来的点,所谓无用的点是指左边紫色的部分)才能扫描出要显示给用户的点。
从纵向的来说。当像素扫描到要显示图像的最右端的时候,也就是图中对应的A点,此时扫描点并不马上调转到左上角显示下一帧,而是仍要不断的扫描几个无用的行再跳转并发出VSYNC信号(此时对应的是图中黄色的部分),在发出VSYNC信号后,仍需要扫面几行无用的像素点(对应图中的红色部分)才可以显示要显示的图像。
所有的这些要扫描的像素点称为一帧,也就是扫描完图中所有的像素点称为一帧(有用的没用的点都要算),所以说VSYNC信号出现的频率称为垂直频率代表每秒中可以显示的图像数,简单的话解释就是每出现一个VSYNC就证明一张图片显示完毕。对应的HSYNC称为水平频率。简单的解释就是每出现一次HSYNC信号就证明完成一行的扫描。
图中深蓝色部分,也就是有效数据的行数列数称为分辨率。
基本的名词,及其lcd的基本的显示原理已经介绍完毕,接下就来控制lcd来显示想要显示的东西,首要要控制就需要有时序图,接下来来看lcd控制器的时序图:
首先图中可以看出,VSYNC的一个周期就是一帧的周期,VSYNC的高电平的时间(脉宽)为VSPW+1个HSYNC信号周期;时序图中的VBPD+1部分就是对应上面那个图的上面红色的部分;接下来就是有效显示的行数一共有LINEVAL+1个有效的行数(对应上图蓝色部分的行数);在后面就是需要VFPD+1个HSYNC周期的时间后才开始下一帧的显示,这里VFPD+1个HSYNC周期的时间就是对应图中下面黄色的部分;总的来说,一帧(也就显示一幅图片的时间)就是(VSPW+1)+ (VBPD+1)+(LINEVAL+1)+(VFPD+1)个HSYNC周期。
然后时序图中把一个HSYNC周期放大,图中HSYNC高电平持续的时间(脉宽)为HSPW+1个VCLK周期;接下来需要HBPD+1个VCLK个周期才可以显示有效数据,此时HBPD+1个VCLK个周期的时间就是对应上图中左边紫色的部分;接下来就开始显示有效数据部分,一共需要HOZVAL+1个VCLK周期(这里对应的是上图的蓝色部分的列数);再往后就是需要HFPD+1个VCLK周期的时间才可以继续显示下一行,HFPD+1个VCLK周期的时间就是对应图中右边紫色的部分。这里扫描一行所需要的时间就是(HSPW+1)+(HBPD+1)+(HOZVAL+1)+(HFPD+1)个VCLK周期。
为了具体的确定VSPW VBPD LINEVAL VFPD HSPW HBPD HOZVAL HFPD的具体数值,就要根据LCD的芯片手册来对比得出结果。来对比一下LCD芯片的数据手册,图中单位有两种,其中的H代表HSYNC,其中的CLK为像素的时钟周期。
对比上面的图可以得知VSPW=9 VBPD=1 LINEVAL=271 VFPD=1 HSPW=40 HBPD=1 HOZVAL=479 HFPD=1
通过上面两段的分析,可以看出:
一帧周期(也就显示一幅图片的时间)就是(VSPW+1)+ (VBPD+1)+(LINEVAL+1)+(VFPD+1)个HSYNC周期,
一个HSYNC周期为(HSPW+1)+(HBPD+1)+(HOZVAL+1)+(HFPD+1)个VCLK周期
所以,一帧周期= {(VSPW+1)+ (VBPD+1)+(LINEVAL+1)+(VFPD+1) } * { (HSPW+1)+(HBPD+1)+(HOZVAL+1)+(HFPD+1)}个VCLK周期
这里的数据手册给出了:
VCLK的频率(hz)=VCLK(Hz) = HCLK / [ ( CLKVAL+1) * 2 ]
其中CLKVAL的最小值取0。
所以一帧的频率就是:
Frame Rate = 1 / [ { (VSPW+1 ) + (VBPD+1 ) + (LIINEVAL + 1 ) +(VFPD+1 ) } * {(HSPW+1 ) + (HBPD +1 ) + (HFPD+1 ) + (HOZVAL + 1 ) } *{ 2 x (CLKVAL+1 ) / ( HCLK ) } ]
因此只需要设置上面公式的那个变量值然后给出帧内存的地址就可以进行数据的显示。
接下来说一下图像是如何存储的,在说着之前需要了解一个概念BPP:
BPP(像素深度):像素深度是指存储每个像素所用的位数,它也是用来度量图像的分辨率。像素深度决定彩色图像的每个像素可能有的颜色数,或者确定灰度图像的每个像素可能有的灰度级数。
例如,一幅彩色图像的每个像素用R,G,B三个分量表示,若每个分量用8位,那么一个像素共用24位表示,就说像素的深度为24,每个像素可以是16 777 216(2的24次方)种颜色中的一种。在这个意义上,往往把像素深度说成是图像深度。表示一个像素的位数越多,它能表达的颜色数目就越多,而它的深度就越深。
2440数据手册中有2BPP、4BPP、8BPP、16BPP、24BPP,这里只介绍16BPP其余的也类似。
假如LCD采用,16BPP来显示,2440采用的方式是用4个字节来存储两个像素点的BPP,其中给个像素点的BPP为占用2个字节,但是这样就有两种存储方式:
当BSWP = 0, HWSWP = 0时,2440采用的是上面的存储方式,当BSWP = 0, HWSWP = 2440采用的是下面的存储方式:
在LCD中,像素点P1、P2、P3等的排列方式为:
采用16BPP存储方式,也就是红绿蓝RGP一个占有16个bit,他们的分配方式有两种5:6:5和5:5:5:1,对于第二种方式,最后一个强度位,可以看作是GRB每个有颜色的最低位,就像下图中的下面的那个表格,VD的18位,10位,2位分别有一位,因此5:5:5:1和R(5+1):G(5+1):B(4+1)是一样的(但是不能理解为2^18个颜色值)。
lcd采用的24位数据线来传递数据,两种方式的在24位传送过程中的安排分别为:
至于其他格式的bpp可以参考数据手册,接下来说一下调色板,直白的说,调色板就是一块256*16的一块内存,使用8BPP模式的时候,可以通过索引值查找调色板,调色板跟16BPP类似可以使用5:6:5和5:5:5:1两种模式,其存放格式分别如下图:
可以看到,调色板的深度为0到0Xff,宽度为16bit,通过图中可以看出,调色板的起始地址为0X4D000400,结束地址为0X4D0007FC,这里调色板只用到32内存的低16位DATA[31 :1 6]上的数据是无效数据。假如是5:5:5:1格式存储,传输的VD1 8, VD1 0 和VD2都是传输的同一个值data(l)。
下面就开始一一介绍控制lcd的寄存器:
先看下LCDCON1,功能如下图:
ENVID:LCD 输出信号控制位 为1表示使能
BPPMODE:屏幕类型的对应BPP的选择
PNRMODE:屏幕类型的选择
MMODE :对于STN LCD设置VM的反转频率
CLKVAL :设置像素时钟
对于TFT: VCLK=HCLK/((CLKVAL+1)*2)
HCLK=100Mhz的情况下,lcd手册说明VCLK典型的是9Mhz,CLKVAL=4或者5
LINECNT :只读位,每扫描一行LINECNT的值减去1,直到减到0
LCDCON2,LCDCON3,LCDCON4其具体含义在前面已经分析,不再赘述,寄存器功能如下图:
LCDCON5寄存器主要是包含包含一些状态的只读寄存器和有关一些信号的极性设置:
HWSWP:半字交换使能位
BSWP:字交换是使能位
(上面两个寄存器用来设置像素点在内存的存储排列格式)
ENLEND:LEND使能寄存器
PWREN: LCD_PWREN使能寄存器
INVLEND:LEND信号的极性,是否反转
INVWREN:pwren信号极性是否反转
INVVEN:VDEN信号的极性,是否反转
INVVD:VD数据传输的极性是否反转
INVVFRAME:VFINE/HSYNC信号的极性是否反转
INVVLINE:VLINE/HSYNC信号的极性是否反转
INVVCLK:设置为0在VCLK下降沿读数据;设置为10在VCLK上升沿读数据
FRM565:设置16BPP时候,是565还是5551
BPP24BL:24BPP模式下,是低字节数据有效还是高字节数据有效
HSTATUS/ VSTATUS:只读寄存器,用来获取当前像素扫描到什么部分。
LCDCON1到LCDCON5寄存器介绍完毕,这5个寄存器主要是设置与硬件密切相关的参数,接下来说的是有关帧内存方面的寄存器,介绍之前需了解一些概念,在LCD显示的图中,可以看到真正的显示有效数据周围还有许多无用的数据,这些所有的数据(有效数据+无效数据)称为一帧,而真正显现出来的有效数据称为VIEW PORT,其图可表示为:
通过图可以看出来,view port的大小就是实际LCD屏幕的大小,一帧中包含着view port,而且view port在一帧当中的位置是是可以移动的,其位置有LCDBASEU 、LCDBASEL(view port上下两点显示的起始地址),PAGEWIDTH(view port的宽度也就是lcd的宽度)决定的。这些值具体的设定需要看下面的寄存器。
首先是LCDSADDR1寄存器:
LCDBASEU:对于TFT LCD,用来保存视口(view port)对应的内存的起始地址(view port的第一个数值的地址即对应图中view port左上角的位置地址),也就是帧缓冲区的开始地址。(可以参考上面的位移图来理解)。其存放的是帧内存首地址(32位的数值)的第21~1位。
LCDBANK:保存帧内存的起始地址(保存帧内存首地址(首地址为32位的数值)的第30~22位),为了当移动view port窗口的时候不影响LCDBANK的值,必须4m对齐。
总的来说LCDBASEU存放的是帧内存起始地址的【21:1】位,LCDBANK保存的是帧内存起始地址的【30:22】位
接下来LCDSADDR2:
LCDBASEL:具体的含义可以看上面的那个VIEW PORT的移动的图理解,对于TFT LCD,保存的是view port最后一行的起始地址,其计算公式为:
LCDBASEL = ((the frame end address) >>1 ) +1
= LCDBASEU +(PAGEWIDTH+OFFSIZE) x (LINEVAL+1 )
上面的公式通过上面的那个位移图应该不难理解,只是要注意的就是这里的OFFSIZE是view port位图上的左右两个标出的OFFSIZE的和。一般情况下LCDBASEL存放的是缓存区的大小的【21:1】(帧内存最大是4m,也就是最大为22位)+偏移地址(帧内存的首地址)。
接下来就是
PAGEWIDTH:view port的宽度,以半字为单位(32位的cpu 半字就是16bit)
OFFSIZE:表示上一行最后一个数据与下一行第一个数据间的地址差的一半,以半字为单位。假如OFFSIZE数值2代表相差4个半字。
设置一且完毕后,再来看一下调色板的信息设置:
TPALVAL:这只调色板的GPG的数值
TPAL调色板的使能位。
设置前面的这些寄存器lcd就可以稳定的工作了,但是lcd控制器为了更可能的节约时间,满足不同需求,其拱了一个lcd中断等的操作,具体的看下面的几个寄存器:
LCDINTPND中断挂起寄存器,主要是表示lcd的中断挂起的情况
INT_FiCnt:中断挂起位,该位为0表示没有发生中断请求,当该位是1表明lcd的FIFO的已经达到指定的阈值。
INT_FrSyn:帧同步中断挂起位,该位为0表示没有帧同步中断请求,该位为1表明帧发出中断请求(lcd已经显示完一帧)。
与中断挂起寄存器LCDINTPND雷同的另一个寄存器是,中断源挂起寄存器,他们的功能相同,这里解释一下中断源,大家都知道中断是指由于某种事件的发生(硬件或者软件的),计算机暂停执行当前的程序,转而执行另一程序,以处理发生的事件,处理完毕后又返回原程序继续作业的过程。中断是处理器一种工作状态的描述。我们把引起中断的原因,或者能够发出中断请求信号的来源统称为中断源。
对应的中断源挂起寄存器为中断源挂起寄存器,表明中断源挂起状态
INT_FiCnt:中断挂起位,该位为0表示没有发生中断请求,当该位是1表明lcd的FIFO的已经达到指定的阈值。
INT_FrSyn:帧同步中断挂起位,该位为0表示没有帧同步中断请求,该位为1表明帧发出中断请求(lcd已经显示完一帧)。
既然lcd有前面的这两个状态寄存器那么一定有与之对应的中断屏蔽寄存器来屏蔽中断的发生,这里的寄存器是LCDINTMSK,中断屏蔽寄存器可以决定屏蔽那个中断源(被屏蔽掉的中断源将不会发生作用)。
INT_FiCnt:屏蔽lcd FIFO中断位,该位设置为0表明相应lcd的FIFO的中断,该位设置为1表示屏蔽lcd的FIFO的中断。
INT_FrSyn:屏蔽lcd 帧同步中断位,该位是指为1表明屏蔽帧同步中断。
FIWSEL: 决定lcd的FIFO出发的阈值,设置为0阈值为4字,设置为1表示深度为8字
此外三星公司为自己生产的lcd增加了控制LPC3600/LCC3600 模式的寄存器TCONSEL:
对于该寄存器不做介绍,使用的非LPC3600 LCC3600给该寄存的【0 1】写0禁止该模块就可以。
所有有关TFT lcd的寄存器已经大致介绍完毕,接下来说明控制lcd的步骤:
总结:
1、初始化有关连接lcd的引脚,连接方式看开发板原理图
2、LCDCON1到LCDCON5 用于选择lcd的了类型,设置一些硬件的信息。
3、CDSADDR1到LCDSADDR3设置帧内存的地址
4、TPAL设置,是否使用调色板及其设置调色板的数据。
5、根据自身是否使用三星公司的 lpc3600 和lcc3600 LCD,假如不使用的话需要禁止相应模块
可以通过TCONSEL来设置。
6、设置是否使用中断,可通过LCDINTMSK来设置
7、控制lcd的打开或者关闭。
下面给出设置代码:
voidlcd_Init(void)
{
#define VBPD (1) //垂直同步信号的后肩
#define VFPD (1) //垂直同步信号的前肩
#define VSPW (9) //垂直同步信号的脉宽
#define HBPD (1) //水平同步信号的后肩
#define HFPD (1) //水平同步信号的前肩
#define HSPW (40) //水平同步信号的脉宽
1、初始化有关连接lcd的引脚,连接方式看开发板原理图
rGPCUP = 0xffffffff; // 禁止内部上拉
rGPCCON = 0xaaaaaaaa; // GPIO管脚用于VD[7:0],LCDVF[2:0],VM,VFRAME,VLINE,VCLK,LEND
rGPDUP = 0xffffffff; // 禁止内部上拉
rGPDCON = 0xaaaaaaaa; // GPIO管脚用于VD[23:8]
rGPBCON &= ~(3<<0); // lcd背光灯控制引脚
rGPBCON |= (1<<0);
rGPBDAT &= ~(1<<0); //关闭背光灯
2、 LCDCON1到LCDCON5用于选择lcd的了类型,设置一些硬件的信息。
// 设置像素时钟频率,屏幕模型,bpp模式
rLCDCON1 = (5<< 8)|(3 <<5 )|(12<< 1) ;
rLCDCON2 = (VBPD << 24)|(271<< 14)|(VFPD << 6)|(VSPW);
rLCDCON3 = (HBPD << 19)|(479<< 8)|(HFPD);
rLCDCON4 = (HSPW);
//信号极性 数据存储格式等的设置
rLCDCON5 = (1 << 11) |(1 <<10)| (1 << 9) | (1 << 8) |(1) ;
//选择565格式 上升沿锁存数据 VLINE/HSYNC VFIAME/VSYNC 反转 存储格式P1 P2
3、 CDSADDR1到LCDSADDR3设置帧内存的地址
//这里的LCDBANK定义为volatile unsigned shortLCDBANK[272][480]; //申请帧内存LCDBANK是系统随机分配的
rLCDSADDR1 =(((unsigned int)LCDBANK >> 22) << 21) | ((((unsignedint)LCDBANK)>> 1)& 0x1fffff );
//((unsigned int)LCDBANK >> 22)<< 21) 将内存地址的22到30位存到寄存器的21到29位中
//(unsigned int)LCDBANK)& 0x1fffff 取出低21位
//(((unsigned int)LCDBANK)&>> 1)0x1fffff
内存首地址(32位的数值)的第21~1位放到寄存器的20~0
rLCDSADDR2 = ( ((unsigned int)LCDBANK + ( (480* 272 *2) ) >> 1 )) &0x1fffff;
//((the frame end address) >>1 ) +1 之所以有(480 * 272 *2)的乘以2是因为16BPP假如8BPP则乘以1
//先左移1位后取低21位
rLCDSADDR3 = (0 << 11) | (480 / 1);
//offsize为0 16bpp正好一个像素占用一个半字
4、TPAL设置,是否使用调色板及其设置调色板的数据
///禁止临时调色板寄存器
rTPAL = 0;
5、根据自身是否使用三星公司的 lpc3600和lcc3600LCD,假如不使用的话需要禁止相应模块
可以通过TCONSEL来设置。
//禁止LPC3600/LCC3600模式
rTCONSEL &= ~((1 << 0)| (1 <<1) | (1 << 2)) ;
6、设置是否使用中断,可通过LCDINTMSK来设置
rLCDINTMSK |= (3); //MASK LCD Sub Interrupt
7、控制lcd的打开或者关闭
rLCDCON1 |= 1;//使能LCD数据信号的传输
lcd_power_control(1);//使能lcd
}