LCD裸机驱动程序总结:
LCD裸机驱动程序流程:
一、LCD初始化:
1、端口初始化:设置GPC和GPD为LCD输出端口模式
2、显示模式初始化:
LCDCON1:选择BBP(位每像素)模式、选择显示模式、决定VLCK频率
LCDCON2:bit[31:24](1:VPBD)、bit[23:14](320-1:行数)、bit[13:6](5:VFPD)、bit[5:0](1:VSPW)
LCDCON3:bit[25:19](36:HBPD);bit[18:8](240-1:列数);bit[7:0](19:HFPD)
LCDCON4:bit[15:8](13:MVAL,只有当LCDCON1 bit[7]MMODE=1才有效);bit[7:0](5:HSPW)
LCDCON5:bit[11](5:6:5 Format)
3、帧缓初始化:设置帧缓冲器的起始地址、结束地址、虚拟屏
4、LCD其他杂项设置:屏蔽中断、调色板、禁止LPC3600/LCC3600模式
5、LCD开启和关闭:LCDCON1的第0位置1即可开启LCD
二、LCD显示:由于一帧中有240*320个像素点,每个像素点都有一个值(0-255),那么把每个像素点的值送到帧缓冲器中,即可实现显示功能。 如果想显示图片的话,需要把一张图片转化成数据,然后在程序中把每一个像素点送到帧缓冲器即可。
源程序:
//Main.c
/*************************************************
实验环境:mini2440开发板
完成时间:2011,4,15
作者:阿龍
实现功能:在LCD上进行显示
遇到的问题:
**************************************************/
#define GLOBAL_CLK 1
#include <stdlib.h>
#include <string.h>
#include "def.h"
#include "option.h"
#include "2440addr.h"
#include "2440lib.h"
#include "2440slib.h"
#include "mmu.h"
#include "profile.h"
#include "memtest.h"
#define CLKVAL 4
#define LCD_LONG 320
#define LCD_WIDTH 240
#define LINEVAL LCD_LONG-1
#define LCD_YSIZE LCD_LONG
#define LCD_XSIZE LCD_WIDTH
#define LCD_UPPER_MARGIN 1
#define LCD_LOWER_MARGIN 5
#define LCD_VSYNC_LEN 1
#define LCD_RIGHT_MARGIN 39
#define LCD_LEFT_MARGIN 16
#define LCD_HSYNC_LEN 5
#define SCR_XSIZE LCD_XSIZE
#define SCR_YSIZE LCD_YSIZE
volatile static unsigned short LCD_BUFFER[SCR_YSIZE][SCR_XSIZE];
#define LCD_ADDR ((U32)LCD_BUFFER)
#define M5D(n) ((n)&0x1fffff)
#define PAGEWIDE LCD_WIDTH
#define OFFSIZE 0
#define LCD_RIGHT_MARGIN 39
#define LCD_LEFT_MARGIN 16
#define LCD_HSYNC_LEN 5
#define ADC_FREQ 2500000
extern unsigned char sunflower_240x320[];
/**************************************************
函数声明
***************************************************/
void delay(int times);
void LCD_init(void);
void LCD_port_init(void);
void DisM_init(void);
void FraBuf_init(void);
void MASK(void);
static void Lcd_EnvidOnOff(int num);
void TFT_LCD_Show(void);
static void Lcd_ClearScr(U16 c);
static void Pait_Bmp(int x0,int y0,int h,int l,const unsigned char *bmp);
void Set_Clk(void);
static void cal_cpu_bus_clk(void);
/**************************************************
主函数
***************************************************/
void Main(void)
{
/*时钟初始化*/
Set_Clk();
//MMU_Init(); //不能用MMU_Init()
/*LCD初始化*/
LCD_init();
/*LCD显示*/
TFT_LCD_Show();
}
void delay(int times)
{
int x,y;
for(x=times;x>0;x--)
for(y=400;y>0;y--);
}
/*********************************************************
LCD初始化
**********************************************************/
void LCD_init(void)
{
/*LCD端口初始化*/
LCD_port_init();
/*显示模式初始化*/
DisM_init();
/*LCD帧缓冲初始化*/
FraBuf_init();
/*LCD其他杂项屏蔽和处理*/
MASK();
/*LCD开启和关闭*/
Lcd_EnvidOnOff(1);
}
/**************************************************
LCD端口初始化
***************************************************/
void LCD_port_init(void)
{
rGPCCON = 0xaaaa02a8; //设置GPC为LCD模式
rGPCUP = 0xffffffff;
rGPDCON =0xaaaaaaa;
rGPCUP =0xffffffff;
}
/*********************************************************
LCD显示模式初始化
**********************************************************/
void DisM_init(void)
{
/*bit[17:8](4:CLKVAL);bit[6:5](11:TFT LCD panel);bit[4:1](1100:16 bpp for TFT)*/
rLCDCON1 = (12<<1)|(3<<5)|(CLKVAL<<8); //选择BBP(位每像素)模式、选择显示模式、决定VCLK频率
/*bit[31:24](1:VBPD);bit[23:14](320-1:行数);bit[13:6](5:VFPD);bit[5:0](1:VSPW)*/
rLCDCON2 = (LCD_UPPER_MARGIN<<24)|((LCD_YSIZE-1)<<14)|(LCD_LOWER_MARGIN<<6)|(LCD_VSYNC_LEN<<0);
/*bit[25:19](36:HBPD);bit[18:8](240-1:列数);bit[7:0](19:HFPD)*/
rLCDCON3 = (LCD_RIGHT_MARGIN <<19)|((LCD_XSIZE-1)<<8)|(LCD_LEFT_MARGIN<<0);
/*bit[15:8](13:MVAL,只有当LCDCON1 bit[7]MMODE=1才有效);bit[7:0](5:HSPW)*/
rLCDCON4 = (13<<8)|(LCD_HSYNC_LEN<<0);
/*bit[11](5:6:5 Format);bit[9](VLINE/HSYNC polarity inverted);bit[8](VFRAME/VSYNC inverted)
bit[3](Enalbe PWERN signal),bit[1](half-word swap control bit)*/
rLCDCON5 = (1<<0)|(1<<3)|(1<<8)|(1<<9)|(1<<11);
}
/*********************************************************
LCD帧缓存寄存器初始化
**********************************************************/
void FraBuf_init(void)
{
/* LCDBANK: 视频帧缓冲区内存地址30-22位。 LCDBASEU: 视频帧缓冲区的开始地址21-1位
LCDBASEL: 视频帧缓冲区的结束地址21-1位*/
/*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_LONG * 2)>>1);
/*PAGEWIDTH:虚拟屏幕一行的字节数,如果不使用虚拟屏幕,设置为实际屏幕的行字节数
OFFSIZE:虚拟屏幕左侧偏移的字节数,如果不使用虚拟屏幕,设置为*/
/*bit[21:11]:OFFSIZE; bit[10:0]:PAGEWIDTH*/
rLCDSADDR3 = LCD_WIDTH;
}
/*********************************************************
对LCD其他的一些屏蔽和处理
**********************************************************/
void MASK(void)
{
/*屏蔽中断*/
rLCDINTMSK |= 3;
rTCONSEL &= (~7);
/*disable调色板*/
rTPAL = 0x0;
/*禁止LPC3600/LCC3600模式*/
rTCONSEL &= ~((1<<4) | 1);
}
/*********************************************************
LCD的开启与关闭函数
**********************************************************/
static void Lcd_EnvidOnOff(int onoff)
{
if(onoff==1)
rLCDCON1|=1; // ENVID=ON
else
rLCDCON1 =rLCDCON1 & 0x3fffe; // ENVID Off
}
/*********************************************************
LCD显示函数
**********************************************************/
void TFT_LCD_Show(void)
{
/*红(255:0:0);绿(0:255:0);蓝(0:0:255);黑(0:0:0);白(255,255,255)*/
/*在屏幕上显示三基色*/
Lcd_ClearScr( (0x00<<11) | (0x00<<5) | (0x00) ) ; //clear screen black
delay(10000);
Lcd_ClearScr((0x1f<<11) | (0x00<<5) | (0x00)); //red
delay(10000);
Lcd_ClearScr((0x00<<11) | (0x3f<<5) | (0x00)); //green
delay(10000);
Lcd_ClearScr((0x00<<11) | (0x00<<5) | (0x1f)); //blue
delay(10000);
Lcd_ClearScr( (0x1f<<11) | (0x3f<<5) | (0x1f) ) ; //clear screen white
delay(10000);
/*显示一副图片在屏幕上*/
Pait_Bmp(0, 0, 240, 320, sunflower_240x320);
}
/*********************************************************
LCD全屏填充颜色函数
**********************************************************/
static void Lcd_ClearScr(U16 c)
{
unsigned int x,y;
for(y=0;y<SCR_YSIZE;y++)
for(x=0;x<SCR_XSIZE;x++)
{
LCD_BUFFER[y][x]=c; //把得到的值送到缓冲器中即可显示颜色
}
}
/*在屏幕上显示图片*/
static void Pait_Bmp(int x0,int y0,int h,int l,const unsigned char *bmp)
{
int x,y;
U32 c;
int p = 0;
for( y = 0 ; y < l ; y++ )
{
for( x = 0 ; x < h ; x++ )
{
c = bmp[p+1] | (bmp[p]<<8) ;
if ( ( (x0+x) < SCR_XSIZE) && ( (y0+y) < SCR_YSIZE) )
LCD_BUFFER[y0+y][x0+x] = c ;
p=p+2;
}
}
}
/*************************************************
时钟频率设置
**************************************************/
void Set_Clk(void)
{
int i;
U8 key;
U32 mpll_val = 0 ;
i = 2 ; //don't use 100M!
//boot_params.cpu_clk.val = 3;
switch ( i ) {
case 0: //200
key = 12;
mpll_val = (92<<12)|(4<<4)|(1);
break;
case 1: //300
key = 13;
mpll_val = (67<<12)|(1<<4)|(1);
break;
case 2: //400
key = 14;
mpll_val = (92<<12)|(1<<4)|(1);
break;
case 3: //440!!!
key = 14;
mpll_val = (102<<12)|(1<<4)|(1);
break;
default:
key = 14;
mpll_val = (92<<12)|(1<<4)|(1);
break;
}
//init FCLK=400M, so change MPLL first
ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3); //set the register--rMPLLCON
ChangeClockDivider(key, 12); //the result of rCLKDIVN [0:1:0:1] 3-0 bit
cal_cpu_bus_clk(); //HCLK=100M PCLK=50M
}
/*************************************************
**************************************************/
static void cal_cpu_bus_clk(void)
{
static U32 cpu_freq;
static U32 UPLL;
U32 val;
U8 m, p, s;
val = rMPLLCON;
m = (val>>12)&0xff;
p = (val>>4)&0x3f;
s = val&3;
//(m+8)*FIN*2 不要超出32位数!
FCLK = ((m+8)*(FIN/100)*2)/((p+2)*(1<<s))*100; //FCLK=400M FIN=12000000
val = rCLKDIVN;
m = (val>>1)&3;
p = val&1;
val = rCAMDIVN;
s = val>>8;
switch (m) {
case 0:
HCLK = FCLK;
break;
case 1:
HCLK = FCLK>>1;
break;
case 2:
if(s&2)
HCLK = FCLK>>3;
else
HCLK = FCLK>>2;
break;
case 3:
if(s&1)
HCLK = FCLK/6;
else
HCLK = FCLK/3;
break;
}
if(p)
PCLK = HCLK>>1;
else
PCLK = HCLK;
if(s&0x10)
cpu_freq = HCLK;
else
cpu_freq = FCLK;
val = rUPLLCON;
m = (val>>12)&0xff;
p = (val>>4)&0x3f;
s = val&3;
UPLL = ((m+8)*FIN)/((p+2)*(1<<s));
UCLK = (rCLKDIVN&8)?(UPLL>>1):UPLL;
}