LCD初步测试

1、lcd基本知识

今天这篇文章来介绍使用s3c2440来操作lcd的过程,在开始之前首先来介绍关于lcd的一些概念。
lcd就是我们常说的显示设备,常用的是TFT lcd和STN lcd,lcd能显示一张图片就是因为在它内部存在一个电子枪,
电子枪把缓存里的数据拿出来一个一个打到显示屏上,根据显示屏的分辨率来决定发出多少数据,
在这里插入图片描述
关于更多它内部的工作细节我们在此不去深究,了解它的大概的工作原理就行,但是我们还需要明确几点才能往下继续

1、电子枪如何移动,也就是打下一个点?
   答:lcd根据外部提供的脉冲信号vclk,每来一个vclk,电子枪就移动到下一个位置
2、电子枪如何跳到下一行? 
   答:电子枪移动到一行的最后一个位置时,就会接受到一个信号(HSYNC),也就是水平
      同步信号,移动到下一行
3、电子枪如何跳到原点?         
   答:当电子枪移动到最后一行的最后一个点时,就需要移动到原点去,这时候会收到一个
       垂直同步信号VSYNC,电子枪才会移动到原点,我们常说的一帧数据就是“一屏”像素,那么,
       VSYNC是在一帧数据显示之前就必须有效的。
4、显示的颜色如何确定? 
   答:显示屏上显示的是缓存中的数据,这些数据是有格式的,叫做bpp,就是每一个像素的格式,
       由红绿蓝三种颜色组成,如果显示的数据格式是5-6-5(16)bpp,那么每一个像素就由16bit数据组成。

好了,到这里我们就已经了解了lcd要显示数据的基本概念了,接下来就来看看s3c2440上面的lcd控制

2、S3C2440 lcd

在这里插入图片描述
我们使用的是TFT lcd,它支持很多种显示格式,在下面的测试里用的是16bpp,下面这张图列举的是lcd的外接信号,这些信号我们会在下面
详细介在这里插入图片描述
来简单说一下显示格式,就拿16BPP来说,那么一个像素在内存里所占的地址空间是16bit,2个字节的空间,可以通过配置BSWP和HWSWP的值来决定他们在缓存里存放的格式,第一种是低字节存放在高地址处,第二种是第字节存放在地地址处,显然第二中更符合我们的编程习惯。
在这里插入图片描述
好了,接下来我们来看看重要的内容,就是lcd的信号时序,决定着lcd控制器能否正常的工作
在这里插入图片描述

这个时序图里包含了我们要处理的一些信号,这个图刚开始比较难懂,需要仔细的看才能看清楚它的内容
1、在前面我们知道 VSYNC 是垂直同步信号,它必须在显示一帧数据之前有效,在它变为高电平(有效之后)  
   开始显示数据。
2、VSPW+1表示VSYNC的脉冲宽度为VSPW+1个HSYNC信号周期,HSYNC信号是行同步信号,所以,也就是说,在 
   VSYNC信号有效之后,(VSPW+1)行个数据是无效的,
3、接着看,经过VBPD+1个HSYNC信号之后,有效的数据行才出现,也就是在VSYNC信号有效之后,总共经历了 
   (VBPD+1 + VSPW+1)行才开始显示数据,这也就是显示屏上面的黑框
4、随后发出LINEVAL+1行有效数据。
5、在有效数据显示完之后,还要经过VFPD+1个无效的行,VSYNC信号才来显示下一帧数据,也就是显示器下边的黑框。

下面的图是显示行的具体过程
1、行(水平)同步信号HSYNC有效之后,表示一行数据显示的开始,
2、HSYNC信号脉冲的宽度是HSPW+1个VCLK信号周期,也就是HSPW+1个像素无效,         
3、紧接着HBPD+1个VCLK信号周期之后,有效数据才开始显示,也就是显示屏左边的黑框一共是(HBPD+1+HSPW+1)个像素
4、随后发出HOZVAL+1个有效像素的数据
5、显示完一行有效的数据之后,还要显示HFPD+1个无效的数据,下一个HSYNC信号才来到,也就是右边的黑框

实际的显示效果如下图所示那样
在这里插入图片描述

3、编程前准备

这一节的内容为编写程序做准备,我们需要确定lcd的时序要求和引脚的配置,因为s3c2440上面的lcd控制器和4.3寸的lcd数据手册中的时序可能是不一样的,所以,要进行对比之后才可以进行编写程序
在这里插入图片描述

上面的图片是我从数据手册中截取出来的,左边的是s3c2440数据手册中的lcd时序图,右边的是4.3寸lcd数据手册的时序图
我们先来解决第一个问题
1、信号的极性	
	s3c2440
	VSYNC : 高电平有效	HSYNC : 高电平有效
	VCLK  : 下降沿读取数据	VDEN  : 高电平有效
	4.3寸lcd
	VSYNC : 下降沿有效	HSYNC : 下降沿有效
	VCLK  : 下降沿读取数据	VDEN  : 高电平有效
 通过对比我们得出结论,s3c2440的lcd时序VSYNC和HSYNC信号需要反转,其他的不需要
2、信号持续时间
对比上面两张图中相同的部分,可以得出信号的脉冲时间
	VSPW+1 = tvp		VBPD+1 = tvb 	
	VFPD+1 = tvf		LINEVAL+1 = tvd
	HSPW+1 = thp		HBPD+1 = thb
	HFPD+1 = thf		HOZVAL+1 = thd
在4.3寸lcd的数据手册中寻找上面的信号的值

在这里插入图片描述

tvp典型值为10,VSPW = tvp- 1 = 9		tvb典型值为2, VBPD = tvb - 1 = 1
tvf典型值为2, VFPD = tvf - 1 = 1	tvd表示行数为272,LINEVAL = tvd - 1 = 271
thp典型值为41,HSPW = thp - 1 = 40	
thb和thf没有给出典型值,但是thf+ thp+ thb﹥44 CLK,所以取他们的最小值2
HBPD = thb - 1 = 1	HFPD = thf - 1 = 1
HOZVAL = thd - 1 = 480 - 1 = 479

接下来需要处理lcd的引脚问题了,在s3c2440原理图上找到cd,看它的引脚要满足那些条件
在这里插入图片描述
其中VD是RGB数据引脚,可将这些引脚都配置为lcd专用引脚,VCLK也接到了普通GPIO上了,将VCLK和VFRAME都配置为lcd使用引脚,这些不再多说,需要注意的是Von和Voff,从名字上来看好像是开关,没错,它们接到了lcd的电源电路
在这里插入图片描述
该电源电路有效的前提是LCD_PWREN引脚输入高电平,LCD_PWREN接到了GPG4引脚上,将其配置为lcd使用引脚,需要注意的是这个引脚不用我们配置输出是高还是低,它是由lcd控制寄存器LCDCON5的bit3和bit5控制,
在这里插入图片描述
最后一个引脚是lcd的背光驱动引脚,KEYBOARD接入到了GPB0引脚上,该引脚输出高点平打开lcd背光,输出低电平关闭lcd背光,需要注意的是,KEYBOARD是lcd的背光电路的开关,这个引脚在使能和禁止的函数里可以进行输出设置,上一个引脚LCD_PWER是lcd设备的电源引脚,不要混淆了。

4、编写程序

接下来,我们来编写S3c2440的lcd程序,我们打开s3c2440的数据手册,来配置所有的lcd的寄存器,寄存器的原始内容在这里就不写了
我只列举出我们需要处理的位就行了
lcd.c

#define LCD_FB_BASE 0x33c00000		//缓存的地址
#define XRES 480			//列
#define YRES   272			//行

//lcd使用到的引脚初始化
void lcd_pin_init()
{	
	 /*GPD2 - 12  VD10-20 */
	 GPDCON = 0xaaaaaaaa; 
 	/*GPC11-15  VD3-7  */
 	/* GPC1 -> vclk   这些引脚都配置为lcd专用引脚 */
 	GPCCON = 0xaaaaaaaa;

 	/* GPB0   -> 背光KEYBOARD   输出(使能1)*/
 	GPBCON  &=  ~(3 << 0);
 	GPBCON |= (1 << 0);

	 /* GPG4  -> LCD_PWREN  输出(使能1) */
 	GPGCON  |= (3 << 8);
}


/* 配置lcd寄存器 */
void lcd_init()
{
	unsigned int addr;
	/*
	   LCDCON1
	   [17:8] CLKVAL  计算公式VCLK = HCLK / [(CLKVAL+1) x 2]
	   	  时钟配置HCLK是100Mhz       VCLK在lcd数据手册中找到典型值是9Mhz
	   	  9 = 100 / [(CLKVAL + 1 ) *2]        CLKVAL = 4.5取5
	   [6:5]  PNRMODE  11对应的是tft显示器   
           [4:1]  BPPMODE  1100 对应16 bpp的TFT显示格式
           [0]   ENVID   输出和逻辑启用 0-disable  这一位在下面的使能和禁用函数里用到	  	 
	*/
	LCDCON1 = (5 << 8) | (3 << 5) | (0xc << 1);
 	/*
           LCDCON2
   	   [31:24] VBPD      tvb-1  
  	   [23:14] LINEVAL   YRES-1
  	   [13:6] VFPD	     tvf-1
  	   [5:0] VSPW        tvp-1
 	*/
 	LCDCON2 = (1 << 24)  | (1 << 6) | (9 << 0) | ((272-1) << 14);
	 /*
	    [25:19] HBPD   thb-1
	    [18:8] HOZVAL  XRES-1
	    [7:0] HFPD     thf-1
	 */
	 LCDCON3 = (1 << 19)  | ((480-1) << 8) | (1 << 0);
	 /*
  	    [7:0]  HSPW  thp-1
 	 */
 	LCDCON4 = (40 << 0);
	
	 /*
  		[11] FRM565  		1 对应 5:6:5 的显示格式
  		[10] INVVCLK 		设置vclk的信号极性  0 对应vclk下降沿读取数据 (我们使用下降沿)
    		[9]  HSYNC信号极性  	1 需要反转
  		[8]  VSYNC信号   	1需要反转
    		[7]  VD(RGB)信号		0 = Normal,一般是常规的,高电平表示1,
  		[6]  VDEN  		0 normal		
    		[5]  PWREN  		power_enable信号极性,0-正常 高电平有效
  		[3]  PWREN   		power_enable信号启用0-disable 该位有效时,bit5输出高电平,在下边的使能函数里用到 
  	*/
	LCDCON5 = (1 << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (0 << 7) | (0 << 6) | (0 << 5); 
	
	 /*
		  * [29:21] : LCDBANK, A[30:22] framdbuffer地址的22-30位
		  * [20:0]  : LCDBASEU, A[21:1] framebuffer地址的1-21位
	 */
	  addr = LCD_FB_BASE & (~(1<<31));
	 LCDSADDR1 = (addr >> 1);
	
 	/* 
 		 * [20:0] : LCDBASEL, A[21:1] framebuffer的结束地址的1-21位
  	*/
 	addr = LCD_FB_BASE + XRES * YRES * 16 / 8;
 	addr >>= 1;
 	addr &= 0x1fffff;
 	LCDSADDR2 = addr;// 
}

//lcd使能配置
void lcd_enable()
{
 /* 背光引脚 : GPB0  输出高电平*/
 GPBDAT |= (1<<0);
 //lcd的输出和逻辑启用
 LCDCON1 |= (1 << 0);
 /* pwren 该位为1,powe_enable输入高电平,有效  */
 LCDCON5 |= (1<<3);
}

void lcd_disable()
{
 /* 背光引脚 :关闭背光*/
 GPBDAT &= ~(1<<0);
  /* 该位为0,power_enable输出低电平,无效  */
 LCDCON5 &= ~(1<<3);
  /* LCDCON1'BIT 0 : 设置LCD控制器是否输出信号 */
 LCDCON1 &= ~(1<<0);
}

void lcd_test()
{
 int i,j;
 unsigned short *p;
  //红色
 p = (unsigned short *)LCD_FB_BASE;
 for (i = 0; i < XRES; i++)
  for (j = 0; j < YRES; j++)
   *p++ = 0xf800;
 //绿色
 p = (unsigned short *)LCD_FB_BASE;
 for (i = 0; i < XRES; i++)
  for (j = 0; j < YRES; j++)
   *p++ = 0x7e0;
 //蓝色
 p = (unsigned short *)LCD_FB_BASE;
 for (i = 0; i < XRES; i++)
  for (j = 0; j < YRES; j++)
   *p++ = 0x1f;
}

ok,lcd的函数已经写完,在主函数里一次调用lcd_init(),lcd_enable, lcd_test();就可以看完lcd显示屏上显示出的画面
在这里插入图片描述

发布了33 篇原创文章 · 获赞 2 · 访问量 1013

猜你喜欢

转载自blog.csdn.net/weixin_41791581/article/details/105162092