S3C2440的LCD編程
4. 幀緩沖(FrameBuffer):
幀緩沖是Linux為顯示設備提供的一個接口,它把一些顯示設備描述成一個緩沖區,允許應用程序通過 FrameBuffer定義好的接口訪問這些圖形設備,從而不用去關心具體的硬件細節。對于幀緩沖設備而言,只要在顯示緩沖區與顯示點對應的區域寫入顏色 值,對應的顏色就會自動的在屏幕上顯示。下面來看一下在不同色位模式下緩沖區與顯示點的對應關系:本文引用地址:http://www.104case.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;
}
很容易發現TFT LCD上顯示單個像素的函數實際上很簡潔,看來似乎只需要LCD_BUFFER[(y)][(x)] = c這一句話.下面就來分析下,是如何通過這一句話來實現在LCD上顯示單個像素的,先分析下Lcd_Init()即LCD初始化函數:
#define rGPCCON
#define rGPCUP
#define rGPDCON
#define rGPDUP
#define rLCDCON1
#define rLCDCON2
#define rLCDCON3
#define rLCDCON4
#define rLCDCON5
#define rLCDSADDR1
#define rLCDSADDR2
#define rLCDSADDR3
#define rLCDINTMSK
#define rTPAL
void Lcd_Init(void)
{
}
程序分析至此,大概已經清楚是如何通過LCD_BUFFER[(y)][(x)] = c來實現在LCD上顯示單個像素了。就是在設置好各個LCD寄存器之后,通過將LCD_BUFFER地址與LCDBANK以及LCDBASEU、 LCDBASEL對應之后,通過改變LCD_BUFFER里不同單元存儲的值(即像素的顏色),即可在LCD相應位置上做出顯示。
那么在應用不同LCD的時候,只需對LCDCONx以及LCDSADDRx做出相應的配置,再創建一個數組,做出上述的地址映射即可。
關于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數據的位數,LCD的數據實際上是LCD要顯示的顏色,24位的是紅綠 藍各占8位,16位則是紅綠藍按照565分配的,其實24的也可以只接16位,每個顏色地位接地就可以,所以要給LCD的緩沖區一個數據才能在LCD上顯 示出來。那究竟是怎么顯示的呢,那就得先說一下像素了,LCD的像素實際上就LCD屏幕有多少個點,LCD顯示的東西都是一個一個點拼湊出來的,比如我用 的是320*240的LCD,就是說LCD每一行有320個點,而每一列有240個點,所以總共有320*240個點,我們讓適當的點顯示適當的顏色就達 到了我們的目的。
其實剛開始困擾我們的是LCD的初始化的問題,要設置的東西比較多,其實我們是記不住這些東西的,呵呵,作為入門我們可以參考別人的初始化程序,把里面的參數改成我們自己的LCD的參數就OK了。
那么我們到底是怎么把我們要顯示的數據送給LCD控制起的呢?是這樣的,我們可以定義一個二維數組,把我們要顯示的數據存到里面,然后把這個數組的地 址賦給LCD的相應的寄存器,這個寄存器是LCDSADDRn,具體的設置大家可以參考數據手冊,我們可以把二維數組的坐標和LCD的坐標對應起來,那么 我們就可以隨意的讓哪一個像素點顯示什么顏色就顯示什么顏色了。這就把數據送出的過程,也就是顯示一個像素點的過程。
到現在我們已經知道如何顯示一個像素了,那接下來就是LCD顯示最基本的東西了----字符和圖片。漢字和圖片的顯示都是基于像素點的顯示的,我們把 要顯示的字符和圖片轉化成相應的數據,然后傳遞給LCD即可。我們可以專門的寫一個顯示字符的函數和一個顯示圖片的函數。顯示字符的數據可以用取模軟件生 成,因為生成的字符數據是表示的每一個點要不要亮,亮的地方用1表示,不亮的地方用0表示,所以如果用LCD顯示,我們還要告訴LCD顯示什么顏色,這才 是LCD需要的數據,比如說16*16的數據,有16行16列,我們將一行的數據,也就是16位數據的每一位都取出來,為1的地方,我們就給LCD一個 16位的數據,為0的地方就不給數據,這樣就能顯示了,取模生成的數據都是按行來的。圖片的顯示直接就將16位的數據傳遞給LCD,這個圖片數據的產生, 我們可以用軟件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以產生這個頻率:
對于TFT LCD,S3C2440提供的VCLK的計算公式為:VCLK = HCLK / ((CLKVAL+1)*2)
可以得出:CLKVAL = HCLK / (VCLK * 2) - 1
我 的HCLK是100Mhz(CPU運行在400Mhz, CLKDIV_VAL設置為5,Fclk:Hclk:Pclk = 1:4:8),VCLK使用屏幕推薦的6.4M,得到:CLKVAL = 100000000 / (6400000 * 2) - 1 = 6.8
選擇最接近的整數值7,寫入LCDCON1:17-8。
(VCLK其實就是根據 每秒幀數*幀行數*行像素 計算出來的,幀行數和行像素需要包含空白數和同步數)
5、設置其他相關參數
LCD相關的參數主要還有這幾個:LINEVAL: LCD水平像素-1,如320-1 = 319HOZVAL: LCD垂直像素-1,如240-1 = 239HFPD: 行開始前的VCLK時鐘數(LCD屏幕的Datasheet一般有推薦值)HBPD: 行結束后的VCLK時鐘數(LCD屏幕的Datasheet一般有推薦值)HSPW: 行之間水平同步的無效VCLK時鐘數(LCD屏幕的Datasheet一般有推薦值)VFPD: 幀數據開始前的空白行數(LCD屏幕的Datasheet一般有推薦值)VBPD: 幀數據結束后的空白行數(LCD屏幕的Datasheet一般有推薦值)VSPW: 幀之間垂直同步的無效行數(LCD屏幕的Datasheet一般有推薦值)
(相關寄存器LCDCON2, LCDCON3, LCDCON4)
6、設置視頻緩沖區的地址
2440支持虛擬屏幕,可以通過改變LCD寄存器實現屏幕快速移動:
PAGEWIDTH:虛擬屏幕一行的字節數,如果不使用虛擬屏幕,設置為實際屏幕的行字節數,如16位寬320像素,設為320 * 2OFFSIZE:虛擬屏幕左側偏移的字節數,如果不使用虛擬屏幕,設置為0
LCDBANK: 視頻幀緩沖區內存地址30-22位LCDBASEU: 視頻幀緩沖區的開始地址21-1位LCDBASEL: 視頻幀緩沖區的結束地址21-1位
(相關寄存器LCDSADDR1,LCDSADDR2,LCDSADDR3)
7、確定信號的極性
2440的LCD控制器允許設置VCLK、VLINE、VFRAME等信號的極性(上升沿有效還是下降沿有效),需要對照LCD的Datasheet一一確認。
(相關寄存器LCDCON5)
8、禁止LPC3600/LCC3600模式
如果不是使用三星LPC3600/LCC3600 LCD,必須禁止LPC3600/LCC3600模式(寫入0到TCONSEL)。
評論