胡國晨
(西安石油大學 〈中船重工西安東儀科工集團有限公司〉 陜西 西安 710000)
uC/OS-Ⅱ是一個嵌入式多任務實時操作系統(tǒng),是Jean J.Labrosse在1992編寫的。最早的這一系統(tǒng)被稱為uC/OS,經(jīng)過近10年的應用和修改,uC/OS-Ⅱ于1999在JeaJ.LabRoSE中引入,2000年,聯(lián)邦航空局批準了商用飛機RTCA DO-178B標準,從而證明uC/OS-Ⅱ具有完整性、穩(wěn)定性和安全性。uC/OS-Ⅱ構(gòu)思巧妙、結(jié)構(gòu)簡潔、可讀性強、功能齊全,并適合擴展更多功能。并且,uC/OS-Ⅱ是公開免收費源代碼的嵌入式實時內(nèi)核,自1992誕生以來,uC/OS-Ⅱ在各種嵌入式系統(tǒng)中得到了廣泛的應用。
我們選用的核心板是DEVICEARM2200,標準配置處理器為LPC2290,2M字節(jié)NOR FLASH、8M字節(jié)RAM、16M字節(jié)NAND FLASH和256字節(jié)E2PROM的MagicARM2200開發(fā)平臺。MagicARM2200滿足很多種類的接口,有以太網(wǎng)、調(diào)制解調(diào)器、IDE硬盤、CF卡、CAN、SD卡、液晶屏、JTAG仿真調(diào)試和外設PACK和GPIO輸出等,同時還支持u CLinux、uC/OS-Ⅱ雙操作系統(tǒng),搭建用戶系統(tǒng)平臺更方便。
為了保證uC/OS-Ⅱ正常運行,處理器要滿足處理器的C編譯器能產(chǎn)生可重入代碼的要求。中斷可以用C語言打開和關(guān)閉。該處理器支持中斷,并且可以產(chǎn)生定時中斷。該處理器具有讀取和存儲的堆棧指針和其他CPU寄存器到堆?;虼鎯ζ鞯闹噶?。
2.2.1 編譯器的挑選
目前,有許多類型的C編譯器適合ARM處理器,如SDT、ADS/IAR/TAG和GCC,它們比SDT、ADS和GCC使用得更多。
SDT和ADS均是由ARM公司開發(fā)的,SDT的升級版本是AD,ARM不再支持SDT,因此,當uC/OS-Ⅱ移植到ARM7時,使用ADS編譯器是最好的選擇。我們利用ADS編譯器編制了MAGICARM2200開發(fā)平臺上的移植代碼。
2.2.2 ARM7工作模式的選擇
ARM7處理器采用的是PHILPS公司的ARM7TDMI-S微控制器LPC2290。uC/OS-Ⅱ任務可使用的模式有用戶模式和系統(tǒng)模式。為了切換任務模式,在移植過程中,將兩個用于架構(gòu)交換的系統(tǒng)函數(shù)添加到uC/OS Ⅱ中:ChangeToSYSMode( )和 ChangeToUSRMode( )。
2.3.1 OS_CPU.H的移植
(1)自定義數(shù)據(jù)類型
uC/OS-Ⅱ不適用C語言的中的短整型和長整型等預處理器類型相關(guān)數(shù)據(jù)的類型,而用移植性強的整型數(shù)據(jù)類型,這樣既直觀又便于移植,同時這部分內(nèi)容也是必須移植的代碼。
對于不同類型的8/16/32位處理器,編譯器對C語言中的short,int,double等數(shù)據(jù)類型的長度定義并不一致,因此μC/OS-Ⅱ中重新定義了統(tǒng)一的數(shù)據(jù)類型,以便在操作系統(tǒng)的移植過程中需要修改的代碼量減為最少,定義如下:
(2) 定義匯編語言接口函數(shù)
在μC/OS-Ⅱ中有四個軟件中斷程序,它們是用匯編語言編譯的。為了使用C語言調(diào)用中斷功能,ADS編譯器使用軟中斷指令SWI來定義接口功能。當調(diào)用一個函數(shù)時,處理器根據(jù)軟件中斷號自動跳轉(zhuǎn)到相應中斷服務程序的入口地址。在移植文件OS_CPU.H中,上表中各函數(shù)如下:
為了在uC/OS-Ⅱ嵌入式操作系統(tǒng)快速移植,我們使用自己定義的數(shù)據(jù)類型來實現(xiàn)內(nèi)核代碼,宏定義uC/OS-Ⅱ與微處理器使用的數(shù)據(jù)類型相同是移植的先決條件,通過OS_CPU.H頭文件實現(xiàn)可以保證移植后RTOS在微處理器系統(tǒng)平臺上正常運行,
(1)在OS_CPU.H中先使用typedef和#define定義的與處理器相關(guān)的常量、宏和類型定義,然后uC/OS-Ⅱ才使用C語言中的短整型、整型等數(shù)據(jù)類型。與此同時,一般通過為OS_STK定義無誤的C數(shù)據(jù)類型來確定完成任務堆棧的數(shù)據(jù)類型。
(2)在uC/OS-Ⅱ中,有兩種進入臨界區(qū)的途徑。第一種途徑是在輸入關(guān)鍵節(jié)代碼時關(guān)閉中斷,并且在關(guān)鍵節(jié)代碼的末尾打開中斷。這是保護關(guān)鍵節(jié)代碼的正常操作的更好方法,但如果在輸入關(guān)鍵段代碼之前關(guān)閉了中斷,則在關(guān)鍵節(jié)的末尾就會更改中斷開關(guān)狀態(tài)。第二種途徑是在進入臨界區(qū)之前中斷開關(guān)狀態(tài)堆棧保護,然后關(guān)閉執(zhí)行臨界區(qū)的代碼,當關(guān)鍵節(jié)代碼完成時,在輸入關(guān)鍵段代碼之前堆棧進程的中斷開關(guān)狀態(tài),這可以確保中斷開關(guān)狀態(tài)在關(guān)鍵節(jié)代碼前后不變。
2.3.2 OS_CPU_C.C的移植
移植要求我們必須編寫:初始化任務堆棧結(jié)構(gòu)的OSTaskStkInit( )函數(shù)、允許用戶擴展μC/OS-Ⅱ的功能的OSTaskCreateHook( )函數(shù)、OSTaskDelHook( )函數(shù)、任務切換時調(diào)用OSTaskSwHook( )的函數(shù)、用戶擴展統(tǒng)計功能的OSTaskStatHook( )函數(shù)和每次時鐘節(jié)拍被OSTaskTick()調(diào)用的OSTimeTickHook( )函數(shù)。
僅僅有OSTaskStkInit( )是一定要編寫的,剩余的五個函數(shù)只定義即可。我們在工程里編寫了OSTaskStkInit( )這個函數(shù),μC/OS-Ⅱ中任務堆棧初始化函數(shù)定義為OSTaskStkInit( ),目的是初始化任務堆棧,當該任務由于某種原因掛起時,程序狀態(tài)寄存器CPSR和當前任務相關(guān)的寄存器信息都保存到堆棧中。針對LPC2290處理器,包括通用寄存器R0~R12,鏈接寄存器(LR)、程序計數(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)先級OSStartHighRdy( )、任務級OSCtxSw( )、中斷級函數(shù)和OSIntxSw( )和時鐘節(jié)拍中斷服務函數(shù)OSTickISR( )。
OSStartHighRdy( )由OSRET( )函數(shù)調(diào)用,使系統(tǒng)能夠進入多任務環(huán)境,以在就緒任務中運行具有最高優(yōu)先級的任務,并且其相應的匯編語言函數(shù)形式是__OSStartHighRdy( )。由于任務堆棧結(jié)構(gòu)需要初始化,寄存器的初始化數(shù)據(jù)早已被壓縮到堆棧中,所以OsStasyRyDy( )函數(shù)只需要獲取任務的堆棧指針,并從堆?;謴捅4娴臄?shù)據(jù)就可以了。
OSCTXSW( )和OSIntxSw( )函數(shù)用于切換任務。與OSCTXSW( )函數(shù)不同,處理器寄存器值必須先存儲在堆棧中,然后暫停任務;將OsTunxSW( )函數(shù)切換到中斷級任務,從而將處理器寄存器值保存到任務中。堆棧被中斷,沒有必要再保存它。大多數(shù)匯編代碼是相同的,OSIntxSw( )可以通過跳轉(zhuǎn)到OSCTXSW( )中的相同代碼來實現(xiàn)。
Boot Loader是運行在操作系統(tǒng)內(nèi)核之前運行的小代碼。靠著這個小代碼,我們能初始化硬件設備,并創(chuàng)建一個內(nèi)存空間的映射,將系統(tǒng)的硬件和軟件環(huán)境帶到合適的狀態(tài),以便為操作系統(tǒng)內(nèi)核的最終調(diào)用準備正確的環(huán)境。
通常情況下,Boot Loader很依賴硬件。因此,在嵌入式世界中構(gòu)建通用的引導加載程序幾乎是不可能的。然而,我們可以將一些一般概念歸納為引導加載程序,以指導用戶特定的引導加載程序的設計和實現(xiàn)。
我們把uC/OS-Ⅱ移植到DEVICEARM2200核心板上以后,開始對操作系統(tǒng)進行擴充。依次是構(gòu)建文件系統(tǒng)、建立驅(qū)動代碼并使API函數(shù)標準化、定義圖形用戶接口(GUI)函數(shù)、重建其他實用的應用程序接口函數(shù)等。
在嵌入式設備的固態(tài)數(shù)據(jù)存儲器中有一片容量為2M的NAND FLASH存儲芯片。它由文件系統(tǒng)管理,同時文件系統(tǒng)的功能函數(shù)和FLASH之間有相關(guān)驅(qū)動代碼并完成數(shù)據(jù)交換。
首先要讓iNoSoFrfile()函數(shù)初始化,然后為文件緩沖區(qū)分配存儲空間。文件系統(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ù)指定的文件用于實現(xiàn)控制的傳遞。