uc/guinios II上的移植


uc/gui是一個優秀的嵌入式圖形用戶界面,這幾天的工作就是將它移植到nios II系統上。前人也做了一些工作,不過大部分都是針對其他硬核處理器,針對nios II軟核處理器的移植資料那簡直是鳳毛麟角。在閱讀了相關文檔後,我決定自己親自動手實踐,這下面的很多過程都是自己摸索出來的,並透過了實驗的驗証。這只是一個初步的移植,也許在以後的更複雜的應用中,還需要對其進行調整。但對目前我的應用而言,應該足夠了。


寫這篇文章的目的一是由於自己記性不好,所以需要給自己留個備忘,免得以後忘的一干二淨;二是給有需要的朋友提供一些參考,也好相互交流,共同進步。請大家多提寶貴意見。


一、源碼和文檔下載


http://www.ucgui.com/上有很多不同版本的源碼下載,目前能下到的最新版本是3.98,不過還有一些組件不是很完整,但作基礎開發已經夠用了。


ucgui3.98源碼下載位址︰uC-GUI-V3-98.zip


ucgui最新版用戶手冊下載位址︰uC-GUI-user.rar


開發軟體︰quartus II 6.0, Nios II IDE 6.0


二、移植過程


先來看看解壓後都有些什麼東西︰




如圖,核心的東西包括ConfigGUI兩個檔案夾,這裡面是ucgui的所有源碼和配置檔案。ConvertColor包含彩色轉換函數,ConvertMono包含灰度到彩色轉換的函數,Core包含核心程式,Font是字體檔案,LCDDriver包含多種控制單元驅動,Widget是視窗控件庫,WM是視窗庫,提供複雜的功能。其他檔案夾包含一些應用範例以及一些有用的工具,留待慢慢探索。


1config檔案的移植︰


Config檔案夾是ucgui的配置檔案夾,裡面有3個檔案︰


GUIConf.hgui的基本屬性配置檔案,有很多開關可以配置,具體可以參考ucgui的用戶手冊,這裡只需配置幾個必要的參數如下︰


#ifndefGUICONF_H


#define GUICONF_H


#define GUI_OS (1) /* 支援作業系統,nios系統自帶了ucosII,所以我們選擇此項,使gui支援該作業系統*/


#define GUI_SUPPORT_TOUCH (0) /* 支援觸摸屏,由於暫時沒有用觸摸屏,所以關掉這個開關*/


#define GUI_SUPPORT_MOUSE (0) /* 支援滑鼠,暫時關閉 */


#define GUI_SUPPORT_UNICODE (1) /* Unicode字元串支援*/


#define GUI_DEFAULT_FONT GUI_Font6x8/* 預設字體*/


#define GUI_ALLOC_SIZE 12500/* WMmemery device分發的內存*/


#define GUI_WINSUPPORT 1 /* Window manager available */


#define GUI_SUPPORT_MEMDEV 0 /* Memory devices available,由於下載到的源代碼中缺少memery device組件的源碼,所以關閉此項 */


#define GUI_SUPPORT_AA 1 /* Anti aliasing available */


#endif /* Avoid multiple inclusion */


LCDConf.hLCD控制單元的硬體配置檔案,這個檔案與硬體直接相關,一般是根據你所使用的LCD的類型和所用的LCD控制單元的類型來配置。我的配置是一塊640*480TFT LCD,支援18位色,不過我只使用16位,RGB565色彩模式,足矣。LCD控制單元就是自己寫的一個硬體模塊,掛在avalon匯流排上,負責讀取顯示緩沖區中的數據,然後按照該LCD的時序輸出顯示到LCD上。顯示緩沖區直接開辟在系統內存中,系統使用一塊SDRAM作為系統內存,CPU可以直接對其進行32位讀寫訪問。透過仔細閱讀ucgui的用戶手冊,可以知道,在我這種硬體配置條件下,可以選擇LCDLin32.c這個驅動檔案(後面將詳細講述對LCDLin32.c的修改與移植),那麼對應了LCD_CONTROLLER 必須配置為3200



#ifndef LCDCONF_H


#define LCDCONF_H


#define LCD_XSIZE (640) /* X-resolution of LCD, Logical coor. */


#define LCD_YSIZE (480) /* Y-resolution of LCD, Logical coor. */


#define LCD_BITSPERPIXEL (16) /* 每個象素點需要的Bit */


#define LCD_CONTROLLER 3200 /* 控制單元名稱 */


#define LCD_ENDIAN_BIG 0 /* 選擇little endian */


#define LCD_FIXEDPALETTE 565 /* 選擇RGB565色彩模式 */


#define LCD_SWAP_RB 1 /* gui預設為GRB565,定義這個開關可以使之轉換為RGB565,即交換RB */


//#define LCD_VRAM_ADR 0x20000000 /* 顯示緩沖區起始位址,這個宏定義定義了顯示緩沖區的位址,在驅動檔案LCDLin32.c中要用到這個位址。由於我的顯示緩沖區要在程式營運起來之後,由malloc函數在系統內存中分發,所以這個位址無法預先定義。於是我取消了這個宏定義,而改為一個指標變量,直接放在LCDLin32.c中,透過修改其中的一些函數定義,完全可以實現這樣的改變。 */


//#define LCD_READ_MEM(Off) IORD_32DIRECT((U32 *)LCD_VRAM_ADR + ((U32)Off) << 2),0)


//#define LCD_WRITE_MEM(Off,data) IOWR_32DIRECT((U32 *)LCD_VRAM_ADR + ((U32)Off) << 2),0,Data)


/* 使用驅動LCDLin32.c需要定義的函數,用於讀寫顯示緩沖區,由於把顯示緩沖區的位址指標放到LCDLin32.c中去了,所以這兩個函數也直接放到LCDLin32.c中去,在這裡就可以不要了 */


#define LCD_INIT_CONTROLLER() LCD_Controller_Init()/* LCD 控制單元初始化函數,由gui_init()調用,我在這裡替換為自己的控制單元初始化函數LCD_Controller_Init(),該函數在後文中敘述 */


#endif/* LCDCONF_H */


GUITouchConf.h︰觸摸屏的配置檔案,暫時沒有使用。


至此,config檔案移植完畢。


2LCD device驅動的移植


這裡所說的LCD device驅動移植主要是指前面所說的LCDLin32.c檔案的修改。LCDLin32.cGUI/LCDDriver檔案夾中,其中定義了幾個關鍵的函數,用於gui對顯示緩沖區進行操作,如


void LCD_L0_SetPixelIndex(int x, int y, int PixelIndex)/* 畫點 */


unsignedint LCD_L0_GetPixelIndex(int x, int y)/* 讀點 */


void LCD_L0_XorPixel(int x, int y)/* 異或點 */


void LCD_L0_DrawHLine(int x0, int y, int x1) /* 畫水準線 */


void LCD_L0_DrawVLine(int x, int y0, int y1) /* 畫垂直線 */


void LCD_L0_FillRect(int x0, int y0, int x1, int y1) /* 矩陣填充 */


void LCD_L0_DrawBitmap(int x0, int y0,


int xsize, int ysize,


int BitsPerPixel,


int BytesPerLine,


const U8 GUI_UNI_PTR * pData, int Diff,


const LCD_PIXELINDEX* pTrans) /* 畫位圖 */


void LCD_On (void) /* 打開LCD */


void LCD_Off (void) /* 關閉LCD */


由於我的LCD不具備打開和關閉功能,所以LCD_On()LCD_Off()定義為空函數。在上述的幾個畫點畫線函數中,與硬體(顯示緩沖區)直接相關的就是


LCD_WRITE_MEM(Off,data)/*寫存儲器*/


LCD_READ_MEM /*讀存儲器*/


我們只需要將這兩個宏定義修改一下,使之指向我們自己定義的操作。由於這兩個函數是對顯示緩沖區進行讀寫操作,所以需要先知道顯示緩沖區的起始位址,在我的系統中該緩沖區由malloc函數得到,於是需要預先定義一個指標變量,用來存儲顯示緩沖區的首位址:


U32 *lcd_framebuffer0; /* our frame buffer first address */


但是預編譯無法處理malloc函數,所以我將這個操作放到自定義的LCD_Controller_Init()函數中執行。這裡使用了Nios系統中hal庫的一些函數,所以需要先包含相應的頭檔案︰


#include


#include


#include


#include


#include


#include"io.h"


#include"sys/alt_alarm.h"


#include"sys/alt_cache.h"


#include"system.h"


#include"priv/alt_file.h"


這其中實際上有幾個頭檔案是沒有必要包含進來的,不過我也沒去管它,所以就都寫在這裡了,應該不會有什麼害處。


#define LCD_BYTESPERFRAME LCD_XSIZE * LCD_YSIZE * LCD_BITSPERPIXEL / 8


void LCD_Controller_Init(void)


{


lcd_framebuffer0 = (U32 *)alt_uncached_malloc(LCD_BYTESPERFRAME);


memset( (void *)lcd_framebuffer0, 0x0, LCD_BYTESPERFRAME ) ; /* reset the frame buffer to 0x0 */


IOWR_32DIRECT( VGA_CONTROLLER_0_BASE, 0, 0x0 ); /* Reset the VGA controller */


IOWR_32DIRECT( VGA_CONTROLLER_0_BASE, 4, lcd_framebuffer0 ); /* Where our frame buffer starts */


IOWR_32DIRECT( VGA_CONTROLLER_0_BASE, 8, LCD_BYTESPERFRAME ); /* amount of memory needed */


IOWR_32DIRECT( VGA_CONTROLLER_0_BASE, 0, 0x1 ); /* Set the go bit. */


}


這個函數初始化了顯示緩沖區,並對LCD控制單元進行配置,使之正確營運。其中,VGA_CONTROLLER_0_BASELCD控制單元的基位址,由system.h檔案定義,所以要將它include進來。LCD_BYTESPERFRAME為每幀需要的位元組數。由宏定義得到。這樣,在系統調用GUI_Init()函數時,LCD_Controller_Init()函數也會被調用,這就可以保證gui在做任何操作以前,顯示緩沖區都已經準備好了,LCD控制單元也已經配置好並已經開始營運了。


實際上,LCDLin32.c檔案中對LCD_READ_MEMLCD_WRITE_MEM已經做了定義,有了lcd_framebuffer0這個指標變量之後,我們只需要對LCD_READ_MEMLCD_WRITE_MEM定義做一些修改,使之指向lcd_framebuffer0所指的緩沖區即可︰


#define LCD_READ_MEM(Off) (*((U32 *)lcd_framebuffer0 + ((U32)Off)))


#define LCD_WRITE_MEM(Off, Data) *((U32 *)lcd_framebuffer0 + ((U32)Off)) = Data


這樣,LCDLin32.c就基本上修改完畢了。當然,我們還可以修改其畫點,畫線,矩陣填充,畫位圖等函數,使之對於我們特定的硬體更加優化,以提升執行效率,這是後話。到目前為止,gui已經能夠正確地操作我們的硬體了。


三、營運第一個程式︰hello_gui


下面,我們就讓剛移植好的gui到實際的系統上去營運一下。


1、配置好FPGA的硬體;


2、打開nios II IDE,以hello_world工程為模版建立一個新的工程hello_gui


3、將ucguiConfigGUI兩個檔案夾(包含有我們剛剛修改過的幾個檔案)複製到工程目錄下;


4、在hello_gui工程選項中添加如下include paths


yourprojectdir/software/hello_gui/Config


yourprojectdir/software/hello_gui/GUI/Core


yourprojectdir/software/hello_gui/GUI/Widget


yourprojectdir/software/hello_gui/GUI/WM


5、修改hello_world.c的內容為︰


#include"GUI.H"


void main(void) {


GUI_Init(); /* 初始化GUI,同時初始化LCD控制單元和顯示緩沖區 */


GUI_SetBkColor(GUI_BLUE); /* 設定背景色為藍色*/


GUI_Clear(); /* 清屏為背景色 */


GUI_SetColor(GUI_RED); /*

arrow
arrow
    全站熱搜

    立你斯 發表在 痞客邦 留言(0) 人氣()