實(shí)時(shí)操作系統mC/OS-II在A(yíng)T91上的移植
摘 要:本文介紹了嵌入式實(shí)時(shí)操作系統mC/OS-II的工作原理,并以AT91FR40162為例,重點(diǎn)討論了mC/OS-II在基于A(yíng)RM架構的AT91系列中的移植。最后給出了移植結果。
關(guān)鍵詞:嵌入式實(shí)時(shí)操作系統;AT91FR40162;mC/OS-II;移植
mC/OS-II內核工作原理
實(shí)時(shí)嵌入式操作系統mC/OS-II內核的工作原理如圖1所示。首先,在主程序中對操作系統進(jìn)行初始化,完成mC/OS-II所有變量和數據結構的初始化,包括任務(wù)控制塊(TCB)初始化,TCB優(yōu)先級表初始化,TCB鏈表初始化,事件控制塊(ECB)鏈表初始化以及空閑任務(wù)的創(chuàng )建等。
然后,根據應用程序的需要,用戶(hù)可以調用OSTaskCreate()函數創(chuàng )建多個(gè)任務(wù)(至少1個(gè))。該函數為新任務(wù)建立任務(wù)堆棧(OSTaskStkInit())以及初始化任務(wù)控制塊TCB(OS_ TCBInit())。
最后,通過(guò)調用OSStart()啟動(dòng)多任務(wù)調度。程序將跳到就緒表中優(yōu)先級最高的任務(wù)開(kāi)始執行。這里假設啟動(dòng)多任務(wù)調度前創(chuàng )建了一個(gè)任務(wù)Task1()。
程序進(jìn)入Task1()后,首先初始化時(shí)鐘和啟動(dòng)時(shí)鐘節拍源開(kāi)始計時(shí)。此節拍源給系統提供周期性的時(shí)鐘中斷信號,實(shí)現延時(shí)和超時(shí)確認。然后根據應用程序要求,完成該任務(wù)的基本功能。最后,調用OSTimeDly(),將自己掛起,即從就緒表中刪除。直到等待延時(shí)時(shí)間到,才將該任務(wù)恢復到就緒表中,并等待調度器的調度。
OSTimeDly()將任務(wù)掛起的同時(shí),為其做好延時(shí)記號,然后調用OS_Sched()進(jìn)行任務(wù)級的任務(wù)調度。若此時(shí)沒(méi)有任何任務(wù)進(jìn)入就緒態(tài),就切換到空閑任務(wù)。
當時(shí)鐘中斷來(lái)臨時(shí),系統進(jìn)入中斷服務(wù)程序OSTickISR()。系統把當前正在執行的任務(wù)掛起,保護現場(chǎng),進(jìn)行中斷處理OSTimeTick(),判斷有無(wú)任務(wù)延時(shí)到期,若有,則使該任務(wù)進(jìn)入就緒態(tài)。最后調用OSIntExit()進(jìn)行中斷級的任務(wù)調度,從而切換到優(yōu)先級最高的任務(wù),若沒(méi)有別的任務(wù)進(jìn)入就緒態(tài),則恢復現場(chǎng)繼續執行原任務(wù)。
AT91FR40162簡(jiǎn)介
AT91FR40162是ATMEL公司出品的一款基于A(yíng)RM7TDMI內核的AT91 16/32位微控制器,其核心為高性能的32位RISC體系結構,并具有高密度的16位指令集和極低的功耗。
ARM處理器共有7種運行模式,處理器模式可以通過(guò)軟件控制進(jìn)行切換,也可以通過(guò)外部中斷或異常處理過(guò)程進(jìn)行切換。在每一種處理器模式中有一組相應的寄存器組。任意時(shí)刻(也就是任意的處理器模式下),可見(jiàn)的寄存器包括15個(gè)通用寄存器(R0~R14)、一個(gè)或兩個(gè)狀態(tài)寄存器及程序計數器(PC)。
CPSR(當前程序狀態(tài)寄存器)可以在任何處理器模式下被訪(fǎng)問(wèn)。它包含了條件標志位、中斷禁止位、當前處理器模式標志以及其他的一些控制和狀態(tài)位。每一種處理器模式下都有一個(gè)專(zhuān)用的物理狀態(tài)寄存器,稱(chēng)為SPSR(備份程序狀態(tài)寄存器)。當特定的異常中斷發(fā)生時(shí),這個(gè)寄存器用于存放CPSR的內容。在異常中斷程序退出時(shí),可以用SPSR中保存的值來(lái)恢復CPSR。
mC/OS-II在
AT91FR40162上的移植
本文使用的內核是mC/OS-II v2.76,選用ADS1.2中的C編譯器。
整個(gè)移植過(guò)程主要分為兩個(gè)方面:與應用相關(guān)的mC/OS-II配置(OS_CFG.H,INCLUDES.H);與處理器相關(guān)的mC/OS-II移植(OS_CPU.H,OS_CPU_A.ASM,OS_CPU_C.C)。
OS_CPU.H
此文件中主要是定義了一些與處理器相關(guān)的常數、宏以及類(lèi)型。根據ADS1.2的編譯手冊,char型變量為8位,short型為16位,int型為32位,堆棧為32位寬。另外,v2.76版本中新增加了一個(gè)全局變量OSIntCtxSwFlag,如果需要中斷級的任務(wù)切換時(shí),就令OSIntCtxSwFlag=TRUE。
OS_CPU_C.C
在這里需要編寫(xiě)兩個(gè)函數:OSInitHookBegin()和OSTaskStkInit()。
OSInitHookBegin()在OSInit()中調用,用來(lái)初始化移植中出現的特殊變量。這里將OSIntCtxSwFlag初始化為0。
OSTaskStkInit()在OSTaskCreate()和OSTaskCreateExt()中調用,用來(lái)初始化任務(wù)的棧結構。圖2顯示了初始化后任務(wù)棧的結構。堆棧從上往下遞減。mC/OS-II規定任務(wù)工作在SVC模式下。另外,根據ATPCS規定,子程序間通過(guò)R0~R3傳遞參數,所以參數p_arg放在R0里。
與以往的版本不同,這里OSIntCtxSw()(由OSIntExit()調用)并不完成任務(wù)的切換工作,僅將OSIntCtxSwFlag變量置1,標志需要進(jìn)行任務(wù)切換。當OSIntExit()調用返回到ISR時(shí),檢查OSIntCtxSwFlag變量,如果為1,則跳到OS_IntCtxSw()函數執行任務(wù)切換。
OS_CPU_A.S
由于C語(yǔ)言不能對寄存器進(jìn)行直接操作,所以必須用匯編語(yǔ)言編寫(xiě)以下函數。
OSStartHighRdy()由OSStart()調用。該函數使就緒態(tài)任務(wù)中優(yōu)先級最高的任務(wù)開(kāi)始運行。注意開(kāi)始要將IRQ和FIQ中斷禁止,最后從堆棧彈出所有寄存器時(shí),必須按照OSTaskStkInit()中相反的順序彈出。
OSCtxSw()由OSSched()調用,完成任務(wù)級的任務(wù)切換。任務(wù)級的任務(wù)切換包括將當前任務(wù)在SVC模式下的寄存器壓入任務(wù)棧中,并且將新任務(wù)的堆棧彈出到SVC模式下的寄存器中。注意必須按照OSTaskStkInit()中任務(wù)棧的結構對任務(wù)棧進(jìn)行操作。
OS_CPU_SR_Save()用于關(guān)中斷,OS_CPU_SR_Restore()用于開(kāi)中斷。OS_CPU_SR_Save()將CPSR保存到R0中,通過(guò)將CPSR中I位和F位置1來(lái)禁止IRQ和FIQ中斷。OS_CPU_SR_Restore()只需將R0中保存的CPSR恢復即可。
OS_IntCtxSw()完成中斷級的任務(wù)切換。當檢查OSIntCtxSwFlag變量為1時(shí),就調用該函數。因為OS_IntCtxSw()是在ISR中被調用的,所以所有的處理器寄存器都已經(jīng)被正確地保存到了被中斷任務(wù)的堆棧中。
mC/OS-II 要求用戶(hù)提供一個(gè)周期性的時(shí)鐘源,來(lái)實(shí)現時(shí)間的延遲和超時(shí)功能。這里時(shí)鐘節拍設為100次每秒,使用定時(shí)器0來(lái)完成該任務(wù)。時(shí)鐘節拍中斷OSTickISR()代碼如下,此時(shí)系統進(jìn)入IRQ模式。
STMFD SP!, {R0-R3, R12, LR}
BL OSIntEnter
BL Tmr_TickISR_Handler
BL OSIntExit
LDR R0,addr_OSIntCtxSwFlag
LDR R1, [R0]
CMP R1, #1
BEQ OS_IntCtxSw
LDMFD SP!, {R0-R3,R12,LR}
SUBS PC, LR, #4
Tmr_TickISR_Handler是中斷處理程序,用C語(yǔ)言編寫(xiě)。如果是其他類(lèi)型的中斷,可以替換為相應的中斷處理程序。這里定時(shí)器0中斷處理程序要做的工作是首先清中斷源,即讀取TC_SR寄存器值,AIC_ICCR=0x00000010,然后告訴處理器中斷結束(向AIC_EOICR寫(xiě)數據),最后調用OSTimeTick()函數,對延時(shí)記號進(jìn)行處理。
定時(shí)器0的設置為:WAVE模式;TC_CMR中CPCTRG=1,表示RC比較將復位計數器并開(kāi)啟時(shí)鐘;TC_RC=計時(shí)時(shí)間;TC_IER=AT91C_TC_CPCS,允許RC比較中斷。
移植中要注意的問(wèn)題
由于各方面的原因,移植中編寫(xiě)的代碼不一定完全正確,需要進(jìn)行逐步調試。調試過(guò)程中,要善于根據具體現象來(lái)發(fā)現問(wèn)題所在。根據筆者的調試經(jīng)歷,總結了一些移植調試過(guò)程中要注意的問(wèn)題。
(1) 對mC/OS-II的內核機理要有充分理解??梢試L試對其內核進(jìn)行調試,這樣可以幫助自己從更深的層次來(lái)理解嵌入式實(shí)時(shí)操作系統。只有對mC/OS-II的內核有了清楚地認識,才能在移植過(guò)程中發(fā)現問(wèn)題的本質(zhì)。
(2) 對所使用的編譯器要有深刻細致的了解。由于A(yíng)DS1.2的C 編譯器有很多優(yōu)化編譯選項和流水處理選項,在處理內核編譯時(shí)很容易有沖突,所以,選擇優(yōu)化選項要慎重。加強對ADS1.2的C 編譯器的理解,可以節約代碼編寫(xiě)時(shí)間。
(3) 在移植過(guò)程中,最容易出問(wèn)題的就是堆棧處理。堆棧處理是操作系統移植的關(guān)鍵部分。先分析ARM系統自身在進(jìn)行現場(chǎng)保護時(shí)的堆棧處理的操作,然后模擬其過(guò)程。關(guān)鍵是要將需要的寄存器都保護到。由于我們在進(jìn)行任務(wù)切換的時(shí)候采用了系統函數來(lái)進(jìn)行現場(chǎng)保護,因此在堆棧初始化的時(shí)候,就應該按照這兩個(gè)函數的操作來(lái)對任務(wù)堆棧進(jìn)行初始化。
(4) 要詳細分析ARM系統自身處理中斷時(shí)的壓棧操作,必須將多余的信息從堆棧中清理干凈。如果對編譯器不熟悉,可以通過(guò)仔細調試中斷,來(lái)確定編譯器的具體操作。在對AT91FR40162的移植中,由于A(yíng)RM處理器有7種運行模式,每種運行模式下都有自己獨立的寄存器,所以在處理中斷的過(guò)程中,要注意運行模式的切換,避免寄存器的內容無(wú)法正確保存和恢復。
(5) 注意程序的返回地址。異常中斷發(fā)生時(shí),程序計數器PC所指的位置對各種不同的異常中斷是不同的,所以,返回地址也是不同的。需要根據不同的中斷類(lèi)型,確定不同的中斷返回地址偏移量,否則程序將跑飛。
結語(yǔ)
本方案經(jīng)過(guò)測試已證明移植成功。本文是以AT91FR40162為例,說(shuō)明mC/OS-II的移植,對于A(yíng)RM系列的處理器,只需稍加改動(dòng)就可以實(shí)現?!?/p>
參考文獻
1 邵貝貝等譯. 嵌入式實(shí)時(shí)操作系統mC/OS-II(第2版). 北京:北京航空航天大學(xué)出版社,2003
評論