在網路上看到已經有不少人把 UCGUI 成功移植到S3C44B0上了,不過他們只提供了他們的演示程序,而公開他們的移植方法和過程,這裡我把我的移植過程寫寫,希望對各位有幫助。
我們採用的是思創嵌入式開發網研發的 S3C44B0 黃金開發板及其液晶顯示模塊。
我的移植分兩個大部分來做的:
一是液晶的正確初始化
二是 UCGUI 移植
原本應該包括觸控屏的移植 可是因為 IAR 下的中斷一直沒有調通 就沒有做觸控屏的移植。
我的液晶是 320X240 16 灰度的,跟 S3C44B0的連接方式是 4 位單掃描 。
一 液晶的正確初始化
液晶的初始化可以參照下面的函數 最後得到顯示緩衝區數組跟視窗屏幕的對應關係如下
事實上液晶的正確初始化就是需要明確顯示緩衝區跟視窗屏幕的對應關係,了達到這個目的,可是通過單步調試逐個顯示點來觀察這種對應關係,在上圖中那就是這樣一個順序 。
Bmp[0]=0xF000;//點 0
Bmp[0]=0xFF00;//點 0 1
Bmp[0]=0xFFF0;//點 0 1 2
Bmp[0]=0xFFFF;//點 0 1 2 3
單步執行,查看液晶屏上顯示點的位置,這樣就可以確定對應關係了。
這S3C44B0中的液晶控制寄存器中有 BSWP 這個設置位,它是用於調整每 4 個位元組的位元組順序的,也是通過單步調試來明確這種對應關係的 .
#define SCR_XSIZE (320)//視窗屏幕大小
#define SCR_YSIZE (240)
#define LCD_XSIZE (320)//液晶屏幕大小
#define LCD_YSIZE (240)
#define MVAL_USED (0)
#define MVAL (13)
#define INVCLK (0)
#define INVFRAME (0)
#define INVLINE (0)
#define CLKVAL_SL (8) //VCLK=MCLK/(CLKVAL*2) (CLKVAL >= 2)
#define M5D(n) ((n) & 0x1fffff)
#define ARRAY_SIZE_G16 (SCR_XSIZE*SCR_YSIZE)
unsigned short Bmp[ARRAY_SIZE_G16/2];//液晶顯示緩衝數組
#define CLKVAL_G16 (10) //40Mhz, CLKVAL=10 ->101Hz
#define HOZVAL (LCD_XSIZE/4-1)
#define LINEVAL (LCD_YSIZE-1)
#define MVAL (13)
#define BSWP (1)//這個決定了每 4 個位元組的順序是否進行交換
#define MODESEL (2)//Gray 16
void LcdInit(void)
{
//The following value has to be changed for better display.
rDITHMODE=0x12210;
//rDITHMODE=0x0;
rDP1_2 =0xa5a5;
rDP4_7 =0xba5da65;
rDP3_5 =0xa5a5f;
rDP2_3 =0xd6b;
rDP5_7 =0xeb7b5ed;
rDP3_4 =0x7dbe;
rDP4_5 =0x7ebdf;
rDP6_7 =0x7fdfbfe;
rLCDCON1 = (0)|(1<<5)|(MVAL_USED<<7)|(0x3<<8)|(0x3<<10)|(CLKVAL_G16<<12);
// disable,4B_SNGL_SCAN,WDLY=8clk,WLH=8clk,
rLCDCON2 = (LINEVAL)|(HOZVAL<<10)|(10<<21);
//LINEBLANK=10 (without any calculation)
rLCDSADDR1 = (MODESEL<<27) | ( ((uint)Bmp>>22)<<21 ) | M5D((uint)Bmp>>1);
// 16-gray, LCDBANK, LCDBASEU
rLCDSADDR2 = (BSWP<<29)|M5D((((uint)Bmp+(SCR_XSIZE*LCD_YSIZE/2))>>1))|(MVAL<<21);
rLCDSADDR3 = (LCD_XSIZE/4) | ( ((SCR_XSIZE-LCD_XSIZE)/4)<<9 );
rLCDCON1 = (1)|(1<<5)|(MVAL_USED<<7)|(0x3<<8)|(0x3<<10)|(CLKVAL_G16<<12);
}
二 UCGUI 的移植
移植的思路是使用 UCGUI 支持的 buffer 型的 LCD控制器 EPSON 1375、我想就是這樣一個使用雙口 RAM的 LCD
控制器吧 因為我注意到 UCGUI 的代碼中 若是使用 1375 控制器時 需要定義四個讀寫函數
#define LCD_READ_MEM(Off) *((U16*) (0xc00000+(((U32)(Off))<<1)))
#define LCD_WRITE_MEM(Off,data) *((U16*) (0xc00000+(((U32)(Off))<<1)))=data
#define LCD_READ_REG(Off) *((volatile U16*)(0xc1ffe0+(((U16)(Off))<<1)))
#define LCD_WRITE_REG(Off,data) *((volatile U16*)(0xc1ffe0+(((U16)(Off))<<1)))=data
前兩個是讀寫內存的定義
后兩個是讀寫寄存器的定義
注意到常數 0xc00000 和 0xc1ffe0 沒有
0xc00000 是 1375 控制器的顯示緩衝區開始地址(Base Address)
0xc1ffe0 是 1375 控制器的寄存器開始地址(Base Address)
讀寫顯示緩衝區就是根據地址偏移 off 和開始地址 0xc00000 來讀寫 Buffer 的
讀寫控制寄存器就是根據地址偏移 off 和開始地址 0xc1ffe0 來讀寫 Buffer 的
我想可以使用欺騙的一招 我們把我們液晶的顯示緩衝區的開始地址(Bmp[0])告訴這幾個函數,那麼就可以了,而讀寫寄存器的兩個函數我們就不用了。
等我移植完畢,我發現網路上的其它移植版本也是如此使用了1375控制器的了,不信看看他們提供的演示,DOME
顯示的液晶控制器是不是 EPSON 13705 。
在 LCD.H中定義數據類型
#define I8 signed char
#define U8 unsigned char /* unsigned 8 bits. */
#define I16 signed short /* signed 16 bits. */
#define U16 unsigned short /* unsigned 16 bits. */
#define I32 signed long /* signed 32 bits. */
#define U32 unsigned long /* unsigned 32 bits. */
#define I16P I16 /* signed 16 bits OR MORE ! */
#define U16P U16 /* unsigned 16 bits OR MORE ! */
在 LCDConf.H中定義
#define LCD_XSIZE (320) /* X-resolution of LCD, Logical coor. */
#define LCD_YSIZE (240) /* Y-resolution of LCD, Logical coor. */
#define LCD_BITSPERPIXEL (4) //16灰度
#define LCD_CONTROLLER 1375
extern unsigned short Bmp[]; //引入顯示緩衝區數組
#define LCD_READ_MEM(Off) *((U16*) (Bmp+(((U32)(Off)))))
#define LCD_WRITE_MEM(Off,data) *((U16*) (Bmp+(((U32)(Off)))))=data
//#define LCD_READ_REG(Off) //這個函數可以不用定義 反正我們沒有用到
#define LCD_WRITE_REG(Off,data) //有些地方用到了 定義為空 避免做大改動
#define LCD_SWAP_BYTE_ORDER (1) //這個是做位元組轉換的
在 LCD13XX.C中定義液晶匯流排寬度
#ifndef LCD_BUSWIDTH
#define LCD_BUSWIDTH (16)
#endif
這裡提及關鍵對應部分
->定義顯示緩衝區時使用的short數據類型,它是16bit的:
unsigned short Bmp[ARRAY_SIZE_G16/2];//液晶顯示緩衝數組
->定義讀寫緩衝區時使用的數據類型,也是16bit的U16:
#define LCD_READ_MEM(Off) *((U16*) (Bmp+(((U32)(Off)))))
#define LCD_WRITE_MEM(Off,data) *((U16*) (Bmp+(((U32)(Off)))))=data
//#define LCD_READ_REG(Off) //這個函數可以不用定義 反正我們沒有用到
#define LCD_WRITE_REG(Off,data) //有些地方用到了 定義為空 避免做大改動
->定義液晶匯流排寬度 定義位 16bit 的
#ifndef LCD_BUSWIDTH
#define LCD_BUSWIDTH (16)
#endif
->定義位元組順序
#define LCD_SWAP_BYTE_ORDER (1) //16bit時需要交換的
讀者已經能看到了對應關係了 都是使用16bit的數據類型 這是關鍵 別用錯了
由此延伸 若是把這些對應關係換成8bit的數據類型 如下
->定義顯示緩衝區時使用的char數據類型,它是8bit的:
unsigned char Bmp[ARRAY_SIZE_G16];//液晶顯示緩衝數組
->定義讀寫緩衝區時使用的數據類型,也是8bit的U8:
#define LCD_READ_MEM(Off) *((U8*) (Bmp+(((U32)(Off)))))
#define LCD_WRITE_MEM(Off,data) *((U8*) (Bmp+(((U32)(Off)))))=data
//#define LCD_READ_REG(Off) //這個函數可以不用定義 反正我們沒有用到
#define LCD_WRITE_REG(Off,data) //有些地方用到了 定義為空 避免做大改動
->定義液晶匯流排寬度 定義位 8bit 的
#ifndef LCD_BUSWIDTH
#define LCD_BUSWIDTH (8)
#endif
->定義位元組順序
#define LCD_SWAP_BYTE_ORDER (0) //8bit時不需要交換的
這樣的對應關係也是可行的,我測試過,不過若是你想把它換成32bit的話就不行了,因為UCGUI不支持32bit的液晶匯流排寬度的。
以上兩部分是整個移植工作的關鍵,當然還有一些繁瑣的事情,請閱讀UCGUI的手冊中Getting Started一章。在IAR下移植時 需要建立group 對照文件夾加入UCGUI代碼。
需要說明的是
除了LCDDriver下只加入LCD13XX.C 在Config下額外加入GUI_X.C外其餘的都是加入相應文件夾中的所有C文件
我還額外加入了跟開發板有關的文件:
LCDLIB.C(液晶的初始化函數LcdInit())
Platform.C(板級初始化函數 它會調用LcdInit()來初始化液晶控制器)
設置include路徑:
我加入的include路徑為
D:\Program Files\IAR Systems\UCGUI\gui\core\
D:\Program Files\IAR Systems\UCGUI\Config\
D:\Program Files\IAR Systems\UCGUI\gui\WM\
D:\Program Files\IAR Systems\UCGUI\gui\Widget\
D:\Program Files\IAR Systems\UCGUI\Sample\GUIDemo\
在GUIConf.H中定義
#define GUI_OS (0) /* Compile with multitasking support */
#define GUI_WINSUPPORT (1) /* Use window manager if true (1) */
#define GUI_SUPPORT_MEMDEV (1) /* Support memory devices */
#define GUI_SUPPORT_TOUCH (0) /* Support a touch screen (req. win-manager) */
#define GUI_SUPPORT_UNICODE (1) /* Support mixed ASCII/UNICODE strings */
我們還沒有移植到OS上 也沒有加入觸摸屏的支持
void GUI_X_Delay(int ms) {
// int tEnd = OS_TimeMS + ms;
// while ((tEnd - OS_TimeMS) > 0);
extern void Delay(int time);//我自己的延時函數
Delay(150*ms);
}
原因是在UCGUI的應用中有一些函數是跟時間相關的,UCGUI認為使用的是UCOS UCOS會維護時間OS_TimeMS;這裡我調用我自己的延遲程序來實現延遲,事實上正是因為有一些函數跟時間有關,因此在UCGUI提供的演示程序中就出現了問題,例如在GUIDEMO_Speed.C中有這麼個循環:
for (i = 0; (((t + 8000) - (int)GUI_GetTime()) > 0) && !GUIDEMO_CheckCancel(); i++) {
}
它調用了GUI_GetTime讀取當前系統時間來控制循環,若是系統沒有維護時間OS_TimeMS 那就會出問題了,我的簡單解決方法是改為
for (i = 0;i<0xFFF;i++){
}
在其它的GUIDEMO_XXXX.C中也有這樣一些循環 你要是調試是發現液晶屏上的顯示一直停在一個畫面上很久的話,估計就是碰上了上面的問題 。
好了,加入那個最簡單的主函數 Basic_Helloworld.C
void BoardInit (void);
void main(void) {
/*
ToDo: Make sure hardware is initilized first!!
*/
BoardInit ();//板級初始化 它調用了LcdInit()
GUI_Init();
GUI_DispString("Hello world!");
while(1);
}
應該能在你的液晶屏上看到UCGUI跟你打招呼的了 "Hello world!" 。
這樣UCGUI的移植基本上已經完成了,當然了這裡只提供了移植關鍵的部分,更多的、更完整的移植還需要做不少的工作,如觸控屏的移植,鍵盤、滑鼠的移植,中文字體的移植,UCGUI支持UNICODE 中文字體不成大問題的。
[admin via 研發互助社區 ] UCGUI在S3C44B0上的移植已經有1750次圍觀
http://cocdig.com/docs/show-post-42797.html