摘 要: μC/OS—II是一個移植方便、可固化、占先的多任務實時內核,它適用于多種微處理器和數字處理芯片。本文論述了μC/OS—II在ARM處理器LPC2131上移植的詳細過程。
關鍵詞: μC/OS—II LPC2131 內核移植
1.系統簡介
1.1LPC2131簡介
LPC2131包含一個支持仿真的ARM7TDMI-S CPU、與片內存儲控制器接口的ARM7局部總線、與中斷控制器接口的AMBA高性能總線AHB和連接片內外設功能的VLSI外設總線VPB。AHB和VPB通過橋相連。LPC2131的外設功能(中斷控制器除外)都連接到VPB總線。片內外設與器件引腳的連接由引腳連接模塊控制。該模塊必須由軟件控制,以符合外設功能與引腳在特定應用中的需求。
1.2 μC/OS—II簡介
μC/OS-II是源碼公開的實時嵌入式內核,其性能完全可以與商業產品競爭。此外,μC/OS—II的鮮明特點就是源碼公開,便于移植和維護。
μC/OS-II的移植條件:
* 處理器的C編譯器可以產生可重入代碼;
* 可以使用C調用進入和退出Critical Code(臨界區代碼);
* 處理器必須支持硬件中斷,并且需要一個定時中斷源;
* 處理器需要有能夠在CPU寄存器與內存和堆棧交換數據的指令。
移植μC/OS—II的主要工作就是處理器和編譯器的相關代碼。
2.μC/OS—II移植過程
2.1 設置與處理器相關的OS_CPU.H文件
OS_CPU.H文件包括了用#define語句定義的、與處理器相關的常數、宏以和類型。對OS_CPU.H的修改主要有以下幾個步驟。
2.1.1 定義與編譯器相關的數據類型
μC/OS—II的移植包括了一系列的數據類型定義,以確保其可移植性。相關的數據定義類型如下:
typedef unsigned charBOOLEAN;/* 布爾變量 */
typedef unsigned charINT8U;/* 無符號8位整型變量 */
typedef signed charINT8S; /* 有符號8位整型變量 */
typedef unsigned short INT16U;/* 無符號16位整型變量 */
typedef signed short INT16S;/* 有符號16位整型變量 */
typedef unsigned int INT32U;/* 無符號32位整型變量 */
typedef signed int INT32S;/* 有符號32位整型變量 */
typedef float FP32; /* 單精度浮點數(32位長度)*/
typedef double FP64; /* 雙精度浮點數(64位長度)*/
2.1.2 宏定義——臨界代碼的處理方式
μC/OS-II定義了兩個宏,用來關/開中斷:OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL().它們總是成對使用的,并且分別加在臨界段代碼的前面和后面,它們可以使用3種不同的方式實現,在這里我們使用的是第二種方式。
第二種方法是:執行OS_ENTER_CRITICAL()時,先將中斷狀態保存到堆棧中,然后關中斷;而當執行OS_EXIT_CRITICAL()時,再從堆棧中恢復原來的中斷開/關狀態。其實現程序代碼如下:
#define OS_CRITICAL_METHOD 2/* 選擇開、關中斷的方式*/
__swi(0x00) void OS_TASK_SW(void); /*任務級任務切換函數 */
__swi(0x01) void _OSStartHighRdy(void); /*運行優先級最高的任務*/
__swi(0x02) void OS_ENTER_CRITICAL(void);/關中斷*/
__swi(0x03) void OS_EXIT_CRITICAL(void); /* 開中斷 */
__swi(0x40) void *GetOSFunctionAddr(int Index); /* 獲取系統服務函數入口*/
__swi(0x41) void *GetUsrFunctionAddr(int Index);/* 獲取自定義服務函數入口*/
__swi(0x42) void OSISRBegin(void); /* 中斷開始處理*/
__swi(0x43) intOSISRNeedSwap(void);/*判斷中斷是否需要切換*/
__swi(0x80) void ChangeToSYSMode(void);/* 任務切換到系統模式*/
__swi(0x81) void ChangeToUSRMode(void);/*任務切換到用戶模式*/
__swi(0x82) void TaskIsARM(INT8U prio);/*任務代碼是ARM代碼*/
__swi(0x83) void TaskIsTHUMB(INT8U prio); /* 任務代碼是THUMB*/
2.1.3 設定堆棧增長方向
堆棧由高地址向低地址增長,這個也是和編譯器有關的,當進行函數調用時,入口參數和返回地址一般都會保存在當前任務的堆棧中,編譯器的編譯選項和由此生成的堆棧指令就會決定堆棧的增長方向。
2.2 設置與操作系統相關的OS_CPU_C.C文件
μC/OS—II的移植范例要求編寫OSTaskStkInit()等10個簡單的C函數。 惟一必要的函數是OSTaskStkInit(),其他9個函數必須申明,但并不一定要包含任何代碼。
OSTaskCreat()和OSTaskCreateExt()通過調用OSTaskStkInit(),初始化任務的棧結構;因此,堆棧看起來就像中斷剛發生過一樣,所有寄存器都保存在堆棧中。
當前任務堆棧初始化完成后,OSTaskStkInit() 返回新的堆棧指針stk,在OSTaskCreate()執行時將會調用其初始化過程,然后通過OSTCBInit()函數調用將返回的SP指針保存到該任務的TCB塊中。
OSTaskStkInit()的示意性程序代碼如下所示:
OS_STK *OSTaskStkInit (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT16U opt)
{
opt = opt;
stk = ptos;
獲取堆棧指針;
使用滿遞減堆棧;
使用R0傳遞第一個參數;
開中斷;
關中斷計數器OsEnterSum;
Return(stk)
}
2.3 OS_CPU_A.ASM中匯編函數的設置
在該文件中,主要需要編寫以下三個匯編函數。
2.3.1 OSStartHighRdy()
OSStart()函數通過調用OSStartHighRdy()來使就緒任務中優先級最高的任務開始運行,
OSStart()多任務啟動以后,該函數負責從最高優先級任務的TCB控制塊中獲得該任務的堆棧指針SP,通過SP依次將CPU現場恢復,這時系統就將控制權交割用戶創建該任務進程。
2.3.2 OSCtxSw()
任務級的切換是通過執行軟中斷指令,或者依據處理器的不同,執行TRAP(陷阱)指令來實現的。中斷服務子程序、陷阱或異常處理的向量地址必須指向OSCtxSw()。
如果當前任務調用μC/OS—II提供的功能函數,并使得更高優先級任務進入了就緒態,μC/OS—II就會借助向量地址找到OSCtxSw()。
2.3.3 OSIntCtxSw()
OSIntExit()通過調用OSIntCtxSw(),在ISR執行任務切換的功能。因為OSIntCtxSw()是在ISR中被調用的,所以所有的處理器寄存器都被正確地保存到了被中斷任務的堆棧之中。
本文簡述了使用嵌入式實時操作系統μC/OS—II的優勢并簡介了它的基本特性,進而分析了其與LPC2131處理器相關的移植條件,詳細介紹了在移植過程中對操作系統內核文件所做的修改工作,實現了一個嵌入式系統的軟件平臺的設計。