驱动程序流程----
1----LCD初始化
---端口初始化
---显示模式初始化
---帧缓冲初始化
2----将图像写入帧缓冲
端口初始化----------
GPC5
GPC6
GPC7
未用-----
GPC0-------10
lineend 信号
static void Lcd_Port_Init( void )
{
rGPCUP=0xffffffff; // Disable Pull-up register
rGPCCON=0xaaaa02a8; //1010 1010 1010 1010 0000 0010 1010 1000Initialize VD[7:0],VM,VFRAME,VLINE,VCLK
rGPDUP=0xffffffff; // Disable Pull-up register
rGPDCON=0xaaaaaaaa; //Initialize VD[15:8]
}
显示模式初始化----------------------------------------------
CLKVAL---
确定VCLK频率的参数,单位为HZ。
MMODE--
确定VM的改变速度。在此选择MMODE=0,为每帧变化模式
VM----通过VM信号改变控制像素点得显示或熄灭。
PNRMODE---
确定扫描方式。选择PNRMODE=0x3,为TFT LCD面板扫描模式。
BPPMODE--
确定BPP(每像素位数)模式。在此选择BPPMODE=0xc,为TFT16位模式。
ENVID----
数据输出和逻辑信号使能控制位。选择ENVID=1,为允许数据输出和逻辑控制
LCD_PIXCLOCK=4;
/*bit[17:8](4:CLKVAL);bit[6:5](11:TFT LCD panel);bit[4:1](1100:16 bpp for TFT)*/
rLCDCON1 = (LCD_PIXCLOCK << 8) | (3 << 5) | (12 << 1);
0100 0000 0000
0000 0110 0000
0000 0001 1000
0100 0111 1000
static void Lcd_EnvidOnOff(int onoff)
{
if(onoff==1)
rLCDCON1|=1; // ENVID=ON
else
rLCDCON1 =rLCDCON1 & 0x3fffe; // ENVID Off
}
#define LCD_UPPER_MARGIN 1
#define LCD_LOWER_MARGIN 5
#define LCD_HEIGHT 320
#define LCD_HSYNC_LEN 5
/*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_HEIGHT - 1) << 14) | (LCD_LOWER_MARGIN << 6) | (LCD_VSYNC_LEN << 0);
VBPD----表示一帧图像开始时,帧同步信号以后的无效的行数,对应驱动中的upper_margin
VFBD-----表示在一帧图像结束后,帧同步信号以前的无效的行数,对应驱动中的lower_margin
VSPW-----表示垂直同步脉冲的宽带,用行数计算,对应驱动中的vsync_len
LINEVAL----确定显示的垂直方向的尺寸LINEVAL=YSIZE-1=479
若是480行,LINEVAL=479;
HBPD------表示从水平同步信号开始到一行有效数据开始之间的VCLK的个数,对应驱动中的left_margin
HFPD------表示一行的有效数据结束到下一个水平同步信号开始之间的VCLK个数,对应
HOZVAL----确定显示的水平方向尺寸公式HOZVAL=XSIZE-1
就是决定显示器有多少列。
/*bit[25:19](36:HBPD);bit[18:8](240-1:列数);bit[7:0](19:HFPD)*/
rLCDCON3 = (LCD_RIGHT_MARGIN << 19) | ((LCD_WIDTH - 1) << 8) | (LCD_LEFT_MARGIN << 0);
HSPW-----表示水平同步信号的宽带,用VCLK计算,对应驱动中的hsync_len
/*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<<11) | (1 << 9) | (1 << 8) | (1 << 3) | (1 << 0);
FRM565---------三基色模式选择
帧缓冲初始化----告诉lcd控制器,帧缓冲--显示缓存的位置。
记录了帧缓冲的起始地址。
/*帧缓冲地址初始化*/
/*
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_HEIGHT * 2) >> 1);
/*PAGEWIDTH:虚拟屏幕一行的字节数,如果不使用虚拟屏幕,设置为实际屏幕的行字节数
OFFSIZE:虚拟屏幕左侧偏移的字节数,如果不使用虚拟屏幕,设置为0
*/
/*bit[21:11]:OFFSIZE; bit[10:0]:PAGEWIDTH*/
rLCDSADDR3 = LCD_WIDTH;
#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 LCD_N35 //NEC 256K色240*320/3.5英寸TFT真彩液晶屏,每一条水平线上包含240个像素点,共有320条这样的线
#if defined(LCD_N35)
#define LCD_WIDTH 240
#define LCD_HEIGHT 320
#define LCD_PIXCLOCK 4
#define LCD_RIGHT_MARGIN 39
#define LCD_LEFT_MARGIN 16
#define LCD_HSYNC_LEN 5
#define LCD_UPPER_MARGIN 1
#define LCD_LOWER_MARGIN 5
#define LCD_VSYNC_LEN 1
#endif
void TFT_LCD_Test(void);
#define LCD_XSIZE LCD_WIDTH
#define LCD_YSIZE LCD_HEIGHT
#define SCR_XSIZE LCD_WIDTH
#define SCR_YSIZE LCD_HEIGHT
volatile static unsigned short LCD_BUFFER[SCR_YSIZE][SCR_XSIZE]; //定义320行,240列的数组,用于存放显示数据
extern unsigned char sunflower_240x320[];
#define M5D(n) ((n)&0x1fffff)
#define LCD_ADDR ((U32)LCD_BUFFER)
#define ADC_FREQ 2500000
volatile U32 preScaler;
static void cal_cpu_bus_clk(void);
void Set_Clk(void);
/*演示函数*/
void delay(int times)
{
int i,j;
for(i=0;i<times;i++)
for(j=0;j<400;j++);
}
/*在屏幕上画图*/
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 ;
}
}
}
/*填充全屏为某一颜色*/
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 ;
}
}
}
/*LCD开关*/
static void Lcd_EnvidOnOff(int onoff)
{
if(onoff==1)
rLCDCON1|=1; // ENVID=ON
else
rLCDCON1 =rLCDCON1 & 0x3fffe; // ENVID Off
}
/*端口初始化*/
static void Lcd_Port_Init( void )
{
rGPCUP=0xffffffff; // Disable Pull-up register
rGPCCON=0xaaaa02a8; //Initialize VD[7:0],VM,VFRAME,VLINE,VCLK
rGPDUP=0xffffffff; // Disable Pull-up register
rGPDCON=0xaaaaaaaa; //Initialize VD[15:8]
}
/*LCD初始化*/
static void LCD_Init(void)
{
Lcd_Port_Init();
/*显示模式初始化*/
/*bit[17:8](4:CLKVAL);bit[6:5](11:TFT LCD panel);bit[4:1](1100:16 bpp for TFT)*/
rLCDCON1 = (LCD_PIXCLOCK << 8) | (3 << 5) | (12 << 1);
/*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_HEIGHT - 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_WIDTH - 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<<11) | (1 << 9) | (1 << 8) | (1 << 3) | (1 << 0);
/*帧缓冲地址初始化*/
/*
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_HEIGHT * 2) >> 1);
/*PAGEWIDTH:虚拟屏幕一行的字节数,如果不使用虚拟屏幕,设置为实际屏幕的行字节数
OFFSIZE:虚拟屏幕左侧偏移的字节数,如果不使用虚拟屏幕,设置为0
*/
/*bit[21:11]:OFFSIZE; bit[10:0]:PAGEWIDTH*/
rLCDSADDR3 = LCD_WIDTH;
/*屏蔽中断*/
rLCDINTMSK |= 3;
rTCONSEL &= (~7);
/*disable调色板*/
rTPAL = 0x0;
/*禁止LPC3600/LCC3600模式*/
rTCONSEL &= ~((1<<4) | 1);
/*打开LCD*/
Lcd_EnvidOnOff(1);
}
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);
}
/*************************************************
Function name: Set_Clk()
Parameter : void
Description : 设置CPU的时钟频率
Return : void
Argument : void
Autor & date : Daniel
**************************************************/
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
}
/*************************************************
Function name: cal_cpu_bus_clk
Parameter : void
Description : 设置PCLK\HCLK\FCLK的频率
Return : void
Argument : void
Autor & date : Daniel
**************************************************/
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;
Uart_Printf("\nFCLK:%dMHz,HCLK:%dMHz,PCLK=%dMHZ\n",FCLK/1000/1000,HCLK/1000/1000,PCLK/1000/1000);
}
/*主函数*/
int Main(void)
{
Set_Clk();
LCD_Init();
TFT_LCD_Show();
return 0;
}