丁旖 武穎 丁柄文
摘要:嵌入式系統(tǒng)的應用和發(fā)展是計算機技術自桌面系統(tǒng)和網(wǎng)絡技術之后,IT產業(yè)和IT技術又一 個新的重大進展。而對于規(guī)模比較小的系統(tǒng),UC/OSII 則以實時行強,內核公開,系統(tǒng)穩(wěn)定,易于學習和開發(fā)等特點受到廣大技術人員和嵌入式愛好者的青睞。本文以UC/OSII為例介紹嵌入式uC/OS-II實時操作系統(tǒng)在嵌入式平臺上的移植程序及方法。
關鍵詞:嵌入式;UC/OSII;實時操作系統(tǒng);開發(fā)流程;移植μC/OS-Ⅱ
1 引言
在日常生活等各個領域.當前流行的嵌入式操作系統(tǒng)有l(wèi)inux,wince, UC/OSII 等等。我國正在成為世界電子制造業(yè)的重要基地之一,對嵌入式系統(tǒng)技術及相關技術人才存在巨大需求。
2 uC/OS-II的移植程序
將μC/OS-Ⅱ移植到不同的處理器上。所謂移植,就是使一個實時內核能在某個微處理器或微控制器上運行。
要使μC/OS-Ⅱ正常運行,處理器必須滿足以下要求:
1. 處理器的C編譯器能產生可重入代碼。
用C語言就可以打開和關閉中斷。
處理器支持中斷,并且能產生定時中斷(通常在10至100Hz之間)。
處理器支持能夠容納一定量數(shù)據(jù)(可能是幾千字節(jié))的硬件堆棧。
處理器有將堆棧指針和其它CPU寄存器讀出和存儲到堆?;騼却嬷兄噶睢?/p>
像Motorola 6805系列的處理器不能滿足上面的第4條和第5條要求,所以μC/OS-Ⅱ不能在這類處理器上運行。
移植工作包括以下幾個內容:
用#define設置一個常量的值(OS_CPU.H)
聲明10個數(shù)據(jù)類型(OS_CPU.H)
用#define聲明三個宏(OS_CPU.H)
用C語言編寫六個簡單的函數(shù)(OS_CPU_C.C)
編寫四個匯編語言函數(shù)(OS_CPU_A.ASM)
一旦代碼移植結束,下一步工作就是測試。
3 UCOS在51單片機的移植
任務函數(shù)中帶有形參和局部變量時若使用reentrant關鍵字會引起重入,從C51.PDF 129-131頁的內容知:為了函數(shù)重入,形參和局部變量必須保存在堆棧里,由于51硬件堆棧太小,KEIL將根據(jù)內存模式在相應內存空間仿真堆棧(生長方向由上向下,與硬件棧相反)。對于大模式編譯,函數(shù)返回地址保存在硬件堆棧里,形參和局部變量放在仿真堆棧中,棧指針為?C_XBP,XBPSTACK=1時,起始值在startup.a51中初始化為FFFFH+1。
為了支持重入,重新設計了堆棧結構。增加了保存仿真堆棧指針?C_XBP和堆棧內容的數(shù)據(jù)結構。相應改變的文件有:OS_CPU_A.ASM、OS_CPU_C.C、OS_CPU.H、YY.C。建議使用統(tǒng)一的固定大小的堆??臻g,盡管uCOSII原作者把不同任務使用不同空間看成是優(yōu)點,但為了在51上有效實現(xiàn)任務重入,還是不使用這個優(yōu)點。
用戶堆??臻g的大小是可以精確計算出來的。用戶堆??臻g=硬件堆??臻g+仿真堆棧空間。硬件棧占用內部RAM,內部RAM執(zhí)行效率高,如果堆??臻g過大,會影響KEIL編譯的程序性能。如果堆??臻g小,在中斷嵌套和程序調用時會造成系統(tǒng)崩潰。綜合考慮,可把硬件堆??臻g大小定成了64字節(jié),用戶根據(jù)實際情況可以自行設定。仿真堆棧大小取決于形參和局部變量的類型及數(shù)量,可以精確算出。因為所有用戶棧使用相同空間大小,所以取占用空間最大的任務函數(shù)的空間大小為仿真堆??臻g大小。這樣用戶堆棧空間大小就唯一確定了。可將用戶堆??臻g大小用宏定義在OS_CFG.H文件中,宏名為MaxStkSize。
51的SP只有8位,無法在64K空間中自由移動,只好采用拷貝全部硬件堆棧內容的笨辦法。51本來就弱,這么一來缺點更明顯了。其實,引入OS必然要付出代價,一般OS要占用CPU10%-20%的負荷能力,需權衡利弊決定。切換頻率決定了CPU的耗費,頻率越高耗費越大,大到一定程度就該換更強的CPU了。我選了50Hz的切換頻率,不高也不低,用戶可以根據(jù)需要自行定奪。
4μC/OS-II在嵌入式開發(fā)平臺上進行移植的一般方法和技巧
在選定了系統(tǒng)平臺和開發(fā)工具之后,進行μC/OS-II的移植工作,一般需要遵循以下的幾個步驟:
深入了解所采用的系統(tǒng)核心
分析所采用的C語言開發(fā)工具的特點
編寫移植代碼
進行移植的測試
針對項目的開發(fā)平臺,封裝服務函數(shù) (類似80x86版本的PC.C和PC.H)
系統(tǒng)核心
無論項目所采用的系統(tǒng)核心是MCU、DSP、MPU,進行μC/OS-II的移植時,所需要關注的細節(jié)都是相近的。
首先,是芯片的中斷處理機制,如何開啟、屏蔽中斷,可否保存前一次中斷狀態(tài)等。還有,芯片是否有軟中斷或是陷阱指令,又是如何觸發(fā)的。
此外,還需關注系統(tǒng)對于存儲器的使用機制,諸如內存的地址空間,堆棧的增長方向,有無批量壓棧的指令等。
植代碼
在深入了解了系統(tǒng)核心與開發(fā)工具的基礎上,真正編寫移植代碼的工作就相對比較簡單了。
μC/OS-II自身的代碼絕大部分都是用ANSI C編寫的,而且代碼的層次結構十分干凈,與平臺相關的移植代碼僅僅存在于OS_CPU_A.ASM、OS_CPU_C.C以及OS_CPU.H這三個文件當中。
在移植的時候,結合前面兩個步驟中已經(jīng)掌握的信息,基本上按照《嵌入式實時操作系統(tǒng)μC/OS-II》一書的相關章節(jié)的指導來做就可以了。
但是,由于系統(tǒng)核心、開發(fā)工具的千差萬別,在實際項目中,一般都會有一些處理方法上的不同,需要特別注意。以C6711的移植為例:
※ 中斷的開啟和屏蔽的兩個宏定義為:
#define OS_ENTER_CRITICAL() Disable_int()
#define OS_EXIT_CRITICAL() Enable_int()
Disable_int和Enable_int是用匯編語言編寫的兩個函數(shù)。在這里使用了控制狀態(tài)寄存器(CSR)的一個特性——CSR中除了控制全局中斷的GIE位之外,還有一個PGIE位,可用于保存之前的GIE狀態(tài)。
因此在Disable_int中先將GIE的值寫入PGIE,然后再將GIE寫0,屏蔽中斷。而在Enable_int中則從PGIE讀出值,寫入GIE,從而回復到之前的中斷設置。
這樣,就可以避免使用這兩個宏而意外改變了系統(tǒng)的中斷狀態(tài)——此外,也沒有使用堆棧或局部變量,比原作者推薦的方法要好。※ 任務的切換:
前文說過,C6711中沒有軟中斷機制,所以任務的切換需要用匯編語言自行編寫一個函數(shù)_OSCtxSw來實現(xiàn),并且 #define OS_TASK_SW() OSCtxSw() 在C6711中需要入棧保護的寄存器包括A0-A15、B0-B15、CSR、IER、IRP和AMR,這些再加上當前的程序地址構成一個存儲幀,需要入棧保存。
_OSCtxSw函數(shù)中,需要像發(fā)生了一次中斷那樣,將上述存儲幀入棧,然后獲取被激活任務的TCB指針,將其存儲幀的內容彈出,從而完成任務切換。
需要特別注意的是,在這里OS_TASK_SW是作為函數(shù)調用的,所以如前文所述,調用時的當前程序地址是保存在B3寄存器中的,這也就是任務重新激活時的返回地址。
※ 中斷的編寫:
如前文所述,如果用“interrupt”關鍵字聲明函數(shù),CCS在編譯時,會自動將該函數(shù)中使用到的寄存器入棧、出棧保護。但是,這會導致各種中斷發(fā)生時,出入棧的內容各不相同。這對于μC/OS-II是會引起嚴重錯誤的。因為μC/OS-II要求中斷發(fā)生時的入棧操作使用和發(fā)生任務切換時完全一樣的存儲幀結構。
因此,在移植時、基于μC/OS-II進行開發(fā)時,都不應當使用“interrupt”關鍵字,而應用如下結構編寫中斷函數(shù):
void OSTickISR (void)
{
DSP_C6x_Save(); // 服務函數(shù),入棧
OSIntEnter();
if (OSIntNesting == 1) // v2.51版本新增加
{
OSTCBCur->OSTCBStkPtr
=(OS_STK*) DSP_C6x_GetCurrentSP(); // 服務函數(shù)
} // 獲取當前SP的值
// 允許中斷嵌套 則在此處開中斷
OSTimeTick();
OSIntExit();
DSP_C6x_Resume(); // 服務函數(shù),出棧
}
DSP_C6x_Save 和DSP_C6x_Resume是兩個服務函數(shù),分別完成中斷的出、入棧操作。它們與OS_TASK_SW函數(shù)的區(qū)別在于:中斷發(fā)生時的當前程序地址是自 動保存在IRP寄存器的,應將其作為任務返回地址,而不再是B3。此外DSP_C6x_Resume是一個永遠不會返回的函數(shù),在將所有內容出棧后,它就直接跳轉回到中斷發(fā)生前的程序地址處,繼續(xù)執(zhí)行。
進行移植的測試
在編寫完了所有的移植代碼之后,就可以編寫幾個簡單的任務程序進行測試了,大體上可以分三個步驟來進行,相關資料比較詳盡,這里就不多作贅述 了。
封裝服務函數(shù)
最后這個步驟,往往是容易被忽視的,但對于保持項目代碼的簡潔、易維護有很重要的意義。
μC/OS-II的原作者強烈建議將源代碼分路徑進行存儲,
5. 結論
μC/OS-II具有免費、簡單、可靠性高、實時性好等優(yōu)點,但也有缺乏便利 開發(fā)環(huán)境等缺點,尤其不像商用嵌入式系統(tǒng)那樣得到廣泛使用和持續(xù)的研究更新。但開放性又使得開發(fā)人員可以自行裁減和添加所需的功能,在許多應用領 域發(fā)揮著獨特的作用。當然,是否在單片機系統(tǒng)中嵌入μC/OS-II應視所開發(fā)的項目而定,對于一些簡單的、低成本的項目來說,就沒必要使用了。
參考文獻
[1] JEAN J.LABROSSE,邵貝貝譯.
[2] μC/OS-II ―源碼公開的實時嵌入式操作系統(tǒng). 中國電力出版社
[3] uC/OS-II-源碼公開的實時嵌人式操作系統(tǒng)【M】,邵貝貝譯.中國電力出版社.2001
[4] 忠梅等 ‘ARM 嵌入式處理器結構與應用基礎.北京:北京虢譬航天大學出版社,2002