S3C2410 LCD 驅動程序移植及GUI程序編寫

S3C2410 LCD 驅動程序移植及GUI程序編寫

1. 爲了不讓大家覺枯燥,讓朋友們更好的理解,我以一個實例來敘述 S3C2410 下一個驅動程序的編寫(本文的初始化源碼以華恆公司提供的 s3c2410fb.c 爲基礎)及簡單的 GUI程序的編寫。

 

2. 拿到一塊 LCD,首先要將 LCD的各個控制線與 S3C2410 LCD控制信號相接,當然,電源也一定要接入了,否則不亮可別找我。另外需要注意以下幾點:

1 背光:對於大部分的彩色 LCD一定要接背光,我們才能看到屏上的內容;

2 控制信號:不同的 LCD 廠商對於控制信號有不同的叫法,S3C2410 芯片手冊也給出了一個信號的多個名稱(圖一),這就要看你們硬件工程師的功底了,

 

圖一 S3C2410 手冊上給出的控制信號的名稱及解釋

   這裏我做一個簡單的介紹:  

VFRAMELCD 控制器和 LCD 驅動器之間的幀同步信號。該信號告訴 LCD屏的新的一幀開始了。LCD 控制器在一個完整幀顯示完成後立即插入一個VFRAME 信號,開始新一幀的顯示;  

VLINELCD控制器和 LCD驅動器之間的線同步脈衝信號,該信號用於 LCD驅動器將水平線(行)移位寄存器的內容傳送給 LCD 屏顯示。LCD 控制器在整個水平線(整行)數據移入 LCD驅動器後,插入一個 VLINE 信號; 

VCLKLCD控制器和 LCD驅動器之間的像素時鐘信號,由 LCD控制器送出的數據在 VCLK的上升沿處送出,在 VCLK的下降沿處被 LCD驅動器採樣; 

VMLCD驅動器的 AC 信號。VM 信號被 LCD驅動器用於改變行和列的電壓極性,從而控制像素點的顯示或熄滅。VM 信號可以與每個幀同步,也可以與可變數量的 VLINE 信號同步。

3 數據線:也就是我們說的 RGB 信號線,S3C2410 芯片手冊上都有詳細的說明,由於篇幅關係,在此不一一摘錄,不過需要與硬件工程是配合的是他採用了哪種接線方法,24 16 位或其它。對於 16 TFT 屏又有兩種方式,在寫驅動前你要清楚是 565還是 555I,這些與驅動的編寫都有關係

4 要注意一下 LCD 的電源電壓,對於手持設備來說一般都爲 5V 3.3V,或同時支持 5V 3.3V,如果 LCD的需要的電源電壓是 5V,那就要注意了,S3C2410 的邏輯輸出電壓只有 3.3V,此時一定要讓你們的硬件工程師幫忙把 S3C2410 的邏輯輸出電壓提高到 5V,否則你可能能將屏點亮,但顯示的圖像要等到太陽從西邊出來的那一天才能正常,呵呵,我可喫過苦頭的哦!

5 3.3V邏輯電壓轉變成 5V邏輯電壓電路圖(此圖由華恆公司提供)

 

6 最後還有一個問題,有些 LCD 屏還需要一顆伴侶芯片,就是 S3C2410 手冊中的那顆 LPC3600。這可能在 LCD 的手冊中都有論述吧,我沒有遇到過這樣的屏,所以也不是很清楚。那麼是不是所有的屏與 S3C2410相接都需要那個討厭的傢伙呢?這是好多人(包括我)在最開始都會有的疑問,不過現在的大部分 LCD 屏應該都不需要這個討厭的傢伙了,屏的控制信號直接與 S3C2410 的控制信號相接就可以了,至少我還沒有遇到過。

7 還得提醒大家一下,S3C2410 LCD屏的連線千萬千萬別超過 0.5 ,否則會給你帶來麻煩,我也是喫過苦頭的,LCD屏上面的部分顯示任何信息都是正確的,而只有屏的底部會有時正確有時錯誤,折騰了好一陣,才知道是連線太長的緣故!

 

3. 好了,在硬件工程師的幫助下,硬件接好了,那就該我們做軟件的幹活了,編寫驅動吧

1 讓我們首先看一下 RGB數據結構的定義

s3c2410fb.c 中找到如下信息

static struct s3c2410fb_rgb xxx_tft_rgb_16 = {

    red: {offset:11, length:5,},

    green: {offset:5, length:6,},

    blue: {offset:0, length:5,},

    transp: {offset:0, length:0,},

}; 

這是對 16 位色的 RGB 顏色進行定義,RGBI = 5650,即我們常說的565 顯示方式。呵呵,爲了讓有些朋友更好的理解,我多羅嗦幾句,我們隨便寫一個 16 位數據的顏色數據(爲了分析的方便,我把它寫成二進制)

RGB = 10101101 10111001

根據上面的結構定義我們來分析一下 RGB 各是多少(因爲沒有透明色,我們不去分析)

a) blue: {offset: 0,   length: 5} 偏移量爲 0,長度爲 5,我們從那個 RGB 中提取出來便是“11001

b) green:{offset: 5,   length: 6} 偏移量爲 5,長度爲 6,我們從那個 RGB 中提取出來便是 101 101

c) red: {offset: 11, length: 5 } 偏移量爲 11,長度爲 5,我們從那個 RGB 中提取出來便是 10101

d) 我們得到了一個 RGB 值爲 1345200,就是這個顏色

e) 那麼反過來,有了 RGB的值我們該如何,因爲 RGB 的有效位數都不足一個字節(8 位),那我們只能忍痛割愛了,捨棄掉低位數據,代碼如下

r=(rDat&0xF8);

g=(gDat&0xFC);

b=(bDat&0xF8);

hight=r|(g>>5);

low=(g<<3)|(b>>3);

color=(hight<<8)|low;

    

記住,這段代碼在 GUI 程序中是有用的

2 對於 8 位色(256 色)的數據結構定義

static struct s3c2410fb_rgb rgb_8 = {

    red: {offset:0, length:4,},

    green: {offset:0, length:4,},

    blue: {offset:0, length:4,},

    transp: {offset:0, length:0,},

}; 

這是原程序中給出的定義,我感覺有些錯誤,我認爲應該爲 RGB = 332

   static struct s3c2410fb_rgb rgb_8 = {

    red: {offset:5, length:3,},

    green: {offset:2, length:3,},

    blue: {offset:0, length:2,},

    transp: {offset:0, length:0,},

}; 

因爲沒有親自去調試,所以沒有什麼發言權,希望做過這方面的朋友給我一個答案。

3 對於 CSTN 屏,一般都能達到 12 位色(4096 色)的,S3C2410 這顆芯片也是支持的,但是在軟件方面要做的工作比較大,因爲從原有的代碼,我們找不到任何 12位色顯示的跡象,另外 Linux 本身好像也不支持 12 位色的,如果你要作的事情比較簡單,那你就自己寫代碼吧。我在此給出 12位色的數據結構定義

static struct s3c2410fb_rgb xxx_stn_rgb_12 = {

    red: {offset:8, length:4,},

    green: {offset:4, length:4,},

    blue: {offset:0, length:4,},

    transp: {offset:0, length:0,},

}; 

 

但是要完成 12 位色 CSTN 屏驅動程序的編寫還有一些工作要做,稍後我會適當的向大家介紹。

4 接着看下面的代碼,其中要修改的部分已經用綠色標出,下面分別進行介紹。

 

a) 顏色位數

bpp16

如果你的 LCD 屏是 TFT 的,那一般都可以達到 16 位色或 24 位色,這也要看硬件怎麼連接了,根據情況進行設置即可;

如果你的 LCD屏是 CSTN的,按照常規 LCD手冊的介紹,一般都可以支持到8 位色(256色),而實際的 CSTN屏的顯示效果都可以達到 12 位色(4096色),那可有很大的區別的,如果你要選擇便宜的屏又要豐富的顏色,那就費點勁,完成 12 位色的驅動。

b) LCD屏的寬度和高度

xres: 240

yres: 320

     這個就不用多說了,你的屏的分辨率是多少就設置成多少唄。

c) 寄存器的設置,這些也不困難。下面就讓我們一起一口一口的將 S3C2410 LCD寄存器統統喫掉!   首先介紹一下我這塊屏,這是日立的一塊 TFT 屏,大小爲 640X240,可以支持到 16位色。   與驅動有關的一張表

 

圖二 LCD屏資料

 

有了這些信息,讓我們看一下 LCD寄存器的設置。

LCD控制器1

 

 

LINECNT --- 這是一個只讀的數據,我們當然沒有必要理它  

CLKVAL    --- 這可是一個很有用的參數,其實沒必要管它後面的計算,我們可以通過實際的測試來得出一個有效的值,對於320x240 的屏一般設置爲 7 就可以了,而對於 640x480 的屏,該值可以小一點。對於後面的計算公式及註釋(STN: CLKVAL >= 2TFT: CLKVAL >= 0),我不知道該如何去理解,因爲在實際的應用中我點了一塊 640X240 CSTN 屏,當我的 CLKVAL = 1 時才達到了一個最佳的效果,這似乎與說明書相違背,我也解釋不清爲什麼?!  

PNRMODE --- 這個應該不用多做解釋,大家一看都明白了,對於 TFT 屏,只能設置成 11,而對於 CSTN 屏,可能需要根據實際屏的信息去設置,我遇到的屏都設置成 10,即 8bit 單掃描模式。對於4bit單掃描、4bit 雙掃描、8bit 單掃描的說明在 s3c2410 的手冊中有詳細的介紹,大家可以去參考一下。  

BPPMODE   --- 這個參數更不用多說了吧,就是設置屏的顏色位數嘍。  

這些參數的設置都很簡單,我給出我這塊屏的定義:

lcdcon1: LCD1_BPP_16T | LCD1_PNR_TFT | LCD1_CLKVAL(1),

同時,我也給出一塊 CSTN 屏的寄存器參數信息

lcdcon1: LCD1_BPP_12S | LCD1_PNR_8S | LCD1_CLKVAL(9),

 

   LCD控制器2

 

 

對於 TFT 屏必須要填,至於什麼意思怎麼翻譯,相信大家都比我的水平強,自己翻譯吧。我只說明從 LCD中如何將這個值“扣”出來。

很容易,看一下圖二 LCD屏資料,對比一下得出如下信息: 

 

LCD2_VBPD:

Vertical back porch 典型值爲 7  

LCD2_VFPD

Vertical front porch 典型值爲 4  

LCD2_VSPW

Vsync Valid width 典型值爲 2  

關於 LINEVAL 在程序的後面將會提到,此處不必理會。  

經過分析,我們知道了如何設置 LCD2

lcdcon2: LCD2_VBPD(7) | LCD2_VFPD(4) | LCD2_VSPW(2),

對於 STNCSTN)屏,這個寄存器的設置最簡單,將 VBPDVFPDVSPW 都設置成 Zero 就可以了。即

lcdcon2: LCD2_VBPD(0) | LCD2_VFPD(0) | LCD2_VSPW(0),

 

LCD控制器3

 

對於 TFT 屏,很容易將 HBPD HFPD 找出來,如下 

 

LCD3_HBPD:

Horizontal back porch 典型值爲 37  

LCD3_HFBD:

Horizontal back porch 典型值爲 32  

對於 HOZVAL 同樣會在後面提到,此處暫時不管  

經過分析,我們知道了如何設置 LCD3

lcdcon3: LCD3_HBPD(37) | LCD3_HFPD(32) ,

對於(STNCSTN屏,我沒有很好的理解 WDLY LINEBLANK 的真正涵義,通過改變這兩個參數的值,我也沒有得到特別明顯的差異,我一般設置爲:

lcdcon3: LCD3_WDLY_16 | 0x10 ,

 

LCD控制器4

 

   對於 TFT 屏,需要設置 HSPW 的值,這個在 LCD 手冊上也很容易得到

LCD4_HSPW

Hsync Valid width 典型值爲 5  

至於 MVAL,我不知道是什麼意思,有什麼作用,我從來不動它,只取它最初的那個值 13  

經過分析,我們知道了如何設置 LCD4

lcdcon4: LCD4_HSPW(5) | LCD4_MVAL(13) ,

對於 STNCSTN)屏,像 WDLY 一樣,我通常不改變,因爲改變了沒有發現有什麼作用,這是我驅動中的代碼,好幾塊屏都一樣的:

lcdcon4: LCD4_WLH(0) | LCD4_MVAL(13) ,

 

   LCD控制器5

 

 

這個寄存器的看起來比較複雜,但是無外乎這幾類: 

 

只讀信息:VSTATUS HSTATUS

只讀的東東,設置它也沒用,不必理會。  

TFT 屏的顏色信息:BPP24BLFRM565

TFT 屏的顏色信息,這個我們在 LCD的硬件連接時已經提到了,根據具體的接線方式,設置信息。  

控制信號的極性

TFT/STN 屏控制信號的極性:INVVCLKINVVLINEINVVFRAMEINVVDINVPWRENPWREN

TFT 屏特有的控制信號的極性:INVVDENINVLENDENLEND

這些信息主要是使S3C2410的信號輸出極性與LCD屏的輸入極性的問題,需要根據具體的硬件進行設置,較爲常見的是vline/hsync VFRAME/VSYNC脈衝的極性。  

顏色信息的字節交換控制位:BSWPHWSWP

這兩位用來控制字節交換和半字交換,主要用來大小頭的問題,如果輸出到屏上的漢字左右互換了,或者輸出到屏上的圖花屏了,可以更改這個選項。具體涵義在 S3C2410芯片手冊上有詳細的說明。  

我的這塊 TFT 的信息設置如下:

lcdcon5: LCD5_FRM565 | LCD5_HWSWP | LCD5_PWREN ,

一塊 CSTN屏的信息

lcdcon5: LCD5_BSWP | LCD5_PWREN ,

FrameBuffer 起始寄存器 1

  z

這個寄存器的設置沒有必要去修改(TFT/STN),都使用默認的代碼即可:

 

 

FrameBuffer 起始寄存器 2 FrameBuffer 起始寄存器 3

 

 

 

這兩個寄存器的設置比較重要,在此我給出 12 位色 CSTN 屏和 16 位色TFT 的設置代碼:

 

   前面提到的 LINEVAL HOZVAL 以源碼的形式給出,其中 CSTN 8 位色沒有經過測試。

 

 

RGB Loopup Table Register

 

 

   這三個寄存器的在驅動 256 CSTN 屏的時候需要使用,我在別的芯片上使用過,因爲這顆芯片支持 12 位色,所以沒有去調試,我給

出兩組可能的值:

S3C44B0 上的

rREDLUT = 0xFCA86420;

rGREENLUT = 0xFCA86420;

rBLUELUT = 0xFFFFFA50;

Jupiter 上的

rREDLUT = 0xFEC85310

rGREENLUT = 0xFEC85310

rBLUELUT = 0xFB40

5 好了,各個寄存器的設置完成了,最後在驅動 CSTN屏的時候需要提醒大家一句,CSTN的信號引腳中有一個叫VM/DISP的信號線,這個信號線的作用就是打開LCD的顯示開關,讓其進行顯示,它可以接到任何一個 GPIO 口上。S3C2410 中提供了一個 VM 信號,可以將 LCD的這個信號與 S3C2410 VM 信號相接即可,然後在驅動中一定要加上如下語句(藍色選中部分):

 

否則你的 LCD可能沒有任何顯示哦(對於 TFT 屏不需要這個語句)

6 關於 12 位色的 CSTN屏的驅動還需要做一些工作,我在這裏簡單介紹一下:

a) 首先要完成一個 fbcon-cfb12.c fbcon-cfb12.h 的編寫,這兩個文件很簡單,在armLinux 中不是提供了 fbcon-cfb16.c fbcon-cfb12.h 嗎?簡單修改一下就可以了;

b) fbcon-cfb12.c 的編譯加入 Config.in 中(不會的話去 google 搜一下,或者看一下我的另一篇文章《JFFS2 HHARM2410 上的實現》,裏邊有一些說明),並定義一個 FBCON_HAS_CFB12 參數(模仿 FBCON_HAS_CFB16 唄);

c) 另外,需要在 s3c2410fb.c 中的相應部分加上對 12位色的支持即可。呵,說起來簡單,但實際做起來可能會有一些問題,給大家一個竅門:在程序中找到#ifdef FBCON_HAS_CFB16 之類的代碼,簡單理解一下加上對 12 位色的支持;

d) 我只給出函數 s3c2410fb_set_var中的改動,其他的應該都不是很困難,相信朋友們都能搞定。

 

e) 不要跟我要源碼哦,否則老闆會不高興哦

 

4. 驅動寫好了,重新 Make,下載就可以了。如果一切順利,在 TFT 屏或 256 色的 CSTN屏上會有一個漂亮的小蜻蜓(應該是蜻蜓吧)出現。注意,並不是蜻蜓出現了就代表你的驅動 OK了,還要用 GUI 程序做進一步的測試,因爲某一個或幾個參數雖然不正確,但是仍然能夠看到小蜻蜓的,但顯示圖形的時候就有問題了。另外,在驅動 CSTN 12位色的時候,我們在屏上看不到小蜻蜓(我的 N CSTN屏上都沒見到小蜻蜓),我想,可能是 armLinux 本身不支持 12 位色顯示,或者我們某些地方沒搞對的原因吧,但這不代表你的驅動有問題,用 GUI 程序寫 FrameBuffer,看看能否的到正確的結果。

 

5. GUI 程序的編寫

FrameBuffer 驅動寫好了,那麼怎麼去使用,怎麼在 LCD 上顯示圖像呢?這就是 GUI程序的任務了,其實要在 LCD 上顯示圖像,說白了就是把數據(包含顏色)寫到FrameBuffer 中對應的位置就可以了。如果你使用如 MicrowinowMiniGuiQt 之類的GUI,則沒有必要關心 FrameBuffer LCD屏上的點如何進行映射了,但如果你在使用了 CSTN 屏,並且要顯示效果好的照片,選擇了 CSTN 12 位色(4096 ),那你就要自己寫 GUI 程序了,因爲好像 armLinux(Linux)本身都不支持 12 位色的,聽說 MiniGui支持 12 位色,但我在工作中的要求只是顯示圖形而已,沒有去深入研究 MiniGui,所以自己寫了。

另外請朋友們見諒的是我不能給出全部的源代碼,因爲我畢竟受僱於人,有些東東是可以 GPL 的,而有些東東暫時是不可以 GPL 的。

下面給出我的程序的部分代碼,希望對朋友們有所幫助。

1 全局變量的定義:

 

定義幾個全局變量,用起來方便。

2 初始化圖形顯示引擎,將 fb0 GUI buffer做個映射

 

   mmap函數使用戶空間的一段地址關聯到設備內存(FrameBuffer)上。無論何時,只要程序在分配的地址範圍內進行讀取或者寫入,實際上就是對設備的訪問,使用 mmap 可以既快速又簡單地訪問顯示卡的內存。對於象這樣的性能要求比較嚴格的應用來說,直接訪問能給我們提供很大不同。   不過我曾將幫一個網友調試了一個 S3C44B0 上的 GUI 程序,在他的 GUI mmap 函數總會出錯,因爲沒有拿到他的硬件和驅動源碼,沒有分析出其中的原因,所以只得用 write函數,直接向 fb0 寫入數據,奇怪的是隻寫入一部分數據好像都不起任何作用,只得整屏數據寫入才搞定了。這可就比較痛苦了,不過好在他只是寫入的黑白數據,數據量還不是很大,要是彩色的那可真的痛苦了   

   另外,我還想多囉嗦兩句,FrameBuffer的像素點與LCD屏上的像素點的對應關係 ,深入瞭解一下對程序的理解可能會更清楚一點。我們知道黑白(2 色)顏色用 0 1 就可以表示了,也就是 1 位數據就可以了,那 1 個字節就可以表示 8 位數據,假如這個字節是10101010FrameBuffer 的偏移地址爲 0,則在 LCD 屏上便會顯示出 4 個黑點,黑點中間會有 4 個白點出現(假如 1 是黑色);對於 4 色則用 00011011 就可以表示出四種顏色,即用兩位數據可以表示一位數據,那同樣是 10101010,則對應於 LCD 屏上則顯示的

是顏色值爲10,長度爲48/2)的一條直線;同理,對於8位色(256色),則8位數據才能表示出一個點的顏色值,10101010LCD屏上就只能顯示爲顏色值爲10101010的點了。  

    有了上面的基礎我們就可以很好的理解這個語句了:

     screensize = vinfo.xres*vinfo.yres*vinfo.bits_per_pixel/8;

FrameBuffer 的大小=LCD屏的寬度 * LCD屏的高度 * 每像素的位數 / 每字節的位數

例如,一個320*240的黑白平,FrameBuffer的大小爲

320 * 240 * 1 / 8 = 9600 (字節)

而一個320 * 24016位色LCD FrameBuffer的大小則爲

320 * 240 * 16 / 8 = 153600(字節)

3 TFT 16 位色的畫點函數

 

有了畫點函數,你還愁什麼?圖形漢字都可以搞定了吧!

4 CSTN 12位色的畫點函數

 

注意,爲了更便於代碼書寫,我在這個函數中將 fbp 定義爲 static char * fbp,而在TFT 16 位色的畫點函數中 fbp 的定義爲 U16 * fbp,你可以根據需要進行修改。

5 TFT 16 位色下顯示 24色位圖函數

 

Bmp文件的格式可以參考網上的一些資料,如果需要也可以直接找我要。

6 CSTN 12位色下顯示 24 色位圖函數

 

7 呵呵,別忘了關閉設備哦

void closegraph()

{

munmap(fbp,screensize);

   close(fb);

}

8 另外關於如何顯示漢字的 C 語言代碼,在我的網站上有現成的源碼《點陣字庫西那時程序》,在TC2.0 下都是可以跑的,她可以支持 12X12 點陣、14X14 點陣、16X16點陣漢字及 ASC 碼的顯示,將畫點函數和與設備相關的函數簡單替換就可以了,移植起來應該不困難。對於有更高需求的朋友,如果 GB 庫還不夠,我也提供了 GBK支持 2 萬多個漢字的顯示,只可惜只有 16X16點陣的字庫,沒有小字體。顯示方法我也提供了源碼哦(因爲網上沒有找到相關資料,再加上老劉我比較笨,我研究了好長時間才成功,就讓需要的朋友一起分享吧!)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章