新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > S3C2440的LCD編程

S3C2440的LCD編程

作者: 時間:2016-11-27 來源:網(wǎng)絡 收藏

4. 幀緩沖(FrameBuffer):
  幀緩沖是Linux為顯示設備提供的一個接口,它把一些顯示設備描述成一個緩沖區(qū),允許應用程序通過 FrameBuffer定義好的接口訪問這些圖形設備,從而不用去關心具體的硬件細節(jié)。對于幀緩沖設備而言,只要在顯示緩沖區(qū)與顯示點對應的區(qū)域寫入顏色 值,對應的顏色就會自動的在屏幕上顯示。下面來看一下在不同色位模式下緩沖區(qū)與顯示點的對應關系:

本文引用地址:http://2s4d.com/article/201611/322380.htm

volatile static unsigned short LCD_BUFFER[240][320];
void Pixel(U32 x,U32 y, U16 c )
{
if ( (x < SCR_XSIZE_TFT_320240) && (y < SCR_YSIZE_TFT_320240) )
LCD_BUFFER[y][x] = c;
}

很容易發(fā)現(xiàn)TFT LCD上顯示單個像素的函數(shù)實際上很簡潔,看來似乎只需要LCD_BUFFER[(y)][(x)] = c這一句話.下面就來分析下,是如何通過這一句話來實現(xiàn)在LCD上顯示單個像素的,先分析下Lcd_Init()即LCD初始化函數(shù):

#define rGPCCON(*(volatile unsigned *)0x56000020)
#define rGPCUP(*(volatile unsigned *)0x56000028)
#define rGPDCON(*(volatile unsigned *)0x56000030)
#define rGPDUP(*(volatile unsigned *)0x56000038)

#define rLCDCON1(*(volatile unsigned *)0x4d000000)
#define rLCDCON2(*(volatile unsigned *)0x4d000004)
#define rLCDCON3(*(volatile unsigned *)0x4d000008)
#define rLCDCON4(*(volatile unsigned *)0x4d00000c)
#define rLCDCON5(*(volatile unsigned *)0x4d000010)
#define rLCDSADDR1(*(volatile unsigned *)0x4d000014)
#define rLCDSADDR2(*(volatile unsigned *)0x4d000018)
#define rLCDSADDR3(*(volatile unsigned *)0x4d00001c)
#define rLCDINTMSK(*(volatile unsigned *)0x4d00005c)
#define rTPAL(*(volatile unsigned *)0x4d000050)

void Lcd_Init(void)
{
rGPCUP=0xffffffff;// Disable Pull-up register
rGPCCON=0xaaaa56a9; //Initialize VD[7:0],LCDVF[2:0],VM,VFRAME,VLINE,VCLK,LEND

rGPDUP=0xffffffff;// Disable Pull-up register
rGPDCON=0xaaaaaaaa; //Initialize VD[15:8]

//LCDCON1: TFT LCD panel,MMODE[7]=0,16bpp TFT,ENVID=off
rLCDCON1=(CLKVAL_TFT_320240<<8)|(MVAL_USED<<7)|(3<<5)|(12<<1)|0;
rLCDCON2=(VBPD_320240<<24)|(LINEVAL_TFT_320240<<14)|(VFPD_320240<<6)|(VSPW_320240);
rLCDCON3=(HBPD_320240<<19)|(HOZVAL_TFT_320240<<8)|(HFPD_320240);
rLCDCON4=(MVAL<<8)|(HSPW_320240);
rLCDCON5=(1<<11)|(1<<9)|(1<<8)|(1<<3)|(BSWP<<1)|(HWSWP);
//rLCDCON5=(1<<11)|(0<<9)|(0<<8)|(0<<6)|(BSWP<<1)|(HWSWP);
//FRM5:6:5,HSYNC and VSYNC are inverted


//LCDBANK[29:21] = (U32)LCD_BUFFER >> 22 : These bits indicate A[30:22] of the bank location for the video buffer in the system memory. LCDBANK value cannot be changed even when moving the view port. LCD frame buffer should be within aligned 4MB region, which ensures that LCDBANK value will not be changed when moving the view port. So, care should be taken to use the malloc() function.
//系統(tǒng)內存地址A[30:22]處的Bank位置為圖像緩沖。LCDBANK的值在視圖移動的值在視圖移動時不能改變,LCD幀緩沖應該在4MB區(qū)域對齊,保證LCDBANK的值在移動視圖時不會改變。
//LCDBASEU[20:0] = ((U32)LCD_BUFFER >> 1)&0x1fffff : For dual-scan LCD : These bits indicate A[21:1] of the start address of the upper address counter, which is for the upper frame memory of dual scan LCD or the frame memory of single scan LCD.
//For single-scan LCD : These bits indicate A[21:1] of the start address of the LCD frame buffer.
//雙掃描:表明高地址計數(shù)器的起始地址A[21:1],用于LCD雙掃描的上部幀內存或者單掃描的幀內存
//單掃描:表明LCD幀緩沖的起始地址A[21:1]
rLCDSADDR1=(((U32)LCD_BUFFER>>22)<<21)|M5D((U32)LCD_BUFFER>>1);

//LCDSADDR2 0x4d000018幀緩沖起始寄存器2:
//LCDBASEL[20:0] = ((LCD_ADDR + LCD_WIDTH * LCD_HEIGHT * 2) >> 1)& 0x1fffff = (LCD_ADDR >> 1 + LCD_WIDTH * LCD_HEIGHT)& 0x1fffff
//For dual-scan LCD: These bits indicate A[21:1] of the start address of the lower address counter, which is used for the lower frame memory of dual scan LCD.
//For single scan LCD: These bits indicate A[21:1] of the end address of the LCD frame buffer.
//LCDBASEL = ((the frame end address) >>1) + 1 = LCDBASEU + (PAGEWIDTH+OFFSIZE) x (LINEVAL+1)
//雙掃描:表明低地址計數(shù)器的起始地址A[21:1],用于LCD雙掃描的下部幀內存或者單掃描的幀內存
//單掃描:表明LCD幀緩沖的結束地址A[21:1]
rLCDSADDR2=M5D( ((U32)LCD_BUFFER+(SCR_XSIZE_TFT_320240*LCD_YSIZE_TFT_320240*2))>>1 );

//LCDSADDR3 0x4d00001c幀緩沖起始寄存器3:
//OFFSIZE = 0;PAGEWIDTH = 320 虛擬屏頁寬(半字數(shù)量)定義了幀中的視圖域寬度
rLCDSADDR3=(((SCR_XSIZE_TFT_320240-LCD_XSIZE_TFT_320240)/1)<<11)|(LCD_XSIZE_TFT_320240/1);

rLCDINTMSK|=(3);// MASK LCD Sub Interrupt
//rTCONSEL|=((1<<4)|1); // Disable LCC3600, LPC3600
rTPAL=0;// Disable Temp Palette
}

程序分析至此,大概已經(jīng)清楚是如何通過LCD_BUFFER[(y)][(x)] = c來實現(xiàn)在LCD上顯示單個像素了。就是在設置好各個LCD寄存器之后,通過將LCD_BUFFER地址與LCDBANK以及LCDBASEU、 LCDBASEL對應之后,通過改變LCD_BUFFER里不同單元存儲的值(即像素的顏色),即可在LCD相應位置上做出顯示。
  那么在應用不同LCD的時候,只需對LCDCONx以及LCDSADDRx做出相應的配置,再創(chuàng)建一個數(shù)組,做出上述的地址映射即可。

  關于VCLK計算,由于配置的是TFT,可用到公式VCLK = HCLK / [(CLKVAL+1) * 2] ( CLKVAL>=0 ),設置的Fclk為400MHz,Hclk為100MHz(Fclk:Hclk=1:4),CLKVAL = 4,因此VLCK = 10MHz。

筆記:
  首先說一下我們平時所說的多少位的LCD,有24位的,有16位的指的是LCD數(shù)據(jù)的位數(shù),LCD的數(shù)據(jù)實際上是LCD要顯示的顏色,24位的是紅綠 藍各占8位,16位則是紅綠藍按照565分配的,其實24的也可以只接16位,每個顏色地位接地就可以,所以要給LCD的緩沖區(qū)一個數(shù)據(jù)才能在LCD上顯 示出來。那究竟是怎么顯示的呢,那就得先說一下像素了,LCD的像素實際上就LCD屏幕有多少個點,LCD顯示的東西都是一個一個點拼湊出來的,比如我用 的是320*240的LCD,就是說LCD每一行有320個點,而每一列有240個點,所以總共有320*240個點,我們讓適當?shù)狞c顯示適當?shù)念伾瓦_ 到了我們的目的。


  其實剛開始困擾我們的是LCD的初始化的問題,要設置的東西比較多,其實我們是記不住這些東西的,呵呵,作為入門我們可以參考別人的初始化程序,把里面的參數(shù)改成我們自己的LCD的參數(shù)就OK了。


  那么我們到底是怎么把我們要顯示的數(shù)據(jù)送給LCD控制起的呢?是這樣的,我們可以定義一個二維數(shù)組,把我們要顯示的數(shù)據(jù)存到里面,然后把這個數(shù)組的地 址賦給LCD的相應的寄存器,這個寄存器是LCDSADDRn,具體的設置大家可以參考數(shù)據(jù)手冊,我們可以把二維數(shù)組的坐標和LCD的坐標對應起來,那么 我們就可以隨意的讓哪一個像素點顯示什么顏色就顯示什么顏色了。這就把數(shù)據(jù)送出的過程,也就是顯示一個像素點的過程。


  到現(xiàn)在我們已經(jīng)知道如何顯示一個像素了,那接下來就是LCD顯示最基本的東西了----字符和圖片。漢字和圖片的顯示都是基于像素點的顯示的,我們把 要顯示的字符和圖片轉化成相應的數(shù)據(jù),然后傳遞給LCD即可。我們可以專門的寫一個顯示字符的函數(shù)和一個顯示圖片的函數(shù)。顯示字符的數(shù)據(jù)可以用取模軟件生 成,因為生成的字符數(shù)據(jù)是表示的每一個點要不要亮,亮的地方用1表示,不亮的地方用0表示,所以如果用LCD顯示,我們還要告訴LCD顯示什么顏色,這才 是LCD需要的數(shù)據(jù),比如說16*16的數(shù)據(jù),有16行16列,我們將一行的數(shù)據(jù),也就是16位數(shù)據(jù)的每一位都取出來,為1的地方,我們就給LCD一個 16位的數(shù)據(jù),為0的地方就不給數(shù)據(jù),這樣就能顯示了,取模生成的數(shù)據(jù)都是按行來的。圖片的顯示直接就將16位的數(shù)據(jù)傳遞給LCD,這個圖片數(shù)據(jù)的產(chǎn)生, 我們可以用軟件LCD彩色圖片轉換工具(BMP_to_H)生成C語言文件,我們只需對文件進行簡單的修改就能加入到我們的程序中,修改方法在軟件的說明 中都有。


編程要點:
1、打開LCD背光
將LCD背光對應的GPIO設置為禁止上拉(GPxUP相應位寫入1),選擇output類型(GPxCON相應位寫入01),輸出為高電平(GPxDAT相應位寫入1)。

2、打開LCD電源
可以將GPG4選擇為LCD_PWREN(GPGCON:9-8寫入11),這時候LCD電源的打開/關閉可以通過LCDCON5:3來控制。也可以自定 義其他GPIO用作LCD電源開關,只需將此GPIO設置為禁止上拉(GPxUP相應位寫入1),選擇output類型(GPxCON相應位寫入01), 輸出為高電平(GPxDAT相應位寫入1)打開LCD電源。

3、設置其他信號線
其他信號線包括VD0-VD23和VFRAME、VLINE、VCLK等,分別在GPCCON,GPDCON中選擇相應功能。

4、設置LCD的頻率(VCLK)
LCD的Datasheet上一般會寫有一個推薦的頻率,比如我使用的屏幕推薦頻率為6.4M,我需要通過一些計算選擇一個合適的CLKVAL以產(chǎn)生這個頻率:
對于TFT LCD,S3C2440提供的VCLK的計算公式為:VCLK = HCLK / ((CLKVAL+1)*2)
可以得出:CLKVAL = HCLK / (VCLK * 2) - 1
我 的HCLK是100Mhz(CPU運行在400Mhz, CLKDIV_VAL設置為5,F(xiàn)clk:Hclk:Pclk = 1:4:8),VCLK使用屏幕推薦的6.4M,得到:CLKVAL = 100000000 / (6400000 * 2) - 1 = 6.8
選擇最接近的整數(shù)值7,寫入LCDCON1:17-8。
(VCLK其實就是根據(jù) 每秒幀數(shù)*幀行數(shù)*行像素 計算出來的,幀行數(shù)和行像素需要包含空白數(shù)和同步數(shù))

5、設置其他相關參數(shù)
LCD相關的參數(shù)主要還有這幾個:LINEVAL: LCD水平像素-1,如320-1 = 319HOZVAL: LCD垂直像素-1,如240-1 = 239HFPD: 行開始前的VCLK時鐘數(shù)(LCD屏幕的Datasheet一般有推薦值)HBPD: 行結束后的VCLK時鐘數(shù)(LCD屏幕的Datasheet一般有推薦值)HSPW: 行之間水平同步的無效VCLK時鐘數(shù)(LCD屏幕的Datasheet一般有推薦值)VFPD: 幀數(shù)據(jù)開始前的空白行數(shù)(LCD屏幕的Datasheet一般有推薦值)VBPD: 幀數(shù)據(jù)結束后的空白行數(shù)(LCD屏幕的Datasheet一般有推薦值)VSPW: 幀之間垂直同步的無效行數(shù)(LCD屏幕的Datasheet一般有推薦值)
(相關寄存器LCDCON2, LCDCON3, LCDCON4)

6、設置視頻緩沖區(qū)的地址
2440支持虛擬屏幕,可以通過改變LCD寄存器實現(xiàn)屏幕快速移動:
PAGEWIDTH:虛擬屏幕一行的字節(jié)數(shù),如果不使用虛擬屏幕,設置為實際屏幕的行字節(jié)數(shù),如16位寬320像素,設為320 * 2OFFSIZE:虛擬屏幕左側偏移的字節(jié)數(shù),如果不使用虛擬屏幕,設置為0
LCDBANK: 視頻幀緩沖區(qū)內存地址30-22位LCDBASEU: 視頻幀緩沖區(qū)的開始地址21-1位LCDBASEL: 視頻幀緩沖區(qū)的結束地址21-1位
(相關寄存器LCDSADDR1,LCDSADDR2,LCDSADDR3)

7、確定信號的極性
2440的LCD控制器允許設置VCLK、VLINE、VFRAME等信號的極性(上升沿有效還是下降沿有效),需要對照LCD的Datasheet一一確認。
(相關寄存器LCDCON5)

8、禁止LPC3600/LCC3600模式
如果不是使用三星LPC3600/LCC3600 LCD,必須禁止LPC3600/LCC3600模式(寫入0到TCONSEL)。


上一頁 1 2 下一頁

關鍵詞: S3C2440LCD編

評論


技術專區(qū)

關閉