凌 云
(建東職業(yè)技術(shù)學(xué)院,江蘇 常州213022)
在嵌入式系統(tǒng)的設(shè)計(jì)和實(shí)現(xiàn)中,嵌入式實(shí)時操作系統(tǒng)得到了廣泛應(yīng)用,嵌入式實(shí)時操作系統(tǒng)為用戶提供了一個開發(fā)環(huán)境,使用戶可以集中精力于特殊應(yīng)用的嵌入式軟件的設(shè)計(jì),簡化了系統(tǒng)設(shè)計(jì),提高了開發(fā)效率。
μC/OS-II 是一個開放源代碼的,精簡的實(shí)時內(nèi)核。 它功能強(qiáng)大,提供了任務(wù)管理、進(jìn)程調(diào)度、任務(wù)間通信、內(nèi)存管理等功能。 更重要的是,μC/OS-II 自1992 年的第一版(μC/OS)以來已經(jīng)有好幾百個應(yīng)用,是一個經(jīng)實(shí)踐證明好用且穩(wěn)定可靠的內(nèi)核。 下面將介紹的是如何將μC/OS-II 移植到TI 公司高性能定點(diǎn)DSP TMS320LF2407 上。
μC/OS-II 的移植條件是:只要該處理器有堆棧,有CPU 內(nèi)部寄存器入棧、出棧指令;使用的C 編譯器支持內(nèi)嵌匯編(inline assembly)或者該C 語言可擴(kuò)展,可連接匯編模塊,使得關(guān)中斷、開中斷能在C 語言程序中實(shí)現(xiàn)。
TMS320LF2407 是由美國德州儀器(TI)公司生成的高性能定點(diǎn)DSP[1]。 T1 公司提供的編譯器CodeComposer V4.10. 36 支 持C 語 言 和匯編語言開發(fā),本文在此編譯器的基礎(chǔ)上進(jìn)行了μC/OS-II 的移植。CodeComposer V4.10. 36 內(nèi)置編譯器維持一個C 運(yùn)行環(huán)境, 為了確保C 語言的成功執(zhí)行,所有運(yùn)行時代碼都必須保持這個環(huán)境。 在編寫匯編和C 代碼的接口函數(shù)時也必須遵循一些規(guī)則,μC/OS-II 才可以完全移植到TMS320LF2407 上。
μC/OS-II 核心代碼很小,程序開發(fā)人員要把它移植到自己的目標(biāo)板中只需做少量的工作。 μC/OS-II 大部分源代碼是用C 語言寫的,但是完成和處理器一些相關(guān)的代碼時, 還是必須要用匯編語言來實(shí)現(xiàn)的。寄存器的讀、寫只能通過匯編語言的存儲和加載指令來實(shí)現(xiàn)。要使μC/OS-II 能夠正常工作,處理器必須滿足以下要求:①處理器的C 編譯器能產(chǎn)生可重入代碼;②用C 語言可以打開和關(guān)閉中斷;③處理器支持中斷,并且能夠產(chǎn)生定時中斷(通常在10~100Hz 之間);④處理器能夠支持容納一定量數(shù)據(jù)的硬件堆棧;⑤處理器有將堆棧指針和其它寄存器讀出和存儲到堆棧或內(nèi)存中的指令。
在移植之前,首先我們需要對μC/OS-II 的內(nèi)核,特別是任務(wù)切換機(jī)制要有一個比較深刻的理解, 而具體的移植工作主要是修改μC/OS-II 中與處理器相關(guān)的三個文件:OS_CPU_A.ASM、OS_CPU_C.C 以及OS_CPU.H, 此 外 還 需 要 修 改INCLUDES.H 文 件, 以 及 針 對TMS320LF2407 最多擴(kuò)展64K 程序存儲器的限制修改CFG.H 文件,裁減μC/OS-II,但后兩個文件改寫較簡單,這里不再贅說。
此文件的內(nèi)容可根據(jù)μC/OS-II 的內(nèi)容進(jìn)行修改, 這里僅給出關(guān)鍵內(nèi)容:
unsigned int INT16U; /* 定義堆棧單位長度*/
unsigned int OS_STK;
#define OS STK_GROWTH 0 /* 定義堆棧由低地址向高地址遞減*/
#define OS_ENTER_CRITICAL() asm(” SECT INTM”); /* 開關(guān)中斷宏定義*/
#define 0S_EXTI_CRITICAL() asm(” CLRC INTM”);
#define OS_TASI_SW() asm(” INTR 8”); /* 任務(wù)切換宏定義*/
在這個文件中需要用戶定義6 個C 語言函數(shù):OSTaskStkInit(),OSTaskCreateHook(),OSTaskDelHook(),OSTaskSwHook(),OSTaskStatHook(),OSTimeTickHook(),實(shí)際必須修改的只有OSTaskStkInit()。
OSTaskStkInit () 函數(shù)是由任務(wù)創(chuàng)建函數(shù)OSTaskCreate ()或OSTaskCreateExt()調(diào)用,功能是初始化任務(wù)堆棧。任務(wù)堆棧用于任務(wù)切換或中斷發(fā)生時保護(hù)當(dāng)前任務(wù)的上下文狀態(tài),以便中斷返回或者任務(wù)下次被調(diào)度運(yùn)行時能夠接著運(yùn)行。堆棧的結(jié)構(gòu)可以按照自己的需要而定制,考慮到CC2000 的C 語言運(yùn)行時支持庫rts2xx.lib 中已經(jīng)有用于保存中斷上下文的庫函數(shù)I$$SAVE 和I$$REST(可用Dspar 工具查看這一函數(shù)),為了重用這一庫函數(shù),這里按照這一庫函數(shù)堆棧結(jié)構(gòu)來設(shè)計(jì)堆棧,其結(jié)構(gòu)如下圖1 所示:
一些說明如下:
(1)第一級硬件堆棧(HW STACK LEVEL 1)不需要保存,原因是I$$SAVE 是通過CALL 指令來調(diào)用,CALL 指令會使用一個硬件堆棧用于保存返回地址。所以在保存另外七個硬件堆棧前會將第一級硬件堆棧彈出。
(2)當(dāng)調(diào)度再次發(fā)生時,通過調(diào)用與I$$SAVE 對應(yīng)的I$$REST 來恢復(fù)被中斷的上下文。
此文件包括的四個函數(shù)都跟處理器有關(guān),由于不同的處理器有不同的寄存器, 所以操作系統(tǒng)在這個文件里給用戶留下四個函數(shù)接口,以便用戶根據(jù)所選處理器編寫相應(yīng)的匯編程序以完成固定的功能。四個函數(shù)分別是OSStartHighRdy(),OSCtxSw(),OSIntCtxSw(),OSTickISR()。
2.3.1 OSStartHighRdy()
該函數(shù)是由啟動函數(shù)OSStart()調(diào)用的,功能是使系統(tǒng)能及時地運(yùn)行優(yōu)先級最高的就緒任務(wù),由于系統(tǒng)中數(shù)據(jù)指針OSTCBHighRdy 一直指向就緒任務(wù)中優(yōu)先級最高的任務(wù)控制塊OSTCB,使得OSStartHighRdy()輕易就可獲取最高優(yōu)先級任務(wù)的棧頂指針,再將保存在此任務(wù)堆棧的寄存器值恢復(fù)到CPU 寄存器中,使該任務(wù)得以運(yùn)行,實(shí)現(xiàn)多任務(wù)的啟動。 對下TMS320LF2407 而言,OSStartHighRdy()代碼編寫如下:
_OSStartHighRdy:
CALL _OSTaskSwHook;調(diào)用鉤子函數(shù),實(shí)現(xiàn)用戶自定義功能
LACK 1; OSRunning = TRUE;
LDPK _OSRunning
SACL _OSRunning
LDPK _OSTCBHighRdy; SP=OSTCBHighRdy->OSTCBStkPtr;
LAR AR3, _OSTCBHighRdy
MAR *, AR3
LAR AR1, *
B I$$REST, AR1; 上下文恢復(fù),任務(wù)返回在調(diào)用函數(shù)OSTaskSwHook()時,由于當(dāng)前任務(wù)控制塊OSTCBCur仍然指向?qū)⒁磺袚Q出去的任務(wù),而OSTCBHighRdy 則指向即將被運(yùn)行的任務(wù),因此用戶可在OSTaskSwHook()中對它們操作,以實(shí)現(xiàn)特殊的功能,當(dāng)然該函數(shù)也可定義為不做任何事的空函數(shù)。 從程序我們可以看出,要運(yùn)行最高優(yōu)先級的任務(wù),首先得找到該任務(wù)堆棧指針,然后將寄存器內(nèi)容及參數(shù)從堆棧中恢復(fù)到CPU 的寄存器中。
2.3.2 任務(wù)級上下文切換的實(shí)現(xiàn)函數(shù)OSCtxSw()
前面曾提過, 任務(wù)切換時使用了軟中斷, 并將中斷向量指向OSCtxSw(),因此該函數(shù)所要做的就是執(zhí)行任務(wù)級的任務(wù)切換。 其目的是為了保證CPU 永遠(yuǎn)運(yùn)行就緒表中優(yōu)先級最高的任務(wù)。 OSCtxSw()是任務(wù)調(diào)度函數(shù)OSSched()通過宏OS_TASK_SW()調(diào)用的,執(zhí)行的是多任務(wù)的調(diào)度功能:不僅要使高優(yōu)先級任務(wù)得以恢復(fù)運(yùn)行,還得將待切換出去的任務(wù)保存起來,兩者的差別也可以從程序代碼中比較出來:
_OSCtxSw:
CALL I$$SAVE
LDPK _OSTCBCur; OSTCBCur->OSTCBStkPtr = SP;
LAR AR3, _OSTCBCur
MAR *, AR3
SAR AR1, * , AR1_
OSIntCtxSw:
CALL _OSTaskSwHook;OSTaskSwHook();
LDPK _OSTCBHighRdy;OSTCBCur = OSTCBHighRdy;
BLDD _OSTCBHighRdy,#_OSTCBCur
LDPK _OSPrioHighRdy;OSPrioCur = OSPrioHighRdy;
BLDD _OSPrioHighRdy,#_OSPrioCur
LDPK _OSTCBHighRdy;SP=OSTCBHighRdy->OSTCBStkPtr;
LAR AR3, _OSTCBHighRdy
MAR *, AR3
LAR AR1, *
B I$$REST, AR1
顯然,對當(dāng)前任務(wù)相關(guān)內(nèi)容的保存、給當(dāng)前優(yōu)先級數(shù)據(jù)結(jié)構(gòu)賦值以及給當(dāng)前任務(wù)控制塊賦值都是OSStartHighRdy()所不具有的。
2.3.3 時鐘中斷服務(wù)程序的實(shí)現(xiàn)
OSTickISR()也是μC/OS -II 操作系統(tǒng)中要求用戶提供的匯編程序,其具體實(shí)現(xiàn)與中斷級上下文切換的實(shí)現(xiàn)有很大的關(guān)系, 它是時鐘中斷服務(wù)程序,主要調(diào)用函數(shù)OSTimeTick(),處理與系統(tǒng)時鐘相關(guān)的工作, 如將每個任務(wù)的等待時間減1、更新系統(tǒng)時間。 OSTickISR()具體代碼如下所示:
_OSTickISR:
CALL I$$SAVE
CALL _OSIntEnter
LAC _OSIntNesting; 保 存 堆 棧 指 針AR1 到 當(dāng) 前OSTCB 的
OSTCBStkPtr;
SUBK 1 BNZ L1
LDPK _OSTCBCur
LAR AR3, _OSTCBCur
MAR *, AR3
SAR AR1, * , AR1
L1: CALL _OSTimeTick
CALL _OSIntExit
BI$$REST,AR1
其中OSTimeTick()函數(shù)定時對所有的任務(wù)控制塊中的OSTCBDly減一,當(dāng)某任務(wù)的OSTCBDly 減為零時,就將其轉(zhuǎn)到就緒態(tài),以備運(yùn)行。 而OSIntExit()主要用于判別中斷的執(zhí)行是否使得更高優(yōu)先級的任務(wù)進(jìn)人就緒態(tài),如有,則進(jìn)行任務(wù)切換,否則返回。 至于時鐘中斷可由DSP 的定時器1 的周期計(jì)數(shù)器PRT 產(chǎn)生。
2.3.4 中斷級上下文切換的實(shí)現(xiàn)函數(shù)OSIntCtxSw()
與OSCtxSw()相比較,OSIntCtxSw()也是執(zhí)行任務(wù)切換的,但它執(zhí)行中斷級的任務(wù)切換。 不使用現(xiàn)成的OSCtxSw()進(jìn)行切換主要基于這樣的考慮:它是在中斷處理程序中調(diào)用的,類似于OSCtxSw()中保存寄存器的工作在進(jìn)人中斷時就做過了。 具體實(shí)現(xiàn)代碼參考函數(shù)OSCtxSw()代碼。
內(nèi)核移植選用三知公司的SZ-2407IV 作為測試平臺, 測試使用LED 顯示模塊和數(shù)字信號處理模塊。 本文設(shè)計(jì)了Task0(),Task1()兩個任務(wù),Task0()為LED 顯示任務(wù),Task1()為數(shù)字信號處理模塊,執(zhí)行一次DFT 算法,計(jì)算一個采樣點(diǎn)的DFT 值。
μC/OS-II 的Tick 時鐘是周期性中斷, 每1.66ms 觸發(fā)一次,Task0和Task1 在延時32 個Ticks 的情況下即20ms 切換一次LED 閃爍顯示一位。 最后觀測結(jié)果,得到了預(yù)期效果。
為了保證移植的成功并使系統(tǒng)可靠運(yùn)行, 除了要熟悉μC/OS-II和所用的處理器外,熟悉CC 編譯器C 開發(fā)環(huán)境也是移植能否成功的一個關(guān)鍵。 而且,μC/OS-II 在TMS320LF2407 上的移植成功只是第一步,今后還需要對μC/OS-II 的內(nèi)核進(jìn)行擴(kuò)展,例如添加TCP/IP 軟件包,以適應(yīng)網(wǎng)絡(luò)化的需求,使之真正成為一個可重用的開發(fā)平臺。
[1]Jean Labrosse.μC/OS-II, 源碼公開的實(shí)時嵌入式操作系統(tǒng)[M].邵貝貝,譯.北京:中國電力出版社,2001.
[2]TMS320C2x/C2xx/C5xx Optimizing C Compilaer User’s Guide[Z].Texas Instruments,1999.