裸机LCD驱动设置
参考:http://www.cnblogs.com/lifexy/p/7144890.html
横屏4.3寸LCD为480*272(一行:480个像素点 一列:272个行)
1、1.1 LCD原理图:
Pin1-Pin6:Von/Voff 电源正/负(由GPG4控制,高电平要效)
Pin2:VM、VDEM 数据使能信号(0:表示正在跳行,1:表示可以传输像素数据)
Pin8:VLINE/HSYNC 水平同步信号(每扫完一行,即发一次水平同步信号)
Pin28:VFRAME/VSNC 垂直同步信号(每扫完一屏,即发一次垂直同步信号)
Pin30:VCLK 始终信号
Pin42,Pin45 LED+,LED- 背光显示开关(由0:off 1:no)
VD23~VD19:R信号
VD15~VD10:G信号
VD7~VD3 :B信号
KEYBOARD:背光电路
LCD PWREN:LCD电源
只有LCD电源和LCD背光电路接通后,LCD才会亮起来。
数据是采用16Bpp像素,RGB565格式(因为LCD控制器不支持18Bpp格式)
1.2 配置引脚
//参考以前的裸机程序lcddrv.c
*gpccon = 0xaaaaaaaa; /* GPIO管脚用于VD[7:0],LCDVF[2:0],VM,VFRAME,VLINE,VCLK,LEND */
*gpdcon = 0xaaaaaaaa; /* GPIO管脚用于VD[23:8] */
*gpbcon &= ~(3); /* GPB0(KEYBOARD)设置为输出引脚 */
*gpbcon |= 1;
*gpbdat &= ~1; /* 输出低电平,背光先不开启 */
*gpgcon |= (3<<8); /* GPG4用作LCD_PWREN */
2、 设置LCDCON1~5控制器
2.1 BSWP和HWSWP介绍
更改存储格式,对于16BppRGB565(高数据在后)来说,BSWP=0,HWSWP=1
2.2 查看2440中LCD控制器初始状态时序图
VSPW:垂直同步脉冲宽度 pulse width
VBPW:垂直脉冲后延延迟(用来等待LCD模块响应的时间)back delay
VFPD:垂直脉冲前沿延迟(用来等待LCD模块响应的时间)Front delay
HSPW:行同步脉冲宽度pulse width
HBPD:行脉冲后沿延迟(用来等待LCD模块响应的时间)back delay
HFPD:行脉冲前沿延迟(用来等待LCD模块响应的时间)Front delay
LINEVAL:行数,用来决定垂直尺寸,对于4.3寸,LINEWAI=272-1
HOZVAL:行数,用来决定水平像素点个数,对于4.3寸时,HOZVAL=480-1
2.3 查看LCD芯片手册时时序图,计算周期时间:
从上图1中可以得到时钟周期(Clock cycle)为9MHz。
从LCD控制器初始状态时序图、图1和图2计算出:(LCD控制器初始状态时序图 和 图2对应着来看)
垂直方向:
tvb=2,VBPD+1=tvb,VBPD=1
tvd=272,LINEVAL+1=tvd,LINEVAL=271
tvf=2,VFPD+1=tvf,VFPD=1
tvp=10,VSPW+1=TVP,VSPW=9
水平方向:
thb=2,HBPD+1=thb,HBPD=1
thd=480,HOZVAL+1=thd,HOZVAL=479
thf=2,HFPD+1=thf,HFPD=1
thp=41,HSPW+1=thp,HSPW=40
设置LCDCON1寄存器:
CLKVAL[17:8]:
设置VCLK时钟,TFT,CLKVAL=HCLK/(LCD时钟*2)-1
本裸板的HCLK=100Mhz,LCD时钟为9MHZ,所以CLKVAL=4
PNRMODE[6:5]:
设置为TFT模式,PNRMODE = 0x3
BPPMODE[4:1]:
设置为16BPP,BPPMODE=0x0C
ENVID[0]:
控制PWREN信号(GPF4)输出,先配置好再输出PWREN,ENVID=0
(开启之前应该设置LCDCON5位[3]允许PWREN信号才有效)
设置LCDCON2寄存器:
VBPD[32:24]:垂直脉冲后沿延时,VBPD=1
LINEVAL[23:14]:垂直行数,决定垂直大小,LINEVAL=271
VFPD[13:6]:垂直脉冲前沿延时,VFPD=1
VSPW[5:0]:垂直同步脉冲宽度,VSPW=9
设置LCDCON3寄存器:
HBPD[25:19]:水平脉冲后沿延时,HBPD=1
HOZVAL[18:8]:水平像素点个数,HOZVAL=479
HFPD[7:0]:水平脉冲前沿延时,HFPD=1
设置LCDCON4寄存器:
HSPW[7:0]:水平同步脉冲宽度,HSPW=40
设置LCDCON5寄存器:
FRM565[11]:设置16bpp输出模式,FRAM565=1(RGB565);
INVVCLK[10]:设置VCLK极性,我们可以看时序图的VD和相对应的VSYNC,所以等于0,下降沿读取
INVVLINE[9]:HSYNC水平同步信号反转,因为LCD手册和2440手册不一样,所以INVVLINE=1;
INVVFRAME[8]:VSYNC垂直同步信号反转,因为LCD手册和2440手册不一样,所以INVVFRAME=1;
PWREN[3]:PWREN信号(GPG4)允许文,=0,不设置,等设置了缓存寄存器后才设置
HWSWP[0]:更改存储格式,这里HWSWP=1,BSWP等于0,使我们的LCD像素显示从低到高排列
上述代码如下:
lcd_regs->lcdcon1 = (4<<8) | (3<<5) | (0x0c<<1);
lcd_regs->lcdcon2 = (1<<24) | (271<<14) | (1<<6) | (9);
lcd_regs->lcdcon3 = (1<<19) | (479<<8) | (1);
lcd_regs->lcdcon4 = 40;
lcd_regs->lcdcon5 = (1<<11) | (0<<10) | (1<<9) | (1<<8) | (1<<0);
3、设置LCDSADDR1~3缓冲地址寄存器
设置LCDSADDR1寄存器:
LCDBANK[29:21]:
保存缓冲起始地址A[30:22]
LCDBASEU[20:0]:
保存缓冲起始地址A[21:1]
(第0位和最高位被忽略了。。)
设置LCDSADDR2寄存器:
LCDBASEL[20:0]:保存缓冲结束地址A[21:1],这里我们采用4.3寸LCD,所以等于
((s3c_lcd->fix.smem_start + s3c_lcd->fix.smem_len) >> 1) & 0x1fffff; //结束地址=开始地址+长度,只关心21位
设置LCDSADDR3寄存器:
OFFSIZE[21:11]:
保存LCD上一行结尾和下一行开头的地址之间的差(半字数为单位),我们使用的是连续地址,所以不设置,默认为0
PAGEWIDTH[10:0]:
保存LCD一行占的宽度(半字数为单位),我们每个像素点是半字数,所以等于480。
代码如下:
lcd_regs->lcdsaddr1 = (s3c_lcd->fix.smem_start >> 1) & ~(3<<30); //第0位和最高位忽略
lcd_regs->lcdsaddr2 = ((s3c_lcd->fix.smem_start + s3c_lcd->fix.smem_len) >> 1) & 0x1fffff; //结束地址=开始地址+长度,只关心21位
lcd_regs->lcdsaddr3 = (480*16/16); /* 一行的长度(单位:半字,就是2个字节) */
4、 启动LCD,并使能背光灯
/* 启动LCD */
lcd_regs->lcdcon1 |= (1<<0); /* 使能LCD控制器 */
lcd_regs->lcdcon5 |= (1<<3); /* 使能LCD本身 */
*gpbdat |= 1; /* 原来输出低电平,现在输出高电平,使能背光灯 */