一、概述
s3c2440的lcd控制器支援虛擬顯示,說的容易理解一點就是,可以顯示比實際顯示器大的影象。可以這樣想象,有乙個大的,但是顯示器(顯示串列埠)比較小,但是我們可以相對於大(即大不動)移動顯示器的位置,從而實現觀察大的其他部分的內容。晶元手冊上對這部分內容用乙個來生動展示如下。
這裡說明四點:
1.虛擬記憶體(大**的儲存空間)比視口的緩衝空間大
2. 虛擬記憶體的基位址是固定的
3.大**的開始位置(虛擬記憶體的基位址(lcdbank))是以4m對齊的,eg:0x30400000
4.可以更改視口的基位址(lcdbaseu)和結束位址(lcdbasel)來移動視口
二、lcd控制器分析
1、虛擬顯示的原理
思考兩個問題:
1.怎麼告知lcd控制器大**的尺寸,這將來涉及到視口如何取資料的問題(配置lcdsaddr3)
2.怎麼移動視窗(配置lcdsaddr1和lcdsaddr2)
可以直接告訴你,大**的垂直長度不用設定,只用設定大**的水平寬度。例如,我的顯示器視口大小是480*272,但是**的大小是640*480。這時,我們只用告訴lcd控制器大**的水平寬度640。在lcdsaddr3中有個offsize和pagewidth,其中pagewidth是視口寬度(480),而offsize是大**多於視口的寬度(160)。通過這兩個引數就告訴了控制器大**的水平寬度為(480+160=640)。
為什麼要規定這個大**的寬度呢?首先,我們考慮**在記憶體中是怎樣儲存的(以16bpp為例): 01
···639
(16bit)
(16bit)
(16bit)
(16bit)
(16bit)
(16bit)
(16bit)
(16bit)
(16bit)
(16bit)
(16bit)
(16bit)
可以看到理論上是個立體空間,(x,y)決定平面座標,而z決定顏色。但是,在儲存器上位址是連續的,可以看做一維的,說的意思是先存(0,0)位置的顏色,占用兩個位元組,然後再存(1,0)位置的顏色,又佔兩個位元組······存完一行時,緊接著再存下一行。總之一句話,這個大是連續的儲存在儲存器中。
然後,我們再考慮一下在這裡邊有乙個小的視窗,我們以視窗在最左上角為例說明,如下圖所示: 01
。。。479
。。。639
(16bit)
(16bit)
···
(16bit)
(16bit)
(16bit)
(16bit)
···
(16bit)
(16bit)
···
···
···
···
(16bit)
(16bit)
···(16bit)
(16bit)
(16bit)
(16bit)
···(16bit)
···(16bit)
我們可以看到,要顯示的視口比較小,它在顯示時從儲存器中讀取資料,並不是從連續的空間中讀取資料,而是只讀取每一行的部分(pagewidth)。
最後,我們來考慮一下,規定大寬度(pagewidth和offsize)的意義。
1.通過規定大的寬度,lcd控制器就知道如何劃分連續的儲存空間成一行一行的,即將連續的空間立體化。以lcdbank為0x30400000為例,寬度為(pagewidth+offsize=480+160=640)。這樣,lcd控制器就知道第一行末尾的位址(以位元組為單位)是(0x30400000+640*2-1)。其中,由於是16bpp,所以每個畫素佔兩個位元組,所以640要乘以2,才得到實際的一行的移動距離。同樣,第三行的第乙個畫素的位址是(0x30400000+640*2*2)。
2.pagewidth和offsize可以告訴lcd控制器,那些資料需要顯示,那些需要跳過。我們以上邊的圖為例,其實這個圖的視口的基位址就是lcdbank。在讀取資料顯示的時候,先把(0x30400000,0x30400000+(pagedith-1)*2)區間的儲存空間讀取到顯示器的第一行,然後跳過offsize*2個儲存單元(byte);接著再把(0x30400000+(pagedith+offsize)*1*2,0x30400000+(pagedith+offsize)*1*2+(pagedith-1)*2)讀取到顯示器的第二行,其中乘以1代表偏移了一行的距離;接著再把(0x30400000+(pagedith+offsize)*2*2,0x30400000+(pagedith+offsize)*2*2+(pagedith-1)*2)讀取到顯示器的第三行······
通過這些內容,相信你已經明白虛擬記憶體顯示的基本原理。
2、移動視口
還有乙個問題怎麼移動視口,明白了上邊的講述這個問題就相當簡單了。我們更改視口的起始位址(lcdbaseu)和結束位址(lcdbasel)就行了。先說一下這兩個引數的意義,lcdbaseu是視口起始位置相對於lcdbank的偏移位址,lcdbasel是視口結束位置相對於lcdbank相對於lcdbank的位址。
好了,舉個例子來說明如何平移視口。假設,我們已經把大傳到虛擬記憶體上了(以0x30400000為起始位址,佔據的儲存空間是640*480*2)。我們的視口佔據的記憶體空間大小是(480*272*2)。剛開始,我們的視口在大**的左上角,即lcdbaseu=0,而 lcdbasel為lower21bits(((0x30400000+640*272*2)>>1))。其中,函式lower21bits()是區低21位。其實,視口結束的位址(以byte為單位)是0x30400000+640*272*2-1,而(0x30400000+640*272*2)這種方式(小於這個限)是規定結束位址限的很好方式。 需要注意的是,這裡邊乘的基數是640,而不是480,因為一行的寬度是640,這點需要注意。我們可以結合下邊的lcdbasel計算位址好好理解一下。
這個時候,假設我們想右移影象100個畫素,那麼設定lcdsaddr1和lcdsaddr2就可以了。
#define lower21bits(n) ((n) & 0x1fffff)
#define lcdframebuffer 0x30400000
#define lineval_tft_480272 (272-1)
#define hozval_tft_480272 (480-1)
lcdsaddr1 = ((lcdframebuffer>>
22)<<
21) | lower21bits((lcdframebuffer+
100*
2)>>
1);lcdsaddr2 = lower21bits(((lcdframebuffer+
100*
2)+ \
(lineval_tft_480272+
1)*((hozval_tft_480272+
1)+160)*
2)>>
1);我們再在這個基礎上下移200個畫素,那麼程式為:
lcdsaddr1 = ((lcdframebuffer>>
22)<<
21) | lower21bits((lcdframebuffer+
100*
2+640*
200*
2)>>
1);lcdsaddr2 = lower21bits(((lcdframebuffer+
100*
2+640*
200*
2)+ \
(lineval_tft_480272+
1)*((hozval_tft_480272+
1)+160)*
2)>>
1);我們再在這個基礎上上移100個畫素,左移50個畫素,那麼程式為:
lcdsaddr1 = ((lcdframebuffer>>
22)<<
21) | lower21bits((lcdframebuffer+
100*
2+640*
200*
2-50*
2-640*
100*
2)>>
1);lcdsaddr2 = lower21bits(((lcdframebuffer+
100*
2+640*
200*
2-50*
2-640*
100*
2)+ \
(lineval_tft_480272+
1)*((hozval_tft_480272+
1)+160)*
2)>>
1);
對LCD的操作(S3C2440)
先簡單介紹下lcd的操作原理。如下圖的lcd示意圖,裡面的每個點就是乙個畫素點。想象有乙個電子槍,一邊移動,一邊發出各種顏色的光。這裡有很多細節問題,我們乙個乙個的梳理。電子槍是如何移動的?答 有一條clk時鐘線與lcd相連,每發出一次clk 高低電平 電子槍就移動乙個畫素。顏色如何確定?答 由連線...
求教 s3c2440問題
趙老師您好,我把您的程式新增到我的程式中去了,下面是主要 1 main函式 int main void a a b rgpbdat liushui delay 20 liushui liushui 0xffe 2 pwm初始化 void pwm init void 3 定時器中斷 static vo...
s3c2440系統時鐘
1 flck hclk和pclk的關係 一般來說,mcu的主時鐘源主要是外部晶振或外部時鐘,而用的最多的是外部晶振。在正確情況下,系統內所使用的時鐘都是外部時鐘源經過一定的處理得到的。由於外部時鐘源的頻率一般不能滿足系統所需要的高頻條件,所以往往需要pll 鎖相環 進行倍頻處理。在s3c2440中,...