s3C44B0X中關於frameBuffer的問題

s3C44B0X中關於frameBuffer的問題
 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
.
.
#if (LCD_TYPE==MLCD_240_320)
#define SCR_XSIZE     (480) 
#define SCR_YSIZE     (640)
.
.
#define ARRAY_SIZE_G16        (SCR_XSIZE/2*SCR_YSIZE)
.
.
unsigned int (*frameBuffer16)[SCR_XSIZE/8];
.
.
void Lcd_Init(int depth)
{       
    switch(depth)
    {case 16:
       if((U32)frameBuffer16==0)
       {
           //The total frame memory should be inside 4MB.
           //For example, if total memory is 8MB, the frame memory
           //should be in 0xc000000~0xc3fffff or c400000~c7fffff.
           //But, the following code doesn't meet this condition(4MB)
           //if the code size & location is changed..
           frameBuffer16=(unsigned int (*)[SCR_XSIZE/8])malloc(ARRAY_SIZE_G16);
.
.
.
       }
我的S3C44B0X開發板外接的是240X320的STN  16級灰度LCD,在初步學習了相關的LCD顯示的程序後,通過改動開發板配套的程序也實現了在LCD上顯示自己照片的功能,對LCD的驅動顯示過程有了一個大體的瞭解,但是在學習程序的細節上有很多的疑惑,主要是某些涉及指針的變量,函數,以及某些運算過程。以上的一段程序(將必要的語句集合到一起以便研究)就讓我迷惑了很久,在網上搜索了相關的資料,發現一些論壇上對於這個問題的討論也不少,但都沒有太詳細的解答,參考了各種資料和大家的討論後,我自己琢磨了一下,問題終於有點眉目了,我想把我的一點心得寫出來和大家分享,有什麼不對的地方,歡迎大家一起討論!
 
    **首先要弄清楚LCD是如何顯示的,16灰度的LCD是每4位(也就是半個字節)代表一個象素,那麼對於256色的LCD來說就是8位(恰好是一個字節的數據寬度)對應一個象素,而S3C44B0X是通過寫顯示緩衝區來實現在LCD屏上顯示圖象的,也就是顯示緩衝區映射的是LCD屏幕上的每一點!明白這一點很關鍵,接下來看一下程序中相關的參量的意義:
#if (LCD_TYPE==MLCD_240_320) 
  //這裏是LCD的類型,我板上的是24X320的16級灰度屏
#define SCR_XSIZE     (480)
#define SCR_YSIZE     (640)
//這實際是定義的虛擬屏幕的寬度(X)和高度(Y),就是說用                               
240X320的屏可以局部顯示480X640的圖象,當然也可以定義的更大  一些來顯示更大的圖象
#define ARRAY_SIZE_G16         (SCR_XSIZE/2*SCR_YSIZE)
//這裏將ARRAY_SIZE_G16的大小定義爲SCR_XSIZE/2*SCR_YSIZE,也就是480*640/2,爲什麼要/2呢?我的 理解是,以後涉及到以ARRAY_SIZE_G16爲大小的參量時肯定是以字節爲單位存儲的!參照之前說的LCD的顯示規則,要想在16級灰度屏上完整顯示大小爲480X640的圖象,至少要有480X640 BYTE的顯示緩衝才能對應480X640個點,而字節的數據寬度是8位,因此只需要480X640/2個字節型的數據就可以了。
unsigned int (*frameBuffer16)[SCR_XSIZE/8];
//在這裏定義了顯示緩衝區,它的大小是SCR_XSIZE/8,也就是480/8,在這裏frameBuffer16是一個指針,它指向的是包含SCR_XSIZE/8個unsigned int類型的(在DEF.H中該類型爲32位,即U32)元素的數組; 這時,SCR_XSIZE/8的意義就顯而易見了,因爲數組的元素是32位的unsigned int類型的,只需要有SCR_XSIZE/8個元素即可以實現輸出480個象素的目的!當然480個象素只是480X640圖象大小的1/640,也就是屏幕上的一行,——是一行的顯示緩衝區;要對應480X640大小的圖象,至少需要480X640大小顯示緩衝區,所以我們接着往下看,
void Lcd_Init(int depth)
//來到真正LCD初始化的地方,在這裏要着重理解的是其中分配內存的一句,其他的很容易理解,就略去了。
if((U32)frameBuffer16==0)
//這一句是在檢查是否已經爲顯示緩衝分配過內存了?(我的猜測,不知道省掉這一句會有什麼區別?)
frameBuffer16=(unsigned int (*)[SCR_XSIZE/8])malloc(ARRAY_SIZE_G16);
 
//由於剛纔已經定義了一個指針frameBuffer16,而且知道要顯示480X640的圖象至少需有480X640/2字節大小的顯示緩衝,理解這一句已經不象開始那樣一頭霧水了,通過malloc(ARRAY_SIZE_G16)在內存中分出一塊大小爲ARRAY_SIZE_G16字節,也就是剛好可以滿足480X640顯示需要的內存區做爲顯示緩存,也許有人要問了,剛纔不是定義過frameBuffer16了嗎?爲什麼現在又定義一次?第1次定義了frameBuffer16這個指針,是指向數組類型的指針,而第2次是將frameBuffer16指向一個實際的內存區域,也就是通過malloc(ARRAY_SIZE_G16)分配的,注意ARRAY_SIZE_G16的大小是480X640/2個字節,(unsigned int (*)[SCR_XSIZE/8])是強制類轉換;我理解這裏在(*)後加一個[SCR_XSIZE/8]的用意,其實只是把malloc(ARRAY_SIZE_G16)分配的內存分成大小爲SCR_XSIZE/8的塊(並沒有實際的意義,爲了便於理解可以這麼考慮),也就是說frameBuffer16每進行一次‘+1’的操作,實際上是地址增加[SCR_XSIZE/8]個字,指針frameBuffer16仍然是32位的,這樣的話就共有(ARRAY_SIZE_G16/8(換算成U32類型的))/(SCR_XSIZE/8)=(480X640/8)/(480/8)=640塊,這說明什麼呢?要是換個理解方式,用2維數組的概念來理解的話,也就是說frameBuffer16指向的是一塊[640][480/8]的2維空間。
 
有了以上的理解,可以看一個最基本的象素輸出函數:
 
void _PutPixelG16(U32 x,U32 y,U8 c)
 
{
 
    if(x<SCR_XSIZE && y<SCR_YSIZE)
 
        frameBuffer16[(y)][(x)/8]=( frameBuffer16[(y)][x/8] & ~(0xc0000000>>((x)%8)*4) )
 
            | ( (c)<<((8-1-((x)%8))*4) );
 
}
爲了更方便形象地對應屏幕上指定位置(X,Y)的點,可以看到_PutPixelG16這個函數即是通過frameBuffer16[(y)][(x)/8],以2維數組的形式來寫顯示緩衝區的。
有了這些理解,對於其它圖形函數的理解應該會更輕鬆了!
 
不知道以上我說的有沒有什麼不對的地方,我也是剛剛學S3C44B0X,沒有什麼經驗可談,就把我自己的理解和大家分享吧!
 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
補充:
 
在lcdlib.c可以找到關於MALLOC()的定義,可以看出MALLOC分配的內存的大小以字節來計算,
 
char Image$$RW$$Limit[];
 
void *mallocPt=Image$$RW$$Limit;
.
.
.
void * malloc(unsigned nbyte)
/*Very simple; Use malloc() & free() like Stack*/
 
{
    void *returnPt=mallocPt;
    mallocPt= (int *)mallocPt+nbyte/4+((nbyte%4)>0); //to align 4byte
    if( (int)mallocPt > HEAPEND )
    {
       mallocPt=returnPt;
       return NULL;
    }
    return returnPt;
}
當程序中第1次使用MALLOC   時,RETURNPT指向的初始位置就是Image$$RW$$Limit[]的起始位置,由mallocPt= (int *)mallocPt+nbyte/4+((nbyte%4)>0)來計算出分配NBYTE後的指針的位置,接下來判斷所分配的內存大小是否超過了堆(HEAP)的界限,如果沒有超過界限,將可以使用從Image$$RW$$Limit到mallocPt之間的內存塊,由於mallocPt是一個全局變量,所以在第1次分配內存後,它的值將是(int *)mallocPt+nbyte/4+((nbyte%4)>0),在下一次使用MALLOC的時候將從這個位置開始分配。但這樣來分配內存似乎存在一個很嚴重的問題,特別是在多次使用MALLOC的時候,由於沒有有效的邊界檢測,誤操作很可能導致指針從第1次MALLOC分配的內存區進入第2次分配的內存區,從而引起數據的錯亂而使程序崩潰 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章