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驱动 本节目标: 实现键盘驱动,让开发板的 ...
随机推荐
- ReactiveX--响应式编程の相关概念 浅析
在许多软件编程任务中,你或多或少期待你的指令将会按照你已经写好的顺序,依次增量执行和完成.但在ReactiveX,很多指令可以通过“观察者”并行执行,其结果将以任意顺序被捕获.你定义了一种“可观察的形 ...
- java基本输入类型数据System.out.println()或System.out.print()
- eclipse没有(添加)"Dynamic Web Project"选项的方法【转载】
第一种方法: 你安装的是专门开发java项目的,而Dynamic Web Project 属于J2EE技术,所以你要专门下载一个集成了J2EE插件的Eclipse,(eclipse-jee-heli ...
- Android多线程下安全访问数据库
http://zhiwei.neatooo.com/blog/detail?blog=5343818a9d4869f0310000de github 原文https://github.com/dmyt ...
- 转:LoadRunner中参数化技术详解
LoadRunner中参数化技术详解 LoadRunner在录制脚本的时候,只是忠实的记录了所有从客户端发送到服务器的数据,而在进行性能测试的时候,为了更接近真实的模拟现实应用,对于某些信息需要每次提 ...
- s5pv210 AD转换
1:ADC:Analog-to-Digital Converter,模拟信号转数字信号,自然界一般为模拟信号,而SoC需要数字信号,所以之间通信需要ADC. 2:转换原理: 以逐次逼近式AD转换为例: ...
- JavaBean-- DAO设计模式
企业分层架构: 资源层:主要是数据库的操作层,里面可以进行各种数据存储,但是这些数据存储操作的时候肯定依靠SQL语句,如果在一个程序中出现过多的SQL语句,JSP页面非常复杂,不便于程序的可重用性 数 ...
- C# 中的内存管理,摘自网络
C#编程的一个优点是程序员不需要关心具体的内存管理,尤其是垃圾收集器会处理所有的内存清理工作.虽然不必手工管理内存,但如果要编写高质量的代码,还是要理解后台发生的事情,理解C#的内存管理.本文主要介绍 ...
- u-boot添加一个hello命令
1.在common目录下建立一个cmd_hello.c文件 2.仿照/common/cmd_bootm.c文件修改,把cmd_bootm.c头文件复制过来 3.再复制do_bootm.U_BOOT_C ...
- Win7+QTP10.0+IE9无法识别对象的解决方法
在WIN7和IE9环境下使用QTP10,会出现识别不了web对象的情况,具体表现为:添加对象,先打开对象库,再打开IE,点击Add object to local 后,出现白色手指,将其拖拉到百度首页 ...