S3C2440 TFTLCD驱动详解
S3C2440自带有LCD控制器,该控制器主要有以下接口
仅仅说TFT显示器,TFT显示器的时序如下
TFT显示器的驱动是以行列的形式逐点扫描过来的,驱动时钟有三种,一种是行时钟,一种是列时钟,还有一个点时钟, VSYNC低电平期间需要扫描完一列数据, HSYNC低电平期间要写完一个点的数据,vclk负责一个点的每一位数据写入,实际上就是说,如果有a列,b行,一个点需c个VCLK时钟,那么扫描完成需要的中vclk为a*b*c(近似,中间还有一些延时时间)
可以将这个过程看作是1602的刷新过程, VSYNC为低选择一列, HSYNC为低选择一行,然后写入显示数据还需要一个数据时钟,写完之后指针自动增长,中间的等待时间是设备响应时间,在TFT上叫做同步时间,用于时钟的同步,防止时钟混乱
那么现在就有这些参数需要设置
VBPD: VSYNC与VCLK的开始同步时间
VSPW: VHYNC脉冲的高电平宽度
LINEVAL LCD面板的垂直尺寸:
VFPD: VSYNC与VCLK的结束同步时间
HBPD: HSYNC与VCLK的开始同步时间
HFPD: HSYNC与VCLK的结束同步时间
HOZVAL: 决定了LCD面板的水平尺寸
HSPW: HSYNC脉冲的高电平宽度
配置这些参数一般都依靠显示器的数据手册进行配置,我使用群创4.3寸屏幕,数据手册上显示
也就是说,确定一个DCLK时间,剩下的都可以确定了.(配置之前注意IO口功能配置GPIOC和D)
根据这张表,驱动S3C2440的步骤分为以下几步
1. 设置DCLK频率,像素比以及信号输出
2. 确定VSYC的开始同步结束同步以及高电平宽度还有尺寸
3. 3.设置HSYC的开始同步结束同步以及高电平宽度还有尺寸
4. 设置HSPW时间
5. 对于输出的图像格式进行一些选择
6. 设置LCD显示缓冲区相关的数据
然后,CPU系统就会去自动刷新屏幕(使用缓冲区数据),而我们的读出写入都针对于缓冲区,再由显示器接口写入显示器
具体设置请查看程序:
Lcd.c
#include "tftlcd.h" volatile static unsigned short LCD_BUFFER[SCR_YSIZE_TFT][SCR_XSIZE_TFT]; //定义显示缓存区 /**************************************************************
TFT LCD功能模块初始化
**************************************************************/
void LCDInit(void)
{
//配置引脚
rGPCUP = 0x00000000;
rGPCCON = 0xaaaa02a9; rGPDUP = 0x00000000;
rGPDCON= 0xaaaaaaaa; //Initialize VD[15:8] // TFT LCD panel,16bpp TFT,ENVID=off
rLCDCON1=(CLKVAL_TFT<<8)|(MVAL_USED<<7)|(3<<5)|(12<<1)|0;
rLCDCON2=(VBPD<<24)|(LINEVAL_TFT<<14)|(VFPD<<6)|(VSPW);
rLCDCON3=(HBPD<<19)|(HOZVAL_TFT<<8)|(HFPD);
rLCDCON4= HSPW;
rLCDCON5 = (1<<11) | (0<<10) | (1<<9) | (1<<8) | (0<<7) | (0<<6) | (1<<3) |(BSWP<<1) | (HWSWP);
//16位输出格式565,VCLK下降沿取数据等 (看数据手册)这里指定目的地址
rLCDSADDR1=(((u32)LCD_BUFFER>>22)<<21)|M5D((u32)LCD_BUFFER>>1); //单扫描
rLCDSADDR2=M5D( ((u32)LCD_BUFFER+(SCR_XSIZE_TFT*LCD_YSIZE_TFT*2))>>1 );
//LCD_WIDTH×16/16;由于是选择的16位模式,
//如果是24位模式,每个像素4字节则为LCD_WIDTH×32/16
//(LCD_WIDTH在此为LCD_XSIZE_TFT)
rLCDSADDR3=(((SCR_XSIZE_TFT-LCD_XSIZE_TFT)/1)<<11)|(LCD_XSIZE_TFT/1); rLCDINTMSK|=(3); // MASK LCD Sub Interrupt
rTCONSEL &= (~7) ; // Disable LPC3600 rTPAL=0; // 禁止临时调色板寄存器
} /**************************************************************
* LCD视频和控制信号输出或者停止,1开启视频输出
**************************************************************/
void LCDEnvidOnOff(int onoff)
{
if(onoff==1)
rLCDCON1|=1; // ENVID=ON
else
rLCDCON1 =rLCDCON1 & 0x3fffe; // ENVID Off
} /**************************************************************
* TFT LCD 电源控制引脚使能
* pwren=1时,允许PWREN信号
* pwren=0时,禁止PWREN信号
* invpwre=1,PWREN信号极性反转
* invpwre=0,PWREN信号极性正常
**************************************************************/
void LCDPowerEnable(int invpwren,int pwren)
{
//GPG4 is setted as LCD_PWREN
rGPGUP |= (1<<4);//GPG4上拉电阻无效
rGPGCON |= (3<<8); //GPG4=LCD_PWREN
rGPGDAT |= 1<<4 ; //GPG4置1
//invpwren=pwren;
//Enable LCD POWER ENABLE Function
if(pwren)rLCDCON5 |= 1<<3;
else rLCDCON5 &= ~(1<<3);
if(invpwren) rLCDCON5 |= 1<<5;
else rLCDCON5 &= ~(1<<5);
} /**************************************************************
TFT LCD单个象素的显示数据输出
**************************************************************/
void LCDPutPixel(u32 x,u32 y, u32 color )
{
if ( (x < SCR_XSIZE_TFT) && (y < SCR_YSIZE_TFT) )
LCD_BUFFER[(y)][(x)] = color;
} /**************************************************************
TFT LCD全屏填充特定颜色单元或清屏
**************************************************************/
void LcdClearScr( u32 color)
{
unsigned int x,y ; for( y = 0 ; y < SCR_YSIZE_TFT ; y++ )
{
for( x = 0 ; x < SCR_XSIZE_TFT ; x++ )
{
LCD_BUFFER[y][x] = color ;
}
}
}
/**************************************************************
在LCD屏幕上指定坐标点画一个指定大小的图片
**************************************************************/
void LCDPaintBmp(u16 x0,u16 y0,u16 h,u16 l,const unsigned char bmp[])
{
int x,y;
u32 c;
int p = 0; for( y = y0 ; y < l ; y++ )
{
for( x = x0 ; x < h ; x++ )
{
c = bmp[p+1] | (bmp[p]<<8) ;
if ( ( (x0+x) < SCR_XSIZE_TFT) && ( (y0+y) < SCR_YSIZE_TFT) )
LCD_BUFFER[y0+y][x0+x] = c ;
p = p + 2 ;
}
}
} /**************************************************************
*
* LCD屏初始化
*
**************************************************************/
void LcdTFTInit(void)
{
LCDInit();
LCDPowerEnable(0, 1);
LCDEnvidOnOff(1); //turn on vedio
LcdClearScr( (0x00<<11) | (0x00<<5) | (0x00) ); //565格式 纯黑色
} //在指定区域内填充指定颜色
//区域大小:
// (xend-xsta)*(yend-ysta)
void LCDFill(u16 xstart,u16 ystart,u16 xend,u16 yend,u16 color)
{
u16 i,j;
for(i = xstart;i<=xend;i++)
{
for(j = ystart; j <= yend; j++)
{
LCDPutPixel(i,j,color);
}
}
} //画线
//x1,y1:起点坐标
//x2,y2:终点坐标
void LCDDrawLine(u16 xstart, u16 ystart, u16 xend, u16 yend,u16 color)
{
u16 t;
int xerr=0,yerr=0,delta_x,delta_y,distance;
int incx,incy,uRow,uCol; delta_x=xend-xstart; //计算坐标增量
delta_y=yend-ystart;
uRow=xstart;
uCol=ystart;
if(delta_x>0)incx=1; //设置单步方向
else if(delta_x==0)incx=0;//垂直线
else {incx=-1;delta_x=-delta_x;}
if(delta_y>0)incy=1;
else if(delta_y==0)incy=0;//水平线
else{incy=-1;delta_y=-delta_y;}
if( delta_x>delta_y)distance=delta_x; //选取基本增量坐标轴
else distance=delta_y;
for(t=0;t<=distance+1;t++ )//画线输出
{
LCDPutPixel(uRow,uCol,color);//画点
xerr+=delta_x ;
yerr+=delta_y ;
if(xerr>distance)
{
xerr-=distance;
uRow+=incx;
}
if(yerr>distance)
{
yerr-=distance;
uCol+=incy;
}
}
} //画矩形
void LCDDrawRectangle(u16 x1, u16 y1, u16 x2, u16 y2,u16 color)
{
LCDDrawLine(x1,y1,x2,y1,color);
LCDDrawLine(x1,y1,x1,y2,color);
LCDDrawLine(x1,y2,x2,y2,color);
LCDDrawLine(x2,y1,x2,y2,color);
} //在指定位置画一个指定大小的圆
//(x,y):中心点
//r :半径
void LCDDrawCircle(u16 x0,u16 y0,u8 r,u16 color)
{
int a,b;
int di;
a=0;b=r;
di=3-(r<<1); //判断下个点位置的标志
while(a<=b)
{
LCDPutPixel(x0-b,y0-a,color); //3
LCDPutPixel(x0+b,y0-a,color); //0
LCDPutPixel(x0-a,y0+b,color); //1
LCDPutPixel(x0-b,y0-a,color); //7
LCDPutPixel(x0-a,y0-b,color); //2
LCDPutPixel(x0+b,y0+a,color); //4
LCDPutPixel(x0+a,y0-b,color); //5
LCDPutPixel(x0+a,y0+b,color); //6
LCDPutPixel(x0-b,y0+a,color);
a++;
//使用Bresenham算法画圆
if(di<0)di +=4*a+6;
else
{
di+=10+4*(a-b);
b--;
}
LCDPutPixel(x0+a,y0+b,color);
}
}
Lcd.h
#ifndef __TFTLCD_H
#define __TFTLCD_H
#include "2440addr.h"
#include "def.h" //RGB5:6:5颜色定义
#define clWhite 0xFFFF //白色
#define clBlack 0x0000 //黑色
#define clDRed 0x8000 //暗红色,为全色的一半
#define clLRed 0xF800 //亮红色
#define clDMagenta 0x8010 //暗紫色
#define clLMagenta 0xF81F //亮紫色
#define clGreen 0x07E0 //绿色
#define clDBlue 0x0010 //暗蓝色
#define clLBlue 0x001F //亮蓝色
#define clDCyan 0x0410 //暗青色
#define clLCyan 0x07FF //亮青色
#define clDYellow 0x8400 //暗黄色
#define clLYellow 0xFFE0 //亮黄色
#define clDGray 0x8410 //暗灰色
#define clLGray 0xF79E //亮灰色
#define clLArgent 0xCE79 //亮银色 #define MVAL_USED (0) //0=each frame 1=rate by MVAL
#define INVVDEN (1) //0=normal 1=inverted
#define BSWP (0) //Byte swap control
#define HWSWP (1) //Half word swap control
#define PNRMODE (3) // 设置为TFT屏
#define BPPMODE (12) // 设置为16bpp模式 //TFT_SIZE
#define LCD_XSIZE_TFT (480)
#define LCD_YSIZE_TFT (272) #define SCR_XSIZE_TFT (480)
#define SCR_YSIZE_TFT (272) #define HOZVAL_TFT (LCD_XSIZE_TFT-1)
#define LINEVAL_TFT (LCD_YSIZE_TFT-1) //Timing parameter for 4.3' LCD 实际值-1的结果
#define VBPD (1) //垂直同步信号的后肩
#define VFPD (1) //垂直同步信号的前肩
#define VSPW (7) //垂直同步信号的脉宽 #define HBPD (1) //水平同步信号的后肩
#define HFPD (1) //水平同步信号的前肩
#define HSPW (40) //水平同步信号的脉宽 #define CLKVAL_TFT (2) //时钟分频因子,VCLK = HCLK/((CLKVAL_TFT+1)*2) #define M5D(n) ((n) & 0x1fffff) //用于设置显示缓存区时,取低21位地址 void LcdTFTInit(void);
void LCDFill(u16 xstart,u16 ystart,u16 xend,u16 yend,u16 color);
void LCDDrawLine(u16 xstart, u16 ystart, u16 xend, u16 yend,u16 color);
void LCDDrawRectangle(u16 x1, u16 y1, u16 x2, u16 y2,u16 color);
void LCDDrawCircle(u16 x0,u16 y0,u8 r,u16 color); #endif
注意,触摸屏不打开cache 和打开cache的速度是不同的(一个要每次去sram取指写入数组,一个直接在内部cache中写入数据),但是打开了cache之后用到延时函数的的驱动可能会遭遇到延时时间大大缩短导致设备驱动不起来的情况(比如at24c02,写入读出太快,设备反应不过来,设备没反应,驱动包错)
S3C2440 TFTLCD驱动详解的更多相关文章
- S3C2440触摸屏驱动详解
2440的触摸屏转换接口搭载在ADC接口之上,使用上比ADC接口多了一些花样,首先,触摸屏接口有几种转换模式 1. 普通转换模式 单转换模式是最合适的通用ADC转换.此模式可以通过设置ADCCON(A ...
- linux usb 驱动详解
linux usb 驱动详解 USB 设备驱动代码通过urb和所有的 USB 设备通讯.urb用 struct urb 结构描述(include/linux/usb.h ). urb 以一种异步的方式 ...
- 25.Linux-Nor Flash驱动(详解)
1.nor硬件介绍: 从原理图中我们能看到NOR FLASH有地址线,有数据线,它和我们的SDRAM接口相似,能直接读取数据,但是不能像SDRAM直接写入数据,需要有命令才行 1.1其中我们2440的 ...
- 16.Linux-LCD驱动(详解)
在上一节LCD层次分析中,得出写个LCD驱动入口函数,需要以下4步: 1) 分配一个fb_info结构体: framebuffer_alloc(); 2) 设置fb_info 3) 设置硬件相关的操作 ...
- 使用VS2010编译MongoDB C++驱动详解
最近为了解决IM消息记录的高速度写入.多文档类型支持的需求,决定使用MongoDB来解决. 考虑到MongoDB对VS版本要求较高,与我现有的VS版本不兼容,在leveldb.ssdb.redis.h ...
- 16.Linux-LCD驱动(详解)【转】
转自:https://www.cnblogs.com/lifexy/p/7604011.html 在上一节LCD层次分析中,得出写个LCD驱动入口函数,需要以下4步: 1) 分配一个fb_info结构 ...
- 18.Llinux-触摸屏驱动(详解)
本节的触摸屏驱动也是使用之前的输入子系统 1.先来回忆之前第12节分析的输入子系统 其中输入子系统层次如下图所示, 其中事件处理层的函数都是通过input_register_handler()函数注册 ...
- 18.Llinux-触摸屏驱动(详解)【转】
转自:https://www.cnblogs.com/lifexy/p/7628889.html 本节的触摸屏驱动也是使用之前的输入子系统 1.先来回忆之前第12节分析的输入子系统 其中输入子系统层次 ...
- 13.Linux键盘驱动 (详解)
版权声明:本文为博主原创文章,未经博主允许不得转载. 在上一节分析输入子系统内的intput_handler软件处理部分后,接下来我们开始写input_dev驱动 本节目标: 实现键盘驱动,让开发板的 ...
随机推荐
- linux通用邻居基础架构
1.为每一个协议提供一个缓存来存放L3到L2的转换结果. 2.提供在缓存中添加.删除.改变和查找一个特定映射项的函数.查找函数必须要快,因为它会影响整个系统的性能. 3.为每一个协议缓存的数据项提供一 ...
- Java成员变量默认值
Java中明确规定:1.如果是引用型的,比如:String,还有类对象,他们的默认值都是:null:2.而如果是值类型:double,int,long,float,char等等,他们都是:0:还有一个 ...
- SonarQube代码质量管理平台比较好的搭建和使用资料
http://www.voidcn.com/blog/lidujun1028/article/p-3831235.html Sonar (SonarQube)是一个开源平台,用于管理源代码的质量. ...
- zencart url特殊字符处理
1. 支持 在后台的seo url 将Outputw3c 改为false 2.删除特殊字符 这对于在少量的zen cart网站上处理少量的特殊字符可能还适用,实际上我们经常在导入产品数据时或者或少会带 ...
- jq的事件冒泡
在页面上可以有多个事件,也可以多个元素响应同一件事, 事件冒泡引发的问题: 有些时候不想动用的事件,却因为事件冒泡而触发 解决问题: 1.事件对象 由于IE-DOM和标准的DOM实现事件对象的方法各不 ...
- Delphi MaskEdit用法(转)
源:http://www.cnblogs.com/zhangzhifeng/archive/2011/10/12/2208640.html MaskEdit是用来建立编辑框的,但它与Edit编辑框可以 ...
- ViewController加载顺序与self.view
转载自:http://blog.csdn.net/ishaoc/article/details/42172749 ViewController的加载顺序如下 从Stroyboard和xib中加 ...
- Android Studio调试功能使用总结---转
Android Studio调试功能使用总结[转] 这段时间一直在使用Intellij IDEA, 今天把调试区工具的使用方法记录于此. 先编译好要调试的程序. 1.设置断点 选定要设置断点的代码 ...
- HDU 4287 Intelligent IME(字典树)
在我没用hash之前,一直TLE,字符串处理时间过长,用了hash之后一直CE,(请看下图)我自从经历我的字典树G++MLE,C++AC以后,一直天真的用C++,后来的CE就是因为这个,G++才支持这 ...
- 使用virsh命令创建KVM虚拟机快照
查看虚拟机所在主机和虚拟机名称:[root@node-1 ~]# nova show a88dcf5d-c8b2-46a5-af27-a176d8235c9d|grep hyper| OS-EXT-S ...