胡國晨
(西安石油大學(xué) 〈中船重工西安東儀科工集團(tuán)有限公司〉 陜西 西安 710000)
uC/OS-Ⅱ是一個(gè)嵌入式多任務(wù)實(shí)時(shí)操作系統(tǒng),是Jean J.Labrosse在1992編寫的。最早的這一系統(tǒng)被稱為uC/OS,經(jīng)過近10年的應(yīng)用和修改,uC/OS-Ⅱ于1999在JeaJ.LabRoSE中引入,2000年,聯(lián)邦航空局批準(zhǔn)了商用飛機(jī)RTCA DO-178B標(biāo)準(zhǔn),從而證明uC/OS-Ⅱ具有完整性、穩(wěn)定性和安全性。uC/OS-Ⅱ構(gòu)思巧妙、結(jié)構(gòu)簡(jiǎn)潔、可讀性強(qiáng)、功能齊全,并適合擴(kuò)展更多功能。并且,uC/OS-Ⅱ是公開免收費(fèi)源代碼的嵌入式實(shí)時(shí)內(nèi)核,自1992誕生以來,uC/OS-Ⅱ在各種嵌入式系統(tǒng)中得到了廣泛的應(yīng)用。
我們選用的核心板是DEVICEARM2200,標(biāo)準(zhǔn)配置處理器為L(zhǎng)PC2290,2M字節(jié)NOR FLASH、8M字節(jié)RAM、16M字節(jié)NAND FLASH和256字節(jié)E2PROM的MagicARM2200開發(fā)平臺(tái)。MagicARM2200滿足很多種類的接口,有以太網(wǎng)、調(diào)制解調(diào)器、IDE硬盤、CF卡、CAN、SD卡、液晶屏、JTAG仿真調(diào)試和外設(shè)PACK和GPIO輸出等,同時(shí)還支持u CLinux、uC/OS-Ⅱ雙操作系統(tǒng),搭建用戶系統(tǒng)平臺(tái)更方便。
為了保證uC/OS-Ⅱ正常運(yùn)行,處理器要滿足處理器的C編譯器能產(chǎn)生可重入代碼的要求。中斷可以用C語言打開和關(guān)閉。該處理器支持中斷,并且可以產(chǎn)生定時(shí)中斷。該處理器具有讀取和存儲(chǔ)的堆棧指針和其他CPU寄存器到堆棧或存儲(chǔ)器的指令。
2.2.1 編譯器的挑選
目前,有許多類型的C編譯器適合ARM處理器,如SDT、ADS/IAR/TAG和GCC,它們比SDT、ADS和GCC使用得更多。
SDT和ADS均是由ARM公司開發(fā)的,SDT的升級(jí)版本是AD,ARM不再支持SDT,因此,當(dāng)uC/OS-Ⅱ移植到ARM7時(shí),使用ADS編譯器是最好的選擇。我們利用ADS編譯器編制了MAGICARM2200開發(fā)平臺(tái)上的移植代碼。
2.2.2 ARM7工作模式的選擇
ARM7處理器采用的是PHILPS公司的ARM7TDMI-S微控制器LPC2290。uC/OS-Ⅱ任務(wù)可使用的模式有用戶模式和系統(tǒng)模式。為了切換任務(wù)模式,在移植過程中,將兩個(gè)用于架構(gòu)交換的系統(tǒng)函數(shù)添加到uC/OS Ⅱ中:ChangeToSYSMode( )和 ChangeToUSRMode( )。
2.3.1 OS_CPU.H的移植
(1)自定義數(shù)據(jù)類型
uC/OS-Ⅱ不適用C語言的中的短整型和長(zhǎng)整型等預(yù)處理器類型相關(guān)數(shù)據(jù)的類型,而用移植性強(qiáng)的整型數(shù)據(jù)類型,這樣既直觀又便于移植,同時(shí)這部分內(nèi)容也是必須移植的代碼。
對(duì)于不同類型的8/16/32位處理器,編譯器對(duì)C語言中的short,int,double等數(shù)據(jù)類型的長(zhǎng)度定義并不一致,因此μC/OS-Ⅱ中重新定義了統(tǒng)一的數(shù)據(jù)類型,以便在操作系統(tǒng)的移植過程中需要修改的代碼量減為最少,定義如下:

(2) 定義匯編語言接口函數(shù)
在μC/OS-Ⅱ中有四個(gè)軟件中斷程序,它們是用匯編語言編譯的。為了使用C語言調(diào)用中斷功能,ADS編譯器使用軟中斷指令SWI來定義接口功能。當(dāng)調(diào)用一個(gè)函數(shù)時(shí),處理器根據(jù)軟件中斷號(hào)自動(dòng)跳轉(zhuǎn)到相應(yīng)中斷服務(wù)程序的入口地址。在移植文件OS_CPU.H中,上表中各函數(shù)如下:

為了在uC/OS-Ⅱ嵌入式操作系統(tǒng)快速移植,我們使用自己定義的數(shù)據(jù)類型來實(shí)現(xiàn)內(nèi)核代碼,宏定義uC/OS-Ⅱ與微處理器使用的數(shù)據(jù)類型相同是移植的先決條件,通過OS_CPU.H頭文件實(shí)現(xiàn)可以保證移植后RTOS在微處理器系統(tǒng)平臺(tái)上正常運(yùn)行,
(1)在OS_CPU.H中先使用typedef和#define定義的與處理器相關(guān)的常量、宏和類型定義,然后uC/OS-Ⅱ才使用C語言中的短整型、整型等數(shù)據(jù)類型。與此同時(shí),一般通過為OS_STK定義無誤的C數(shù)據(jù)類型來確定完成任務(wù)堆棧的數(shù)據(jù)類型。
(2)在uC/OS-Ⅱ中,有兩種進(jìn)入臨界區(qū)的途徑。第一種途徑是在輸入關(guān)鍵節(jié)代碼時(shí)關(guān)閉中斷,并且在關(guān)鍵節(jié)代碼的末尾打開中斷。這是保護(hù)關(guān)鍵節(jié)代碼的正常操作的更好方法,但如果在輸入關(guān)鍵段代碼之前關(guān)閉了中斷,則在關(guān)鍵節(jié)的末尾就會(huì)更改中斷開關(guān)狀態(tài)。第二種途徑是在進(jìn)入臨界區(qū)之前中斷開關(guān)狀態(tài)堆棧保護(hù),然后關(guān)閉執(zhí)行臨界區(qū)的代碼,當(dāng)關(guān)鍵節(jié)代碼完成時(shí),在輸入關(guān)鍵段代碼之前堆棧進(jìn)程的中斷開關(guān)狀態(tài),這可以確保中斷開關(guān)狀態(tài)在關(guān)鍵節(jié)代碼前后不變。
2.3.2 OS_CPU_C.C的移植
移植要求我們必須編寫:初始化任務(wù)堆棧結(jié)構(gòu)的OSTaskStkInit( )函數(shù)、允許用戶擴(kuò)展μC/OS-Ⅱ的功能的OSTaskCreateHook( )函數(shù)、OSTaskDelHook( )函數(shù)、任務(wù)切換時(shí)調(diào)用OSTaskSwHook( )的函數(shù)、用戶擴(kuò)展統(tǒng)計(jì)功能的OSTaskStatHook( )函數(shù)和每次時(shí)鐘節(jié)拍被OSTaskTick()調(diào)用的OSTimeTickHook( )函數(shù)。
僅僅有OSTaskStkInit( )是一定要編寫的,剩余的五個(gè)函數(shù)只定義即可。我們?cè)诠こ汤锞帉懥薕STaskStkInit( )這個(gè)函數(shù),μC/OS-Ⅱ中任務(wù)堆棧初始化函數(shù)定義為OSTaskStkInit( ),目的是初始化任務(wù)堆棧,當(dāng)該任務(wù)由于某種原因掛起時(shí),程序狀態(tài)寄存器CPSR和當(dāng)前任務(wù)相關(guān)的寄存器信息都保存到堆棧中。針對(duì)LPC2290處理器,包括通用寄存器R0~R12,鏈接寄存器(LR)、程序計(jì)數(shù)器(PC)。
2.3.3 OS_CPU.A.ASM的移植
在μC/OS-Ⅱ中原始文件為OS_CPU_A.ASM,由于ADS編譯器規(guī)定的匯編語言文件后綴名為S,因此其改名為OS_CPU_A.S,移植過程需要編寫如下匯編語言函數(shù):最高優(yōu)先級(jí)OSStartHighRdy( )、任務(wù)級(jí)OSCtxSw( )、中斷級(jí)函數(shù)和OSIntxSw( )和時(shí)鐘節(jié)拍中斷服務(wù)函數(shù)OSTickISR( )。
OSStartHighRdy( )由OSRET( )函數(shù)調(diào)用,使系統(tǒng)能夠進(jìn)入多任務(wù)環(huán)境,以在就緒任務(wù)中運(yùn)行具有最高優(yōu)先級(jí)的任務(wù),并且其相應(yīng)的匯編語言函數(shù)形式是__OSStartHighRdy( )。由于任務(wù)堆棧結(jié)構(gòu)需要初始化,寄存器的初始化數(shù)據(jù)早已被壓縮到堆棧中,所以O(shè)sStasyRyDy( )函數(shù)只需要獲取任務(wù)的堆棧指針,并從堆棧恢復(fù)保存的數(shù)據(jù)就可以了。
OSCTXSW( )和OSIntxSw( )函數(shù)用于切換任務(wù)。與OSCTXSW( )函數(shù)不同,處理器寄存器值必須先存儲(chǔ)在堆棧中,然后暫停任務(wù);將OsTunxSW( )函數(shù)切換到中斷級(jí)任務(wù),從而將處理器寄存器值保存到任務(wù)中。堆棧被中斷,沒有必要再保存它。大多數(shù)匯編代碼是相同的,OSIntxSw( )可以通過跳轉(zhuǎn)到OSCTXSW( )中的相同代碼來實(shí)現(xiàn)。
Boot Loader是運(yùn)行在操作系統(tǒng)內(nèi)核之前運(yùn)行的小代碼??恐@個(gè)小代碼,我們能初始化硬件設(shè)備,并創(chuàng)建一個(gè)內(nèi)存空間的映射,將系統(tǒng)的硬件和軟件環(huán)境帶到合適的狀態(tài),以便為操作系統(tǒng)內(nèi)核的最終調(diào)用準(zhǔn)備正確的環(huán)境。
通常情況下,Boot Loader很依賴硬件。因此,在嵌入式世界中構(gòu)建通用的引導(dǎo)加載程序幾乎是不可能的。然而,我們可以將一些一般概念歸納為引導(dǎo)加載程序,以指導(dǎo)用戶特定的引導(dǎo)加載程序的設(shè)計(jì)和實(shí)現(xiàn)。
我們把uC/OS-Ⅱ移植到DEVICEARM2200核心板上以后,開始對(duì)操作系統(tǒng)進(jìn)行擴(kuò)充。依次是構(gòu)建文件系統(tǒng)、建立驅(qū)動(dòng)代碼并使API函數(shù)標(biāo)準(zhǔn)化、定義圖形用戶接口(GUI)函數(shù)、重建其他實(shí)用的應(yīng)用程序接口函數(shù)等。
在嵌入式設(shè)備的固態(tài)數(shù)據(jù)存儲(chǔ)器中有一片容量為2M的NAND FLASH存儲(chǔ)芯片。它由文件系統(tǒng)管理,同時(shí)文件系統(tǒng)的功能函數(shù)和FLASH之間有相關(guān)驅(qū)動(dòng)代碼并完成數(shù)據(jù)交換。
首先要讓iNoSoFrfile()函數(shù)初始化,然后為文件緩沖區(qū)分配存儲(chǔ)空間。文件系統(tǒng)函數(shù)在OsField.h中定義。使用OpenOsFrase( )函數(shù)在指定的模式下打開文件文件;用Read OsScript()函數(shù)將打開的文件數(shù)據(jù)讀入指定的緩沖區(qū);用RealeOsFoofile( )函數(shù)將指定的緩沖區(qū)數(shù)據(jù)寫入文件;使用LureReADOSfile()函數(shù)的文本文件的Reter,用CuteOsFixfile( )函數(shù)關(guān)閉文件并釋放文件。文件緩沖區(qū);使用SekOsFask( )函數(shù)定位文件指針;刪除DeleTeSoFfile()函數(shù)指定的文件用于實(shí)現(xiàn)控制的傳遞。