1. 硬件原理
要使一块LCD正常的显示文字或图像,不仅需要LCD驱动器,而且还需要相应的LCD控制器。在通常情况下,生产厂商把LCD驱动器会以COF/COG的形式与LCD玻璃基板制作在一起,而LCD控制器则是由外部的电路来实现,现在很多的MCU内部都集成了LCD控制器,如S3C2410/2440 等。通过LCD控制器就可以产生LCD驱动器所需要的控制信号来控制STN/TFT屏了。嵌入式LCD主要以薄膜式晶体管型TFT为主流。TFT LCD 特性:
支持每像素1、2、4、8位 调色显示。
支持每像素16位、24位真彩TFT LCD.
支持最大1600万色(24位每像素模式)TFT LCD.
典型实际分辨率:640x480,320x240,160*160
最大虚拟分辨率:4M 字节.
最大虚拟分辨率(65536色) 2048x1024.
下图给出了TFT的典型时序图。
我们先来理解下面引脚有寄存器中相关参数的意义吧
外部引脚信号:
VSYNC: 帧同步信号,表示扫描1帧的开始,一帧就是LCD显示的一个画面。
HSYNC: 行同步信号,表示扫描1行的开始。
VDEN:数据使能信号。
VD[23:0] : LCD像素数据输出端口。
VCLK:像素时钟信号。
寄存器参数:
VSPW:帧同步信号的脉宽,单位为1行(Line)的时间。
VFPD: 帧同步信号的前肩,单位为1行(Line)的时间。
VBPD: 帧同步信号的后肩,单位为1行(Line)的时间。
LINEVAL :帧显示尺寸-1,即屏行宽-1,
HBPD:行同步信号的后肩,单位为1VCLK的时间。
HFPD:行同步信号的前肩,单位为1VCLK的时间。
HSPW:行同步信号的脉宽,单位为1VCLK的时间。
HOZVAL:行显示尺寸-1,即屏列宽-1,
2. 芯片手册
3. mini2440电路图
4. S3C2440寄存器
要想正确使用LCD,必须注意两点:1、时序;2、显示缓存区。
4.1. 时序
LCD一般需要三个时序信号:VSYNC、HSYNC和VCLK。VSYNC是垂直同步信号,在每进行一个帧(即一个屏)的扫描之前,该信号就有效一次,由该信号可以确定LCD的场频,即每秒屏幕刷新的次数(单位Hz)。HSYNC是水平同步信号,在每进行一行的扫描之前,该信号就有效一次,由该信号可以确定LCD的行频,即每秒屏幕从左到右扫描一行的次数(单位Hz)。VCLK是像素时钟信号。s3c2440处理LCD的时钟源是HCLK,通过寄存器LCDCON1中的CLKVAL可以调整VCLK频率大小,它的公式为:
VCLK=HCLK÷[(CLKVAL+1)×2]
例如,HCLK的频率为100MHz,要想驱动像素时钟信号为6.4MHz的LCD屏,则通过上式计算CLKVAL值,结果CLKVAL为6.8,取整后(值为6)放入寄存器LCDCON1中相应的位置即可。由于CLKVAL进行了取整,因此我们把取整后的值代入上式,重新计算VCLK,得到VCLK=7.1MHz。
按理说,对于一个已知尺寸(即水平显示尺寸HOZVAL和垂直显示尺寸LINEVAL已知)的LCD屏,只要确定了VCLK值,行频和场频就应该知道了。但这样还不行的,因为在每一帧时钟信号中,还会有一些与屏显示无关的时钟出现,这就给确定行频和场频带来了一定的复杂性。如在HSYNC信号先后会有水平同步信号前肩(HFPD)和水平同步信号后肩(HBPD)出现,在VSYNC信号先后会有垂直同步信号前肩(VFPD)和垂直同步信号后肩(VBPD)出现,在这些信号时序内,不会有有效像素信号出现,另外HSYNC和VSYNC信号有效时,其电平要保持一定的时间,它们分别叫做水平同步信号脉宽HSPW和垂直同步信号脉宽VSPW,这段时间也不能有像素信号。因此计算行频和场频时,一定要包括这些信号。HBPD、HFPD和HSPW的单位是一个VCLK的时间,而VSPW、VFPD和VBPD的单位是扫描一行所用的时间。在s3c2440中,所有的这些信号(VSPW、VFPD、VBPD、LINEVAL、HBPD、HFPD、HSPW和HOZVAL)都是实际值减1的结果。这些值是通过寄存器LCDCON2、LCDCON3和LCDCON4来配置,只要把这些值配置成与所要驱动的LCD中相关内容的数据一致即可。例如,我们所要显示的LCD屏大小为320×240,因此HOZVAL=320-1,LINEVAL=240-1。水平同步信号的脉宽、前肩和后肩分别为30、20和38,则HSPW=30-1,HFPD=20-1,HBPD=38-1;垂直同步信号的脉宽、前肩和后肩分别为3、12和15,则VSPW=3-1,VFPD=12-1,VBPD=15-1。
下面我们就具体计算一下行频(HSF)和场频(VSF):
HSF=VCLK÷[(HSPW+1)+(HSPD+1)+(HFPD+1)+(HOZVAL+1)]
=7.1÷408=17.5kHz
VSF=HSF÷[(VSPW+1)+(VBPD+1)+(VFPD+1)+(LINEVAL+1)]
=17.5÷270=64.8Hz
在有些情况下,s3c2440的LCD时钟信号的默认极性与所控制的LCD时钟信号的极性相反,这时可以通过寄存器LCDCON5的相关位来改变某些时钟信号的极性。
4.2. 显示缓存区
只要把所要显示的数据放入显示缓存区内,就可以在屏幕上呈现内容。该缓存区是我们自己编程时开辟的一段内存区。一般我们是通过定义一个与屏幕尺寸大小相同的二维数组来开辟该空间的,这样控制屏幕内容会方便一些,如当屏幕的尺寸为320×240时,可以定义该缓存区为LCD_BUFFER[240][320]。由于s3c2440支持16位和24位的非调色板真彩色的TFT型LCD模式,而24位颜色模式是用32位数据来表示的,所以前面定义的那个二维数据的数据类型应该是半字整型或全字整型的。例如,在24位颜色模式下,我们想要在尺寸大小为320×240屏幕的中心处设置为白色像素,则:LCD_BUFFER[120][160]=0xffffffff。
在s3c2440中,寄存器LCDSADDR1和LCDSADDR2用于设置显示缓存区,即把我们定义的那个二维数组告诉s3c2440。其中LCDBANK的9位数据指定LCD的BANK,即显示缓存区的第30位到第22位地址;LCDBASEU的21位数据指定了LCD的基址,即显示缓存区开始地址的第21位到第1位;LCDBASEL的21位数据指定了LCD的尾址,即显示缓存区结束地址的第21位到第1位。例如,我们想要在尺寸为320×240的屏幕上显示24位颜色,定义的显示缓存区数组为LCD_BUFFER[240][320],则LCDBANK等于LCD_BUFFER的第30位到第22位数据值(因为LCD_BUFFER表示的就是数组的首地址),LCDBASEU等于LCD_BUFFER的第21位到第1位数据值,由于是用32位数据表示24为颜色,因此每个像素值是4个字节,所以LCDBASEL等于(LCD_BUFFER+(240×320×4))结果的第21位到第1位的数据值。另外寄存器LCDSADDR3有两个内容:OFFSIZE和PAGEWIDTH。OFFSIZE用于虚拟屏幕的偏移长度,如果我们不使用虚拟屏幕,就把它置为0;PAGEWIDTH定义了视口的宽,单位是半字,如在上面的例子中,PAGEWIDTH应该为320×32÷16。
lcd.h
/*******************************************************************
* Copyright (C),2011-2012, XXX.
* FileName: lcd.h
* Author:HuangYinqing
* Version:1.0
* Date::2012-04-22
* Description:LCD驱动.
* Function List:
* History:
******************************************************************/
#ifndef __LCD_H__
#define __LCD_H__
#define LCD_W35 //320*240/3.5英寸TFT真彩液晶屏
#if defined(LCD_W35)
#define LCD_CLKVAL 7
#define LCD_WIDTH 320
#define LCD_HEIGHT 240
#define LCD_HBPD 0x44 //开始
#define LCD_HFPD 0x4 //结束
#define LCD_HSPW 1 //The width of HSYNC
#define LCD_VBPD 10 //开始
#define LCD_VFPD 4 //结束
#define LCD_VSPW 1 //The width of VSYNC
#endif
#define BPPMODE_1BPP 0x8
#define BPPMODE_2BPP 0x9
#define BPPMODE_4BPP 0xA
#define BPPMODE_8BPP 0xB
#define BPPMODE_16BPP 0xC
#define BPPMODE_24BPP 0xD
#define LCDTYPE_TFT 0x3
#define ENVID_DISABLE 0
#define ENVID_ENABLE 1
#define FRM_5551 0
#define FRM_565 1
#define HSYNC_NORM 0
#define HSYNC_INV 1
#define VSYNC_NORM 0
#define VSYNC_INV 1
#define PWREN 1
#define BSWP 1
#define HWSWP 1
#define M5D( n ) ( ( n ) & 0x1fffff )
#define FREQ_PWM1 1000
void LCDInit(void);
void LCDTest(void);
extern const unsigned char sunflower_240x320[];
#endif
lcd.c
/*******************************************************************
* Copyright (C),2011-2012, XXX.
* FileName: lcd.c
* Author:HuangYinqing
* Version:1.0
* Date::2012-04-22
* Description:LCD驱动.
* Function List:
* History:
******************************************************************/
#include "common.h"
#include "core.h"
#include "drv.h"
//定义240行,320列的数组,用来存放像素数据
//每个像素用16位数据表示 (16BPP模式)
//volatile用来定义可被多线程访问或修改的变量
volatile static unsigned short LCD_BUFFER[LCD_HEIGHT][LCD_WIDTH];
#define LCD_ADDR ( (U32)LCD_BUFFER )
/********************************************************************
函数功能:LCD初始化。
入口参数:无。
返 回:无。
备 注:无。
********************************************************************/
void LCDInit(void)
{
rGPCUP = 0xffffffff;//Disable Pull-up register
rGPCCON = 0xaaaa02a8;//设置GPC各引脚对应引脚功能为 VD[7...0],VM,VFRAME,VLINE,VCLK
rGPDUP = 0xffffffff;//Disable Pull-up register
rGPDCON = 0xaaaaaaaa;//设置VD[15:8]
//bit[17:8](4:CLKVAL);bit[6:5](11:TFT LCD panel);bit[4:1](1100:16BPP for TFT)
rLCDCON1 = ( LCD_CLKVAL<<8 ) | ( LCDTYPE_TFT<<5 ) | ( BPPMODE_16BPP<<1) | ( ENVID_DISABLE<<0 );//设置像素时钟:VPLK=HPLK/((CLKVAL+1)*2)=HPLK/10=
//bit[31:24](1:VBPD);bit[23:14](320-1:行数(320));bit[13:6](5:VFPD);bit[5:0](1:VSPW);
rLCDCON2 = ( LCD_VBPD<<24 ) | ( ( LCD_HEIGHT-1 )<<14 ) | ( ( LCD_VFPD )<<6 ) | ( ( LCD_VSPW )<<0 );
//bit[25:19](36:HBPD);bit[18:8](240-1:列数(240));bit[7:0](19:HFPD);
rLCDCON3 = ( LCD_HBPD<<19 ) | ( ( LCD_WIDTH-1 )<<8 ) | ( LCD_HFPD<<0 );
//bit[15:8](13:MVAL,只有当LCDCON1 bit[7]MMODE=1才有效);bit[7:0](5:HSPW)
rLCDCON4 = ( LCD_HSPW<<0 );
//设置为16BPP模式时为5:6:5格式,VLINE/HSYNC,VFRAME/VSYNC的极性反转,LCD_PWREN信号输出使能,半字交换使能
//rLCDCON5= ( (FORMAT16BPP_565 << 11) | (HSYNC_INV<<9) | (VSYNC_INV<<8) | (ENLEND<<2) | (HWSWP<<0));
rLCDCON5 = ( (FRM_565<<11) | (HSYNC_INV<<9) | (VSYNC_INV<<8) | (PWREN<<3) | ( HWSWP<<0 ) );
/* LCDBANK:视频帧缓冲区内存地址30-22位
LCDBASEU:视频帧缓冲区的开始地址21-1位
LCDBASEL:视频帧缓冲区的结束地址21-1位
*/
//LCD_ADDR为32位,如果只取30-22位,可认为32-31无效
//bit[29:21]:LCDBANK bit[20:0]:LCDBASEU
rLCDSADDR1 = ( ( LCD_ADDR >> 22 ) << 21 ) | ( ( M5D ( LCD_ADDR >> 1 ) ) << 0 );
//bit[20:0]:LCDBASEL 公式
rLCDSADDR2 = M5D ( ( LCD_ADDR + LCD_WIDTH * LCD_HEIGHT * 2 ) >> 1 ); //LCD_ADDR中的第21位移到了第20位,然后我只取0-20位
//BIT[21:11]:OFFSIZE BIT[10:0]:PAGEWIDTH
rLCDSADDR3 = LCD_WIDTH;
//屏蔽中断
rLCDINTMSK |= 3;
//DISABLE 调色板
rTPAL = 0x0;
//禁止LPC3600和LCC3600
rTCONSEL &= ~( ( 1 << 4 ) | 1<<0 );
}
/********************************************************************
函数功能:显示图片。
入口参数:
x0,y0:显示的位置。
h,l:图片的高度和宽度。
pucBmp:位图数据指针。
返 回:无。
备 注:无。
********************************************************************/
void PaintBmp( int x0, int y0, int h, int l, const unsigned char *pucBmp)
{
int x,y;
U32 c;
int p = 0;
for( y = 0 ; y < l ; y++ )
{
for( x = 0 ; x < h ; x++ )
{
c = pucBmp[p+1] | (pucBmp[p]<<8) ;
if ( ( (x0+x) < LCD_WIDTH) && ( (y0+y) < LCD_HEIGHT) )
LCD_BUFFER[y0+y][x0+x] = c ;
p = p + 2 ;
}
}
}
/********************************************************************
函数功能:清屏幕。
入口参数:
usColor:用什么颜色清屏。
返 回:无。
备 注:无。
********************************************************************/
void LCDClearScreen( unsigned short usColor)
{
unsigned int x,y ;
for( y = 0 ; y < LCD_HEIGHT ; y++ )
{
for( x = 0 ; x < LCD_WIDTH ; x++ )
{
LCD_BUFFER[y][x] = usColor ;
}
}
}
/********************************************************************
函数功能:使能LCD电源。
入口参数:
invPwren:极性。
pwren:电源使能。
返 回:无。
备 注:无。
********************************************************************/
static void LCDPowerEnable(int invPwren,int pwren)
{
//GPG4 is setted as LCD_PWREN
rGPGUP = rGPGUP | ( 1 << 4 ); // Pull-up disable
rGPGCON = rGPGCON | ( 3 << 8 ); //GPG4=LCD_PWREN
//Enable LCD POWER ENABLE Function
rLCDCON5 = rLCDCON5 & (~(1<<3)) | (pwren<<3); // PWREN
rLCDCON5 = rLCDCON5 & (~(1<<5)) | (invPwren<<5); // INVPWREN
}
/********************************************************************
函数功能:使能视频输出。
入口参数:
onoff:1:使能;0:禁止。
返 回:无。
备 注:无。
********************************************************************/
static void LCDEnvidOnOff(int onoff)
{
if ( onoff == 1 )
rLCDCON1 |= 1; // ENVID=ON
else
rLCDCON1 = rLCDCON1 & (~0x1); // ENVID Off
}
/********************************************************************
函数功能:背光设置。
入口参数:
HiRatio:占空比。
返 回:无。
备 注:无。
********************************************************************/
void LCDBkLtSet(U32 HiRatio)
{
if(!HiRatio)
{
rGPBCON = rGPBCON & (~(3<<2)) | (1<<2) ; //GPB1设置为output
rGPBDAT &= ~(1<<1);
return;
}
rGPBCON = rGPBCON & (~(3<<2)) | (2<<2) ; //GPB1设置为TOUT1
if( HiRatio > 100 )
HiRatio = 100 ;
rTCON = rTCON & (~(0xf<<8)) ; // clear manual update bit, stop Timer1
rTCFG0 &= 0xffffff00; // set Timer 0&1 prescaler 0
rTCFG0 |= 15; //prescaler = 15+1
rTCFG1 &= 0xffffff0f; // set Timer 1 MUX 1/16
rTCFG1 |= 0x00000030; // set Timer 1 MUX 1/16
rTCNTB1 = ( 100000000>>8 )/FREQ_PWM1; //if set inverter off, when TCNT2<=TCMP2, TOUT is high, TCNT2>TCMP2, TOUT is low
rTCMPB1 = ( rTCNTB1*(100-HiRatio))/100 ; //if set inverter on, when TCNT2<=TCMP2, TOUT is low, TCNT2>TCMP2, TOUT is high
rTCON = rTCON & (~(0xf<<8)) | (0x0e<<8) ;
//自动重装,输出取反关闭,更新TCNTBn、TCMPBn,死区控制器关闭
rTCON = rTCON & (~(0xf<<8)) | (0x0d<<8) ; //开启背光控制
}
/********************************************************************
函数功能:背光控制。
入口参数:无。
返 回:无。
备 注:无。
********************************************************************/
void LCDBackLightControl( void )
{
U8 HiRatio = 50 ;
LCDBkLtSet( HiRatio ) ;
while( 1 )
{
U8 key = Uart0GetChar();
if( key == '+' )
{
if( HiRatio < 100 )
HiRatio += 1 ;
}
if( key == '-' )
{
if( HiRatio > 1 )
HiRatio -= 1 ;
}
if( key == ESC_KEY ) break ;
LCDBkLtSet( HiRatio ) ;
}
}
/********************************************************************
函数功能:LCD测试程序。
入口参数:无。
返 回:无。
备 注:无。
********************************************************************/
void LCDTest(void)
{
LCDInit();
LCDBkLtSet( 70 ) ;
LCDPowerEnable( 0, 1 );
LCDEnvidOnOff( 1 );
//清屏
LCDClearScreen( (0x00<<11) | (0x00<<5) | (0x00<<0) );//5:6:5(红,绿,蓝),参数为一个像素的颜色
delay(1);
LCDClearScreen( (0x1f<<11) | (0x00<<5) | (0x00<<0) );//(15:11)红
delay(1);
LCDClearScreen( (0x00<<11) | (0x3f<<5) | (0x00<<0) );//绿
delay(1);
LCDClearScreen( (0x00<<11) | (0x00<<5) | (0x1f<<0) );//蓝
delay(1);
LCDClearScreen( (0x1f<<11) | (0x3f<<5) | (0x1f<<0) );//三色加起来是白
delay(1);
PaintBmp(0, 0, 240, 320, sunflower_240x320);
delay(1);
LCDBackLightControl();
LCDClearScreen(0xffff);
}
上一篇:mini2440硬件篇之ADC触摸屏
下一篇:mini2440硬件篇之IIC
推荐阅读最新更新时间:2024-03-16 15:22