所用的LCD爲TopPoly-TD035STED4(TFT)型號,240*320的
其VCLK爲6.39MHz。 根據s3c2440手冊s3c2440處理LCD的時鐘源是HCLK,通過寄存器LCDCON1中的CLKVAL可以調整VCLK頻率大小,它的公式爲:VCLK=HCLK÷[(CLKVAL+1)×2],程序的內部分頻爲FCLK=400MHz、HCLK=100MHz、PCLK=50MHz(MPLLCON=(92<<12)|(1<<4)|1;),因此得到CLKVAL取整爲6。
注:(LCD一般需要三個時序信號:VSYNC、HSYNC和VCLK。VSYNC是垂直同步信號,在每進行一個幀(即一個屏)的掃描之前,該信號就有效一次,由該信號可以確定LCD的場頻,即每秒屏幕刷新的次數(單位Hz)。HSYNC是水平同步信號,在每進行一行的掃描之前,該信號就有效一次,由該信號可以確定LCD的行頻,即每秒屏幕從左到右掃描一行的次數(單位Hz)。VCLK是像素時鐘信號。
其中VSYNC是幀同步信號,VSYNC每發出1個脈衝,都意味着新的1屏視頻資料開始發送。而HSYNC爲行同步 信號,每個HSYNC脈衝都表明新的1行視頻資料開始發送。而VDEN則用來標明視頻資料的有效,VCLK是用來鎖存視頻資料的像數時鐘。網上搜到的資料來解釋這幾個時序信號。
可以查看s3c2440手冊‘Figure 15-6. TFT LCD Timing Example’圖)
通過上圖可以得到:
#define LCD_HEIGHT 320 //屏幕的高
//垂直同步信號的脈寬、後肩和前肩-----這些值是根據TopPoly-TD035STED4.pdf文件中的13頁的表
#define VSPW 1 //(3-1)
#define VBPD 1 //(15-1)
#define VFPD 1 //(12-1)
//水平同步信號的脈寬、後肩和前肩-----這些值是根據TopPoly-TD035STED4.pdf文件中的13頁的表
#define HSPW (10-1)
#define HBPD (20-1)
#define HFPD (10-1)
//顯示尺寸
#define LINEVAL (LCD_HEIGHT-1)
#define HOZVAL (LCD_WIDTH-1)
注:(對於一個已知尺寸的LCD屏,只要確定了VCLK值,行頻和場頻就應該知道了。但這樣還不行的,因爲在每一幀時鐘信號中,還會有一些與屏顯示無關的時鐘出現,這就給確定行頻和場頻帶來了一定的複雜性。如在HSYNC信號先後會有水平同步信號前肩(HFPD)和水平同步信號後肩(HBPD)出現,在VSYNC信號先後會有垂直同步信號前肩(VFPD)和垂直同步信號後肩(VBPD)出現,在這些信號時序內,不會有有效像素信號出現,另外HSYNC和VSYNC信號有效時,其電平要保持一定的時間,它們分別叫做水平同步信號脈寬HSPW和垂直同步信號脈寬VSPW,這段時間也不能有像素信號。因此計算行頻和場頻時,一定要包括這些信號。HBPD、HFPD和HSPW的單位是一個VCLK的時間,而VSPW、VFPD和VBPD的單位是掃描一行所用的時間。也是網上搜的。)
這些信號(VSPW、VFPD、VBPD、LINEVAL、HBPD、HFPD、HSPW和HOZVAL)是通過寄存器LCDCON2、LCDCON3和LCDCON4來配置的,具體查看s3c2440的手冊。
LCDCON1寄存器:
CLKVAL :決定VCLK的分頻 比(上面已經提到過)。LCD控制器輸出的VCLK是直接由系統總線(AHB)
出的VCLK在5~10MHz之間。
MMODE :VM信號的觸發模式(僅對STN屏有效,對TFT屏無意義。)PNRMODE :選擇當前的顯示模式,
對於TFT屏而言,應選擇[11],即TFT LCD panel。
BPPMODE :選擇色彩模式,對於真彩顯示而言,選擇16bpp(64K色)即可滿足要求。
LCDCON5寄存器:
VSTATUS :當前VSYNC信號掃描狀態,指明當前VSYNC同步信號處於何種掃描階段。
對於16bpp的 64K色顯示模式,該設置位無意義。
常用,它的含義是表示64K種色彩的16bit RGB資料中,紅色(R)佔了5bit,綠色(G)佔了
6bit,蘭色(B)佔了5bit。
道,CPU的LCD控制器輸出的時序默認是正脈衝,而LCD需要VSYNC(VFRAME)、
VLINE(HSYNC)均爲負脈衝,因此 INVLINE 和 INVFRAME 必須設爲“1 ”,即選擇反相輸
出。 INVVDEN , INVPWREN , INVLEND 的功能同前面的類似。
來做爲LCD屏電源的開關信號。
INVVDEN、INVPWREN、INVLEND:是否翻轉這些信號,一般爲正常,不需要翻轉。
BSWP 、HWSWP : 爲字節(Byte)或半字(Half-Word)交換使能。由於不同的GUI對
FrameBuffer(顯示緩衝區)的管理不同,必要時需要通過調整 BSWP 和 HWSWP
來適應GUI。
因此:
#define CLKVAL_TFT 4 //設置時鐘信號
#define MVAL_USED 0 //
#define PNRMODE_TFT 3 //TFT型LCD
#define BPPMODE_TFT 13 //24位TFT型LCD
//for LCDCON5
#define BPP24BL 0 //32位數據表示24位顏色值時,低位數據有效,高8位無效
#define INVVCLK 0 //像素值在VCLK下降沿有效
#define INVVLINE 1 //翻轉HSYNC信號
#define INVVFRAME 1 //翻轉VSYNC信號
#define INVVD 0 //正常VD信號極性
#define INVVDEN 0 //正常VDEN信號極性
#define PWREN 1 //使能PWREN信號
#define BSWP 0 //顏色數據字節不交換
#define HWSWP 0 //顏色數據半字不交換
rLCDCON1=(CLKVAL_TFT<<8)|(MVAL_USED<<7)|(PNRMODE_TFT<<5)|(BPPMODE_TFT<<1)|0;
rLCDCON2=(VBPD<<24)|(LINEVAL<<14)|(VFPD<<6)|(VSPW);
rLCDCON3=(HBPD<<19)|(HOZVAL<<8)|(HFPD);
rLCDCON4=(HSPW);//
rLCDCON5 = (BPP24BL<<12) | (INVVCLK<<10) | (INVVLINE<<9) | (INVVFRAME<<8) | (0<<7) | (INVVDEN<<6) | (PWREN<<3) |(BSWP<<1) | (HWSWP);
LCDSADDR1和LCDSADDR2:
LCDBASEL=LCDBASEU+(PAGEWITH+OFFSIZE)×(LINEVAL+1)
LCDSADDR3寄存器:
OFFSIZE:用於虛擬屏幕的偏移長度,如果我們不使用虛擬屏幕,就把它置爲0 。
PAGEWIDTH:定義了視口的寬,單位是半字,如在上面的例子中,PAGEWIDTH應該爲320×32÷16。
//定義顯示緩存區
volatile U32 LCD_BUFFER[LCD_HEIGHT][LCD_WIDTH];
rLCDSADDR1=(((U32)LCD_BUFFER>>22)<<21)|M5D((U32)LCD_BUFFER>>1);
rLCDSADDR2=M5D((M5D((U32)LCD_BUFFER>>1)+((LCD_WIDTH*32/16+0)*320)));
rLCDSADDR3=(LCD_WIDTH*32/16)&0x7ff;//參考s3c2440的手冊
簡單程序實現:
#include "def.h"
#include "option.h"
#include "2440addr.h"
#include "2440lib.h"
#include "2440slib.h"
//================================
#define M5D(n) ((n) & 0x1fffff) //用於設置顯示緩存區時,取低21位地址
#define LCD_WIDTH 240 //屏幕的寬
#define LCD_HEIGHT 320 //屏幕的高
//垂直同步信號的脈寬、後肩和前肩-----這些值是根據TopPoly-TD035STED4.pdf文件中的13頁的表
#define VSPW 1 //(3-1)
#define VBPD 1 //(15-1)
#define VFPD 1 //(12-1)
//水平同步信號的脈寬、後肩和前肩-----這些值是根據TopPoly-TD035STED4.pdf文件中的13頁的表
#define HSPW (10-1)
#define HBPD (20-1)
#define HFPD (10-1)
//顯示尺寸
#define LINEVAL (LCD_HEIGHT-1)
#define HOZVAL (LCD_WIDTH-1)
//for LCDCON1
#define CLKVAL_TFT 4 //設置時鐘信號
#define MVAL_USED 0 //
#define PNRMODE_TFT 3 //TFT型LCD
#define BPPMODE_TFT 13 //24位TFT型LCD
//for LCDCON5
#define BPP24BL 0 //32位數據表示24位顏色值時,低位數據有效,高8位無效
#define INVVCLK 0 //像素值在VCLK下降沿有效
#define INVVLINE 1 //翻轉HSYNC信號
#define INVVFRAME 1 //翻轉VSYNC信號
#define INVVD 0 //正常VD信號極性
#define INVVDEN 0 //正常VDEN信號極性
#define PWREN 1 //使能PWREN信號
#define BSWP 0 //顏色數據字節不交換
#define HWSWP 0 //顏色數據半字不交換
//定義顯示緩存區
volatile U32 LCD_BUFFER[LCD_HEIGHT][LCD_WIDTH];
//**********************************************************
//延時程序
void delay(int a)
{
int k;
for(k=0;k<a;k++) ;
}
//繪製屏幕背景顏色,顏色爲c
void Brush_Background( U32 c)
{
int x,y ;
for( y = 0 ; y < LCD_HEIGHT ; y++ )
{
for( x = 0 ; x < LCD_WIDTH ; x++ )
{
LCD_BUFFER[y][x] = c ;
}
}
}
void init_port_lcd()
{
rGPCCON = 0xaaaaaaaa;
rGPCUP = 0xffff; // The pull up function is disabled GPC[15:0]
//*** PORT D GROUP
//Ports : GPD15 GPD14 GPD13 GPD12 GPD11 GPD10 GPD9 GPD8 GPD7 GPD6 GPD5 GPD4 GPD3 GPD2 GPD1 GPD0
//Signal : VD23 VD22 VD21 VD20 VD19 VD18 VD17 VD16 VD15 VD14 VD13 VD12 VD11 VD10 VD9 VD8
//Binary : 10 10 , 10 10 , 10 10 , 10 10 , 10 10 , 10 10 , 10 10 ,10 10
rGPDCON = 0xaaaaaaaa;
rGPDUP = 0xffff;
rLCDCON1=(CLKVAL_TFT<<8)|(MVAL_USED<<7)|(PNRMODE_TFT<<5)|(BPPMODE_TFT<<1)|0;
rLCDCON2=(VBPD<<24)|(LINEVAL<<14)|(VFPD<<6)|(VSPW);
rLCDCON3=(HBPD<<19)|(HOZVAL<<8)|(HFPD);
rLCDCON4=(HSPW);
//rLCDCON4 = (5<< 0);
rLCDCON5 = (BPP24BL<<12) | (INVVCLK<<10) | (INVVLINE<<9) | (INVVFRAME<<8) | (0<<7) | (INVVDEN<<6) | (PWREN<<3) |(BSWP<<1) | (HWSWP);
rLCDSADDR1=(((U32)LCD_BUFFER>>22)<<21)|M5D((U32)LCD_BUFFER>>1);
rLCDSADDR2=M5D( (M5D((U32)LCD_BUFFER>>1)+((LCD_WIDTH*32/16+0)*320)) );//LCD_WIDTH*LCD_HEIGHT*4
rLCDSADDR3=(LCD_WIDTH*32/16)&0x7ff;//參考s3c2440的手冊
rLCDINTMSK|=(3); // 屏蔽LCD中斷
//rTCONSEL = 0; //無效LPC3480
rTCONSEL &= (~7);
rTPAL = 0x0;
rTCONSEL &= ~((1<<4) | 1);
rGPGUP=rGPGUP&(~(1<<4))|(1<<4); //GPG4上拉電阻無效
rGPGCON=rGPGCON&(~(3<<8))|(3<<8); //設置GPG4爲LCD_PWREN
rGPGDAT = rGPGDAT | (1<<4) ; //GPG4置1
rLCDCON5=rLCDCON5&(~(1<<3))|(1<<3); //有效PWREN信號
rLCDCON5=rLCDCON5&(~(1<<5))|(0<<5); //PWREN信號極性不翻轉
rLCDCON1|=1; //LCD開啓
}
int Main(int argc, char **argv)
{
int i;
U8 key;
U32 mpll_val=0;
int data;
mpll_val = (92<<12)|(1<<4)|(1);
//init FCLK=400M, so change MPLL first
ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);
ChangeClockDivider(key, 12);
//ChangeClockDivider(1,1); // 1:2:4 FCLK:HCLK:PCLK
// rCLKDIVN=0x4; // 1:4:4
//ChangeMPllValue(82,2,1); //FCLK=135.0Mhz
//ChangeMPllValue(82,1,1); //FCLK=180.0Mhz
//ChangeMPllValue(161,3,1); //FCLK=202.8Mhz
//ChangeMPllValue(117,1,1); //FCLK=250.0Mhz
//ChangeMPllValue(122,1,1); //FCLK=260.0Mhz
//ChangeMPllValue(125,1,1); //FCLK=266.0Mhz
//ChangeMPllValue(127,1,1); //FCLK=270.0Mhz
//MMU_EnableICache();
//MMU_EnableDCache();
MMU_DisableICache();
MMU_DisableDCache();
init_port_lcd();
while(1)
{
//黑色背景
Brush_Background(0x0000);
delay(5000000);
//白色背景
Brush_Background(0xffffff);
delay(5000000);
//藍色背景
Brush_Background(0x00ff);
delay(5000000);
//綠色背景
Brush_Background(0xff00);
delay(5000000);
//黃色背景
Brush_Background(0xffff00);
delay(5000000);
}
return 0;
}