S3C2440的LCD编程
4. 帧缓冲(FrameBuffer):
帧缓冲是Linux为显示设备提供的一个接口,它把一些显示设备描述成一个缓冲区,允许应用程序通过 FrameBuffer定义好的接口访问这些图形设备,从而不用去关心具体的硬件细节。对于帧缓冲设备而言,只要在显示缓冲区与显示点对应的区域写入颜色 值,对应的颜色就会自动的在屏幕上显示。下面来看一下在不同色位模式下缓冲区与显示点的对应关系:本文引用地址://m.amcfsurvey.com/article/201611/322380.htm
volatile static unsigned short LCD_BUFFER[240][320];
void Pixel(U32 x,U32 y, U16 c )
{
if ( (x < SCR_XSIZE_TFT_320240) && (y < SCR_YSIZE_TFT_320240) )
LCD_BUFFER[y][x] = c;
}
很容易发现TFT LCD上显示单个像素的函数实际上很简洁,看来似乎只需要LCD_BUFFER[(y)][(x)] = c这一句话.下面就来分析下,是如何通过这一句话来实现在LCD上显示单个像素的,先分析下Lcd_Init()即LCD初始化函数:
#define rGPCCON
#define rGPCUP
#define rGPDCON
#define rGPDUP
#define rLCDCON1
#define rLCDCON2
#define rLCDCON3
#define rLCDCON4
#define rLCDCON5
#define rLCDSADDR1
#define rLCDSADDR2
#define rLCDSADDR3
#define rLCDINTMSK
#define rTPAL
void Lcd_Init(void)
{
}
程序分析至此,大概已经清楚是如何通过LCD_BUFFER[(y)][(x)] = c来实现在LCD上显示单个像素了。就是在设置好各个LCD寄存器之后,通过将LCD_BUFFER地址与LCDBANK以及LCDBASEU、 LCDBASEL对应之后,通过改变LCD_BUFFER里不同单元存储的值(即像素的颜色),即可在LCD相应位置上做出显示。
那么在应用不同LCD的时候,只需对LCDCONx以及LCDSADDRx做出相应的配置,再创建一个数组,做出上述的地址映射即可。
关于VCLK计算,由于配置的是TFT,可用到公式VCLK = HCLK / [(CLKVAL+1) * 2] ( CLKVAL>=0 ),设置的Fclk为400MHz,Hclk为100MHz(Fclk:Hclk=1:4),CLKVAL = 4,因此VLCK = 10MHz。
笔记:
首先说一下我们平时所说的多少位的LCD,有24位的,有16位的指的是LCD数据的位数,LCD的数据实际上是LCD要显示的颜色,24位的是红绿 蓝各占8位,16位则是红绿蓝按照565分配的,其实24的也可以只接16位,每个颜色地位接地就可以,所以要给LCD的缓冲区一个数据才能在LCD上显 示出来。那究竟是怎么显示的呢,那就得先说一下像素了,LCD的像素实际上就LCD屏幕有多少个点,LCD显示的东西都是一个一个点拼凑出来的,比如我用 的是320*240的LCD,就是说LCD每一行有320个点,而每一列有240个点,所以总共有320*240个点,我们让适当的点显示适当的颜色就达 到了我们的目的。
其实刚开始困扰我们的是LCD的初始化的问题,要设置的东西比较多,其实我们是记不住这些东西的,呵呵,作为入门我们可以参考别人的初始化程序,把里面的参数改成我们自己的LCD的参数就OK了。
那么我们到底是怎么把我们要显示的数据送给LCD控制起的呢?是这样的,我们可以定义一个二维数组,把我们要显示的数据存到里面,然后把这个数组的地 址赋给LCD的相应的寄存器,这个寄存器是LCDSADDRn,具体的设置大家可以参考数据手册,我们可以把二维数组的坐标和LCD的坐标对应起来,那么 我们就可以随意的让哪一个像素点显示什么颜色就显示什么颜色了。这就把数据送出的过程,也就是显示一个像素点的过程。
到现在我们已经知道如何显示一个像素了,那接下来就是LCD显示最基本的东西了----字符和图片。汉字和图片的显示都是基于像素点的显示的,我们把 要显示的字符和图片转化成相应的数据,然后传递给LCD即可。我们可以专门的写一个显示字符的函数和一个显示图片的函数。显示字符的数据可以用取模软件生 成,因为生成的字符数据是表示的每一个点要不要亮,亮的地方用1表示,不亮的地方用0表示,所以如果用LCD显示,我们还要告诉LCD显示什么颜色,这才 是LCD需要的数据,比如说16*16的数据,有16行16列,我们将一行的数据,也就是16位数据的每一位都取出来,为1的地方,我们就给LCD一个 16位的数据,为0的地方就不给数据,这样就能显示了,取模生成的数据都是按行来的。图片的显示直接就将16位的数据传递给LCD,这个图片数据的产生, 我们可以用软件LCD彩色图片转换工具(BMP_to_H)生成C语言文件,我们只需对文件进行简单的修改就能加入到我们的程序中,修改方法在软件的说明 中都有。
编程要点:
1、打开LCD背光
将LCD背光对应的GPIO设置为禁止上拉(GPxUP相应位写入1),选择output类型(GPxCON相应位写入01),输出为高电平(GPxDAT相应位写入1)。
2、打开LCD电源
可以将GPG4选择为LCD_PWREN(GPGCON:9-8写入11),这时候LCD电源的打开/关闭可以通过LCDCON5:3来控制。也可以自定 义其他GPIO用作LCD电源开关,只需将此GPIO设置为禁止上拉(GPxUP相应位写入1),选择output类型(GPxCON相应位写入01), 输出为高电平(GPxDAT相应位写入1)打开LCD电源。
3、设置其他信号线
其他信号线包括VD0-VD23和VFRAME、VLINE、VCLK等,分别在GPCCON,GPDCON中选择相应功能。
4、设置LCD的频率(VCLK)
LCD的Datasheet上一般会写有一个推荐的频率,比如我使用的屏幕推荐频率为6.4M,我需要通过一些计算选择一个合适的CLKVAL以产生这个频率:
对于TFT LCD,S3C2440提供的VCLK的计算公式为:VCLK = HCLK / ((CLKVAL+1)*2)
可以得出:CLKVAL = HCLK / (VCLK * 2) - 1
我 的HCLK是100Mhz(CPU运行在400Mhz, CLKDIV_VAL设置为5,Fclk:Hclk:Pclk = 1:4:8),VCLK使用屏幕推荐的6.4M,得到:CLKVAL = 100000000 / (6400000 * 2) - 1 = 6.8
选择最接近的整数值7,写入LCDCON1:17-8。
(VCLK其实就是根据 每秒帧数*帧行数*行像素 计算出来的,帧行数和行像素需要包含空白数和同步数)
5、设置其他相关参数
LCD相关的参数主要还有这几个:LINEVAL: LCD水平像素-1,如320-1 = 319HOZVAL: LCD垂直像素-1,如240-1 = 239HFPD: 行开始前的VCLK时钟数(LCD屏幕的Datasheet一般有推荐值)HBPD: 行结束后的VCLK时钟数(LCD屏幕的Datasheet一般有推荐值)HSPW: 行之间水平同步的无效VCLK时钟数(LCD屏幕的Datasheet一般有推荐值)VFPD: 帧数据开始前的空白行数(LCD屏幕的Datasheet一般有推荐值)VBPD: 帧数据结束后的空白行数(LCD屏幕的Datasheet一般有推荐值)VSPW: 帧之间垂直同步的无效行数(LCD屏幕的Datasheet一般有推荐值)
(相关寄存器LCDCON2, LCDCON3, LCDCON4)
6、设置视频缓冲区的地址
2440支持虚拟屏幕,可以通过改变LCD寄存器实现屏幕快速移动:
PAGEWIDTH:虚拟屏幕一行的字节数,如果不使用虚拟屏幕,设置为实际屏幕的行字节数,如16位宽320像素,设为320 * 2OFFSIZE:虚拟屏幕左侧偏移的字节数,如果不使用虚拟屏幕,设置为0
LCDBANK: 视频帧缓冲区内存地址30-22位LCDBASEU: 视频帧缓冲区的开始地址21-1位LCDBASEL: 视频帧缓冲区的结束地址21-1位
(相关寄存器LCDSADDR1,LCDSADDR2,LCDSADDR3)
7、确定信号的极性
2440的LCD控制器允许设置VCLK、VLINE、VFRAME等信号的极性(上升沿有效还是下降沿有效),需要对照LCD的Datasheet一一确认。
(相关寄存器LCDCON5)
8、禁止LPC3600/LCC3600模式
如果不是使用三星LPC3600/LCC3600 LCD,必须禁止LPC3600/LCC3600模式(写入0到TCONSEL)。
评论