程克非,付學恕,涂 剛
(1.重慶郵電大學 計算機學院,重慶400065;2.華中科技大學 計算機學院,湖北 武漢430074)
微軟的 Microsoft Visual Studio 2005和Platform Builder開發工具使得開發和定制 WinCE 6.0變得簡單而且功能強大。由于WinCE 6.0具有可定制、多平臺、實時性、網絡功能、多媒體和多語言等諸多優點,其應用極為廣泛[1]。在嵌入式操作系統中Bootloader是系統上電后首先執行的代碼,對于原生WinCE 6.0系統來說,從打開電源到系統完全啟動期間,LCD(液晶顯示屏)沒有任何視頻或圖像輸出,導致其用戶體驗有所欠缺。而此前的研究成果基本可以分為兩類:一類是在開機時顯示單一色彩的圖片或一些字符,使開機界面不夠美觀;另一類則是直接采用一個超大數組存放圖片數據而使得移植困難。本文正是基于以上原因,在認真分析和研究了以前的成果基礎上,通過對WinCE 6.0的Bootloader代碼進行分析和設計,將符合LCD分辨率的開機Logo數據直接固化在Flash上并在Bootloader啟動時讀出,使得系統開機后馬上就有漂亮的彩色圖像輸出,同時更換Logo也變得簡單方便,從而滿足用戶對嵌入式產品要求的友好界面及美觀性。基于該方法實現的WinCE 6.0系統的手持式第二代居民身份證閱讀器使用的顯示屏是信利(Truly)半導體有限公司的4.8英寸分辨率為800×480的TFT LCD。
Bootloader是用來管理目標設備啟動過程的特定程序,是在操作系統內核加載之前設備首先運行的一小段程序[2]。其主要工作包括設備硬件平臺的初始化,內存地址空間映射的建立,以及從非易失存儲器(Nand Flash或 Nor Flash,本文中設備采用的是Nand Flash)上或者網絡上加載操作系統映像文件并引導運行等。
UBoot(universal Bootloader): 它 起 源 于 開 源 項 目PPCBoot,后來ARMBoot也合并進來,再加入其他一些Bootloader,于是 UBoot誕生了[3]。2002年12月17日UBoot 0.2.0發布,它是UBoot的第一個發布版本。從那以后,UBoot又陸續修改和更新了6次之多。從2008年8月后,UBoot采用日期作為版本號。截至目前為止,最新版本號為 UBoot-2011.06。UBoot的支持是不間斷的。UBoot有引導啟動(Bootloading)模式和下載運行(downloading)模式,并具有大型Bootloader所應該具備的所有功能。它是GPL(general public license)下資源代碼最完整的一個通用Bootloader。UBoot支持的處理器架構包括PowerPC,ARM,MIPS和X86等。UBoot支持大量的外設驅動,支持多種不同的文件系統,還附帶有腳本和調試等工具,專門針對Linux的支持做了優化,并特別為板級移植做了很多的支持。其主要特性為:以太網支持,IP/MAC預置功能,在線讀寫Flash,支持串口下載代碼,識別二進制及其它格式的內核,監控命令集,支持看門狗(WatchDog)時鐘,支持LCD顯示Logo等。
Redboot:它是Redhat公司的一個開源項目,是伴隨ECOS發布的一個獨立運行在嵌入式系統上的Bootloader方案[4]。Redboot廣泛支持各種處理器架構,諸如:Power-PC、MIPS、ARM和X86等,功能非常完善。Redboot采用了ECOS的硬件抽象層并以此為基礎,繼承了ECOS的簡潔和穩定可靠的優點,同時又可以靈活的配置。它不僅支持Ymodem或者Xmodem協議通過串口下載映像,也支持以太網口使用TFTP的方式下載映像文件,常用于系統初始化、引導內核映像和調試支持。Redboot自啟動后,會提供一個可交互的命令行,用來管理本地映像,映像下載和運行,Bootloader配置以及其它各種外部硬件設備等。Redboot的引導腳本文件保存在本地Flash上,主要用作從TFTP服務器端或本地Flash下載系統映像并將其加載運行。
Blob(boot loader object):它是由Jan-Derk Bakker and Erick Mouw發布的,是專門針對StrongARM構架下的LART(Linux advanced radio terminal)設計的一個 Bootloader[5]。Blob提供兩種工作模式,在啟動時處于引導加載模式,但是它有10s的等待時間,當用戶按下任意鍵,則Blob立刻切換到下載運行模式。如果10s內沒有按鍵響應,則Blob啟動并加載儲存在本地的Linux內核。Blob主要是通過串口跟主機通信,速度慢而且效率低下,同時其支持的CPU結構也很有限。Blob最新的版本是Blob 2.0.5。
VIVI:它是由韓國mizi公司開發設計的一個專門針對ARM 9嵌入式處理器的Bootloader。與其它的Bootloader相比VIVI具有容易理解,易于移植等優點[6]。VIVI也具有兩種工作模式:引導啟動模式和下載運行模式。引導啟動模式是VIVI的默認工作模式,它可在一段用戶自定義的時間流逝后自行引導和啟動Linux內核。在非默認的下載運行模式下,VIVI會為用戶提供一個電腦終端命令行接口,通過該接口可以利用主機的串口來使用VIVI提供的操作命令和VIVI進行通信。
一個典型的WinCE 6.0系統的啟動流程如圖1所示。
圖1 WinCE 6.0系統啟動流程
采用分級Bootloader(NBoot和EBoot)設計,可以方便代碼維護和修改,并且將核心硬件和外圍硬件初始化分開完成,提高了代碼執行效率和復用率,同時使得代碼便于移植[7]。所以本文中的第二代居民身份證閱讀器就是采用 NBoot(Nand Flash Bootloader) 和 EBoot(Ethernet Bootloader)的兩級Bootloader模式。
1.2.1 NBoot分析
NBoot位于 Nand Flash的block 0(每block大小為1MB)上,通過Platform Builder編譯為block0.nb0映像文件[8]。該文件固定大小為72KB。系統上電時首先即自動加載 Nand Flash的block 0上的前4KB代碼[9],它是 NBoot的匯編初始化代碼。匯編代碼完成最基本的硬件初始化之后,就跳轉到C語言入口開始執行后續代碼[10],后續代碼所完成的主要工作就是將EBoot從Nand Flash的block 3上拷貝到RAM(內存)并加載運行。整個NBoot的主要執行流程如圖2所示。
圖2 NBoot執行流程
1.2.2 EBoot分析
EBoot位于 Nand Flash的block 3上。大小控制在512KB以內(本設備為391KB)。EBoot主要由Blcommon、OEM代碼和網絡驅動等組成[11]。它有兩種工作模式:燒寫模式完成將Bootloader自身和內核映像(NK.bin)固化到Nand Flash的指定block上;下載模式完成將內核映像從Nand Flash下載到RAM指定地址處加載運行。
本設計主要利用EBoot的main()函數中包含的BootloaderMain()函數實現。在BootloaderMain()中調用了OEMPlatformInit()函數來完成硬件平臺的初始化過程,包括LCD的初始化。本文中實現開機Logo的功能即是在這兩個函數中添加C語言代碼實現的。首先通過EBoot的燒寫模式將Logo下載到Nand Flash的指定block中,然后開機時再通過EBoot的下載模式將Logo從Nand Flash讀到RAM中的LCD緩沖區顯示。EBoot簡化后的執行流程如圖3所示。
圖3 EBoot執行流程
由于Bootloader執行效率和硬件關聯度高,并且開機Logo的顯示相對于普通的視頻輸出從實現方式和顯示內容并不完全一樣[12]。所以在Bootloader中添加的實現開機Logo的代碼要相對簡單且執行效率高,同時必須和底層的硬件以及LCD密切相關。
本文中的設備上使用的LCD是信利(truly)半導體公司生產的型號為 TFT800480-30-E 4.8英寸 TFT LCD,分辨率為800×480,32位色彩顯示[13]。硬件核心采用的是三星電子(samsung electronics)的 ARM11架構的S3C6410嵌入式處理器,主頻為667MHz。S3C6410的顯示控制器時序如圖4所示[14]。
圖4 LCD RGB接口時序
在 WinCE 6.0自帶的 Bootloader中并沒有初始化S3C6410的LCD控制器的代碼,LCD的初始化發生在內核的加載啟動之后。所以在Bootloader運行的這段時間內,LCD上沒有任何視頻輸出。因此為了產品的美觀性和交互性,本設備在Bootloader中添加了實現開機Logo的代碼,使得系統一啟動就有視頻圖像輸出并顯示系統開機進度條,Logo包含有公司的信息和圖標等。其中Logo是BMP(位圖)格式的圖片,分辨率為800×480,其顏色位值為24,大小固定為1152054字節。通過Bootloader燒寫到Nand Flash的block 5和block 6上,并在系統啟動后由Bootloader讀取位圖數據,然后將數據直接拷貝到RAM的LCD輸出緩沖區中,LCD就會原樣顯示出Logo。Logo在Nand Flash上的存儲位置如圖5所示。
圖5 Logo存儲分布
實現開機顯示Logo的具體過程如下:
(1)從SD卡中讀取Logo數據到RAM:在Bootloader的燒寫工作模式下,添加從SD卡讀取Logo的C語言代碼,在BootloaderMain()函數中添加如下函數:
LogoReadFromSD();從SD卡中讀取Logo信息,包括Logo存放的起始地址和長度等。其主要代碼如下:
這兩段代碼分別指明了Logo將要讀取到RAM中的地址值和對Logo數據進行分析和處理,為讀取SD卡中的Logo到RAM做準備。
DownloadImage(DWORD dwImageStart, DWORD dwImageLength,DWORD dwLaunchAddr);這3個入口參數分別是映像存儲起始地址,映像長度和映像加載地址。主要功能是從SD卡下載Logo數據到RAM。它會調用它所 包 含 的 OEMReadData(DWORD dwData,PUCHAR pData)函數來完成具體的Logo數據下載工作,其中2個入口參數分別指:映像數據長度和映像存儲緩沖區。
(2)將RAM中的Logo燒寫到 Nand Flash:這是在Bootloader燒寫工作模式下實現整個開機Logo設計與顯示過程中最關鍵的一部分,主要由 WinCE 6.0自帶的底層Flash訪問函數完成。該函數具有便于移植,代碼復用率高和執行效率高的優點,并且可以不加修改直接運用于其它基于 WinCE 6.0的嵌入式設備上。
OEMLaunch(DWORD dwImageStart,DWORD dwImage-Length,DWORD dwLaunchAddr,const ROMHDR *pRomHdr);這4個入口參數分別是映像存儲起始地址,映像長度,映像加載地址和TOC分區標識符。主要功能是將下載到RAM中的Logo燒寫到Nand Flash的指定block上。
OEMLaunch()調用 WriteRawImageToBootMedia
(DWORD dwImageStart,DWORD dwImageLength,DWORD dwLaunchAddr)函數完成具體燒寫過程。其入口參數分別指:映像存儲起始地址,映像長度和映像加載地址。其主要功能就是執行下面的底層Flash訪問函數代碼:
dwBlock=LOGO_BLOCK;指定了Logo將要燒寫到的Nand Flash起始block數。
pLowFuncTbl=FIL_GetFuncTbl();直接訪問底層Nand Flash的函數,可以直接對Nand Flash進行訪問和修改等操作,其中最重要3個底層操作如下:
pLowFuncTbl-> Read(UINT32nBank, UINT32 nPpn, UINT32nSctBitmap, UINT32nPlaneBitmap,UINT8 *pDBuf,UINT8 *pSBuf,BOOL32bECCIn,BOOL32bCleanCheck);直接讀Nand Flash數據。其參數分別指:block數,Nand Flash頁數,扇區映射位,Nand Flash平面映射位,目標數據緩沖區,源數據緩沖區,ECC校驗碼標識位和Nand Flash數據清除標識位。
pLowFuncTbl->Write(UINT32nBank,UINT32nPpn,UINT32nSctBitmap,UINT32nPlaneBitmap,UINT8*pDBuf,UINT8*pSBuf);直接寫Nand Flash數據。其參數分別指:block數,Nand Flash頁數,扇區映射位,Nand Flash平面映射位,目標數據緩沖區和源數據緩沖區。
pLowFuncTbl-> Erase(UINT32nBank, UINT32 nPbn,UINT32nPlaneBitmap);直接擦除Nand Flash數據。其參數分別指:block數,Nand Flash頁數和Nand Flash平面映射位。
(3)設置 LCD寄存器[15]:
設置LCD主要在Bootloader的下載模式中完成。首先在OEMPlatformInit()函數中調用LCD初始化函數InitializeDisplay()來設置CPU的控制LCD輸出的GPIO口:
然后在InitializeDisplay()中實現重要函數:LDI_fill_output_device_information(void*pDevInfo);其參數指針指向一個系統定義的視頻設備信息結構體。該函數功能為:初始化LCD設備基本信息,像素時鐘采樣頻率33.33MHz,位數模式24BPP,輸出圖像格式8:8:8,像素點時鐘下降沿采樣,幀率為60,水平、垂直同步信號低電平有效。在該函數中還要設置如下重要參數:
以上代碼分別指:幀后、幀前等待計數分別為31、1個行時鐘,垂直脈沖寬度為2個行時鐘,行后、行前等待計數分別為86、1個像素點時鐘,水平同步時鐘寬度為128個像素點時鐘。
(4)將Logo數據拷貝到RAM的LCD輸出緩沖區:
將Logo從Nand Flash拷貝到RAM中,主要是靠在下載模式下通過OEMPlatformInit()中添加的如下3個函數完成的:
ShadowLogo()函數主要將Logo數據從Nand Flash對應block讀取到RAM指定地址中。其中包含如下重要代碼:
pBuffer=(UINT8*)EBOOT_BINFS_BUFFER_UA_START;指向Logo在RAM中的儲存起始地址,這是一個通過 MMU(Memory Management Unit)映射后的虛擬地址。
dwStartBlock=LOGO_START_BLOCK;指向Logo在Nand Flash存儲的起始block。
dwNumBlock=LOGO_BLOCK_SIZE;指向Logo在Nand Flash上所占據的block數。
CopyLogoPicSeg(S32xPos,S32yPos,S32nWidth,S32nHight,PU08pBuf);其各個參數分別指:Logo在LCD屏幕上開始顯示的橫坐標和縱坐標,二維圖像數組寬和高,以及Logo在RAM的起始地址值。其中包含如下重要參數設置:
U32*tmp=EBOOT_FRAMEBUFFER_UA_START;指向RAM中的LCD輸出緩沖區,這也是一個經過MMU映射的虛擬地址,Logo數據信息將被拷貝至此地址處,然后在LCD上完整的顯示出來。
顯示內核加載進度的進度條也是顯示Logo的一部分,該功能主要由函數progress_draw_v(int_top_left,int_top_right,int _width,int _heigth,int _color)完成,其入口參數分別指:進度條位于LCD的橫坐標和縱坐標,LCD屏幕寬度和高度,以及進度條的顏色。
(5)顯示示例Logo:
打開Platform Builder編譯生成本項目下的BSP(board support package)包,會得到EBoot.bin和EBoot.nb0兩個Bootloader映像文件。將EBoot.bin燒寫到本設備的Nand Flash的block 3上,啟動設備,即可看到如圖6所示示例Logo及位于LCD下方的開機進度條。
圖6 開機Logo
本文通過對WinCE 6.0的Bootloader啟動流程進行分析,針對實際的硬件平臺,完成了基于 WinCE 6.0系統和三星S3C6410硬件平臺的開機Logo的設計與實現。對比其它類似設計與實現不能快速準確顯示彩色圖片,不易于移植以及不能隨意且方便的更換Logo的局限性,本文中的設計與實現代碼簡潔高效,方便移植,Logo可以隨意更換,而且代碼可以不加修改而直接運用于其它基于 WinCE 6.0系統的嵌入式設備上。經過反復測試,該設計與實現可以準確快速的將Logo原樣顯示在LCD上。本文中的第二代居民身份證閱讀器正是采用了上述設計實現了開機顯示Logo的功能,該設備已進入量產和實際應用階段。
[1]HE Zongjian.Windows CE embedded system [M].Beijing:Beihang University Press,2006:7-10(in Chinese).[何宗健.Windows CE嵌入式系統 [M].北京:北京航空航天大學出版社,2006:7-10.]
[2]ZHANG Dongquan,TAN Nanlin.Windows CE practical development technology [M].Beijing:Publishing House of Electronics Industry,2006(in Chinese).[張東泉,譚南林.Windows CE實用開發技術 [M].北京:電子工業出版社,2006.]
[3]YANG Fumin,WANG Pengyu,TU Gnag.Design and implementation of BSP in the embedded Linux [J].Computer Engineering and Science,2005(in Chinese). [陽富民,王朋羽,涂剛.嵌入式Linux系統BSP的設計與實現 [J].計算機工程與科學,2005,27(1):64-66.]
[4]ZHENG Kelong.Design and application of RedBoot based ARM-Linux embedded system [D].Xi'an:Xidian University Library,2009(in Chinese).[鄭克龍.基于 ARM-Linux嵌入式系統RedBoot的設計與應用 [D].西安:西安電子科技大學圖書館,2009.]
[5]Startup code analyze of BLOB and research of Bootloader porting[D]. Wuhan: Wuhan University of Science and Technology Library,2010(in Chinese). [李 昂.基 于 S3C44BOX 的Bootloader-BLOB移植研究 [D].武漢:武漢科技大學圖書館,2010.]
[6]KU Shaoping,TIAN Yunfang.Analysis &improvement of VIVI BootLoader based on Nand Flash [J].Control and Automation Publication Group,2009,26(8):76-78(in Chinese).[庫少平,田云芳.基于Nand Flash的VIVI裝載器的分析于改進 [J].微計算機信息,2009,26(8):76-78.]
[7] WANG Yagang.Analysis and transplant of embedded Boot-Loader mechanism [J].Computer Engineering,2010,36(6):267-269(in Chinese). [王亞剛.嵌入式 Bootloader機制分析與移植 [J].計算機工程,2010,36(6):267-269.]
[8]Platform builder for microsoft Windows CE 6.0help [Z].Microsoft Corporation,2006.
[9]QI Yun,ZHANG Yongrui.Design and implementation of Boot-Loader based on PXA255processor in WinCE [J].Electronic Science and Technology,2005,(10):58-61(in Chinese).[齊云,張永瑞.PXA255處理器在 WinCE系統下的Boot-Loader設計與實現 [J].電子科技,2005,(10):58-61.]
[10]ZHANG Fei,BAI Ruilin,LU Lin.Design and implementation of WinCE 5.0Bootloader [J].Computer Engineering,2009(in Chinese).[張飛,白瑞林,陸林.WinCE 5.0Bootloader的設計與實現 [J].計算機工程,2009,35(7):232-234.]
[11]GONG Nan,CAO Ling,GAO Zhiying.Design and development of Windows CE 5.0Boot Loader based on Sansung S3C2440Aprocessor [J].Journal of Xi'an Institute of Posts and Telecommunications,2008,13(5):45-47(in Chinese).[弓楠,曹凌,高志英.基于Sansung S3C2440A處理器 Windows CE 5.0Boot Loader的設計與開發 [J].西安郵電學院學報,2008,13(5):45-47.]
[12]ZHANG Zhi,JIANG Zhilong.Implementation of Boot Logo in Bootloader based on Windows CE and S3C2410 [J].Electronic Measurement Technology,2010,33(2):87-90(in Chinese).[張智,江志農.基于S3C2410和Windows CE的Bootloader啟動圖片的實現 [J].電子測量技術,2010,33(2):87-90.]
[13]TFT800480-30-E Specification [Z]. Truly Semiconductors LTD,2009.
[14]S3C6410XUser's Manual [Z].Samsung Electronics,2009.
[15]ZHANG Genbao,YANG Feng,TIAN Ze,et al.Development of Eboot Based on Windows CE.NET [J].Measurement and Control Technology,2007,26(7):53-55(in Chinese).[張根寶,楊峰,田澤,等.Windows CE.NET系統下Eboot開發 [J].測控技術,2007,26(7):53-55.]