μCOSII在Cortex-M3核ARM處理器上的移植 μCOSII在Cortex-M3核ARM處理器上的移植
更新于2009-03-31 14:47:51 文章出處:與非網(wǎng) 目前,,嵌入式技術(shù)已被廣泛應(yīng)用到汽車電子,、無線通信、數(shù)碼產(chǎn)品等各個(gè)領(lǐng)域,。嵌入式操作系統(tǒng)及嵌入式處理器技術(shù)發(fā)展迅猛,,嵌入式操作系統(tǒng)典型代表有μCOS —II、μClinux,、Winclow CE,、VxWorks等;嵌入式處理器包括ARM,、MIPS,、PowerPC等。隨著軟硬件技術(shù)的發(fā)展,,人們開始意識(shí)到基于嵌入式操作系統(tǒng)的程序開發(fā)模式的便利性及可靠性,,并且在程序開發(fā)過程中開始傾向于從傳統(tǒng)超循環(huán)開發(fā)模式轉(zhuǎn)向基于嵌入式操作系統(tǒng)的開發(fā)模式。 1 軟硬件開發(fā)環(huán)境及處理器介紹 1.1 軟件硬開發(fā)環(huán)境 本移植過程使用的軟件環(huán)境是RealView MDK開發(fā)套件,,此產(chǎn)品是ARM公司最新推出的針對(duì)各種嵌入式處理器的軟件開發(fā)工具,,該開發(fā)套件功能強(qiáng)大,包括了μVision3集成開發(fā)環(huán)境和 RealView編譯器。使用的硬件平臺(tái)是深圳英蓓特公司推出的全功能評(píng)估板STMl03V100,,其上所采用的處理器是ST意法半導(dǎo)體公司生產(chǎn)的32位哈佛結(jié)構(gòu)ARM處理器STM32F103VBT6,,該處理器內(nèi)置ARM公司最新的Cortex—M3核,并且具有非常豐富的片上資源,。 1.2 關(guān)于基于Cortex-M3的ARM處理器的介紹 基于Cortex—M3核的ARM處理器支持兩種模式,,分別稱為線程模式和處理模式。程序可以在系統(tǒng)復(fù)位時(shí)或中斷返回時(shí)兩種情況下進(jìn)入線程模式,,而處理模式只能通過中斷或異常的方式來進(jìn)入,。處于線程模式中代碼可以分別運(yùn)行在特權(quán)方式下和非特權(quán)方式下。處于處理模式中的代碼總是運(yùn)行在特權(quán)方式下,。運(yùn)行在特權(quán)方式下的代碼對(duì)系統(tǒng)資源具有完全訪問權(quán),,而運(yùn)行在非特權(quán)方式下的代碼對(duì)系統(tǒng)資源的訪問權(quán)受到一定限制。處理器可以運(yùn)行在Thumb狀態(tài)或Debug狀態(tài),。在指令流正常執(zhí)行期間,,處理器處于Thumb狀態(tài)。當(dāng)進(jìn)行程序調(diào)試時(shí),,指令流可以暫停執(zhí)行,,這時(shí)處理器處于Debug狀態(tài)。處理器有兩個(gè)獨(dú)立的堆棧指針,,分別稱為MSP和PSP,。系統(tǒng)復(fù)位時(shí)總是處于線程模式的特權(quán)方式下,并且默認(rèn)使用的堆棧指針是MSP,。本移植過程中假設(shè)任務(wù)總是運(yùn)行在線程模式的特權(quán)方式下且總是使用堆棧指針PSP,。 2 移植過程詳解 2.1 μCOS-II內(nèi)核介紹 μCOS—II是一個(gè)實(shí)時(shí)可剝奪型操作系統(tǒng)內(nèi)核,該操作系統(tǒng)支持最多64個(gè)任務(wù),,但每個(gè)任務(wù)的優(yōu)先級(jí)必須互不相同,,優(yōu)先級(jí)號(hào)小的任務(wù)比優(yōu)先級(jí)號(hào)大的任務(wù)具有更高的優(yōu)先級(jí),并且該操作系統(tǒng)總是調(diào)度優(yōu)先級(jí)最高的就緒態(tài)任務(wù)運(yùn)行,。此內(nèi)核的代碼是美國(guó)人Jean J.Labrosse用C語言編寫的,,具有很好的可移植性,其2.52版本通過了美國(guó)航天航空管理局的安全認(rèn)證,,可靠性非常高。文中所述的移植過程使用的就是該版本的源代碼,。 2.2 開始移植 μCOS—II v2.52的源代碼按照移植要求分為需要修改部分和不需要修改部分,。其中需要修改源代碼的文件包括頭文件OS_CPU.H、C語言文件OS_CPU.C以及匯編格式文件OS_CPU_A.ASM,。 2.2.1 修改頭文件OS_CPU.H 頭文件OS_CPU.H中需要修改的內(nèi)容有與編譯器相關(guān)的數(shù)據(jù)類型重定義部分和與處理器相關(guān)的少量代碼,。由于本移植過程中使用的是RealView編譯器,因此通過查閱此編譯器的相關(guān)說明文檔可以得到其所支持的基本數(shù)據(jù)類型,據(jù)此修改OS_CPU.H中與編譯器相關(guān)的數(shù)據(jù)類型重定義部分,。修改后代碼如下所示: 其中定義的數(shù)據(jù)類型OS_STK指出了處理器堆棧中的數(shù)據(jù)是32位的,,OS_CPU_SR指出了處理器狀態(tài)寄存器字長(zhǎng)也為32位。 頭文件中與處理器相關(guān)部分代碼包括臨界區(qū)訪問處理,、處理器堆棧增長(zhǎng)方向及任務(wù)切換宏定義,。臨界區(qū)代碼訪問涉及到全局中斷開關(guān)指令,由文獻(xiàn)可以得知關(guān)中斷和開中斷可以分別由指令CPSID i和CPSIE i實(shí)現(xiàn),,文中臨界段訪問處理如下: 其中INT_DIS()和INT_EN()分別對(duì)應(yīng)關(guān)中斷和開中斷處理過程,。 根據(jù)文獻(xiàn)可知文中所使用的處理器支持的堆棧為滿遞減方式,即堆棧的增長(zhǎng)方向是從內(nèi)存高地址向低地址方向遞減并且堆棧指針總是指向棧頂?shù)臄?shù)據(jù),。在頭文件OS_CPU.H中相應(yīng)代碼只須修改一條,,如下所示 #define OS_STK_GROWTH1 此定義中的1代表堆棧方向是向下遞減的。 頭文件OS_CPU.H中最后一個(gè)要修改的地方是任務(wù)切換宏定義,,μCOS—II內(nèi)核就是通過這個(gè)宏調(diào)用來觸發(fā)任務(wù)級(jí)的任務(wù)切換,。任務(wù)切換一般是通過陷阱或軟件中斷來實(shí)現(xiàn)的,在基于Cortex—M3核的處理器中支持一條稱為超級(jí)用戶調(diào)用的指令SVC,,此指令是ARM軟件中斷指令SWI的升級(jí)版,。此處的宏定義代碼修改為如下形式 #define OS_TASK_SW()OS_SVC() 其中OS_SVC()之中包含了SVC指令,它可以由嵌入?yún)R編的方式在C語言代碼中進(jìn)行定義,,如下所示 _asm void OS_SVC(void){SVCOx00} 以上代碼以嵌入?yún)R編的方式定義了一個(gè)輸入?yún)?shù)和返回值都為空的C語言函數(shù),,嵌入?yún)R編的格式在RealView編譯器的說明文檔中有詳細(xì)的說明。 2.2.2 修改C語言文件OS_CPU.C 根據(jù)文獻(xiàn)可知文件OS_CPU.C中有10個(gè)C語言函數(shù)需要編寫,,這些函數(shù)中唯一必要的函數(shù)是OSTaskStkInit,,其他9個(gè)函數(shù)必須聲明,但不一定要包含任何代碼,。為了簡(jiǎn)潔起見,,本移植過程只編寫了OSTaskStkInit,此函數(shù)的作用是把任務(wù)堆棧初始化成好像剛發(fā)生過中斷一樣,。要初始化堆棧首先必須了解微處理器在中斷發(fā)生前后的堆棧結(jié)構(gòu),,根據(jù)文獻(xiàn)易知微處理器在中斷發(fā)生前后的堆棧結(jié)構(gòu),并且可知寄存器xPSR,、PC,、LR、R12,、 R3,、R2、R1,、RO是中斷時(shí)由硬件自動(dòng)保存的,。初始化時(shí)需要注意的地方是xPSR,、PC和LR的初值,對(duì)于其他寄存器的初值沒有特別的要求,。xPSR 比特位是Thumb狀態(tài)位,,初始化時(shí)須置1,否則執(zhí)行代碼時(shí)會(huì)引起一個(gè)稱為Invstate的異常,,這是因?yàn)閮?nèi)置Cortex—M3核的微處理器只支持 Thumb和Thumb2指令集,。堆棧中PC和LR須初始化為任務(wù)的入口地址值,這樣才能在任務(wù)切換時(shí)跳轉(zhuǎn)到正確的地方開始執(zhí)行,。此函數(shù)可以用以下代碼來實(shí)現(xiàn) 2.2.3 修改匯編語言文件OS_CPU_A.ASM 匯編文件OS_CPU_A.ASM中需要編寫的函數(shù)分別為OSStartHighRdy,、OSCtxSw、OSIntCtxSw和 OSTickISR,。第一個(gè)函數(shù)的作用是啟動(dòng)多任務(wù)調(diào)度,,此函數(shù)只在操作系統(tǒng)開始調(diào)度任務(wù)前執(zhí)行一次,以后不再調(diào)用,。按照文獻(xiàn)中所述須將堆棧中的寄存器依次彈出,,然后執(zhí)行一條中斷返回指令來開始第一個(gè)用戶任務(wù)的調(diào)度。但基于Cortex—M3核的ARM處理器在執(zhí)行中斷返回指令時(shí)必須處于處理模式下,,否則將會(huì)引起內(nèi)存訪問異常,。當(dāng)系統(tǒng)上電啟動(dòng)時(shí)或程序重置后,處理器會(huì)進(jìn)入線程模式,,而要在函數(shù)OSStartHighRdy中執(zhí)行中斷返回指令就首先需要進(jìn)行模式轉(zhuǎn)換,,進(jìn)入處理模式,而進(jìn)行同步可控制模式轉(zhuǎn)換的途徑是超級(jí)用戶調(diào)用,,即通過SVC指令產(chǎn)生軟件中斷可轉(zhuǎn)換到處理模式,。實(shí)際上考慮到此函數(shù)只在啟動(dòng)多任務(wù)調(diào)度開始前被調(diào)用一次,并且第一次調(diào)度任務(wù)運(yùn)行時(shí)任務(wù)堆棧中除了xPSR,、PC和LR的初值以外,,其他寄存器的初值無關(guān)緊要。因此可以簡(jiǎn)化該函數(shù)的編寫,,只須從第一個(gè)任務(wù)的堆棧中取出該任務(wù)的首地址,,然后修改堆棧指針使其指向任務(wù)堆棧中內(nèi)存地址最高處,即相當(dāng)于拋棄任務(wù)堆棧中所有數(shù)據(jù),,最后根據(jù)取出的地址直接跳轉(zhuǎn)到任務(wù)入口地址處開始執(zhí)行,。這樣可以免去軟件中斷和模式切換,從而簡(jiǎn)化了對(duì)此函數(shù)的編寫,。需要說明的是在拋棄任務(wù)堆棧中所用數(shù)據(jù)的同時(shí)也將 xPSR的初值拋棄了,,但這并不影響第一個(gè)任務(wù)投人運(yùn)行,因?yàn)樵谔D(zhuǎn)到第一個(gè)任務(wù)運(yùn)行之前,,指令流是在Thumb狀態(tài)下正常執(zhí)行的,,xPSR已經(jīng)有了確定的值。此函數(shù)代碼如下所示 BX r0,;直接跳轉(zhuǎn)到第一個(gè)任務(wù)的入口地址 第二個(gè)匯編語言函數(shù)OSCtxSw是任務(wù)級(jí)的任務(wù)切換函數(shù),。若在任務(wù)執(zhí)行過程中有一個(gè)比當(dāng)前任務(wù)優(yōu)先級(jí)更高的任務(wù)進(jìn)入就緒態(tài),μCOS—II內(nèi)核就會(huì)啟動(dòng)OSCtxSw進(jìn)行任務(wù)切換,。該函數(shù)會(huì)保存當(dāng)前任務(wù)狀態(tài),,然后恢復(fù)那個(gè)優(yōu)先級(jí)更高的任務(wù)狀態(tài),使之投入運(yùn)行,。前述的宏定義#defineOS_TASK_SW()OS_SVC()中的OS_SVC()包含了SVC軟件中斷指令,,此中斷的中斷向量應(yīng)該設(shè)為函數(shù)OSCtxSw 的入口地址,即OSCtxSw是SVC指令產(chǎn)生中斷的中斷服務(wù)程序,,其源代碼如下 由于微處理器在進(jìn)入中斷時(shí)按堆棧增長(zhǎng)方向自動(dòng)順序保存了如下8個(gè)寄存器:xPSR,、PC、LR,、R12,、R3、R2,、R1,、R0,因此在程序中只須保存另外8個(gè)寄存器,,保存順序可以隨意,,但注意彈棧時(shí)要按照先進(jìn)后出的方式進(jìn)行。按照本文開頭的假定,,任務(wù)總是運(yùn)行在線程模式的特權(quán)方式下且總是使用堆棧指針PSP,。而中斷產(chǎn)生后,中斷服務(wù)程序?qū)⑻幱谔幚砟J较?,并且默認(rèn)使用的堆棧指針是MSP,。因此在保存堆棧指針的時(shí)候需要保存的是當(dāng)前任務(wù)的PSP。中斷返回前新任務(wù)的堆棧指針需要恢復(fù)到PSP中,。中斷返回使用如下指令 MOVrO,,#Oxfffffffd BXr0 其中立即數(shù)#0xfffffffd包含了返回信息,用這兩條指令可以使中斷返回時(shí)使用任務(wù)堆棧指針PSP,,返回后任務(wù)處于線程模式且使用任務(wù)堆棧指針PSP,。 第三個(gè)匯編語言函數(shù)OSIntCtxSw與OSCtxSw類似。若任務(wù)執(zhí)行過程中產(chǎn)生了中斷,,且中斷服務(wù)程序使得一個(gè)比當(dāng)前被中斷的任務(wù)具有更高優(yōu)先級(jí)的任務(wù)就緒時(shí),,μCOS—II內(nèi)核就會(huì)在中斷返回之前調(diào)用函數(shù)OSIntCtxSw。在此函數(shù)中不需要像任務(wù)級(jí)任務(wù)切換函數(shù)那樣保存當(dāng)前任務(wù)狀態(tài),,因?yàn)楫?dāng)前任務(wù)已經(jīng)被中斷,,在進(jìn)入中斷服務(wù)程序的時(shí)候任務(wù)狀態(tài)已被保存,。其源代碼與函數(shù)OSctxSw中保存當(dāng)前任務(wù)堆棧PSP指令以后部分相同,此處不再列出,。 第4個(gè)匯編語言函數(shù)OSTickISR是系統(tǒng)時(shí)鐘節(jié)拍的中斷服務(wù)函數(shù),。處理器STM32F103VBT6中有一個(gè)專用系統(tǒng)時(shí)鐘節(jié)拍定時(shí)器SysTick,本移植過程使用此定時(shí)器產(chǎn)生每100 ms一次的時(shí)鐘節(jié)拍中斷,。此函數(shù)源代碼如下 3 程序開發(fā)模式討論 傳統(tǒng)應(yīng)用程序開發(fā)模式稱為超循環(huán)模式,,即通常主程序是由C語言中的for語句或while語句構(gòu)成的一個(gè)無限循環(huán),程序在此循環(huán)中檢測(cè)事件的發(fā)生,,從而轉(zhuǎn)向不同的任務(wù),。這種程序開發(fā)模式有兩個(gè)主要的不足之處。首先從程序維護(hù)和可靠性的角度來看,,所有任務(wù)都需要程序開發(fā)人員來進(jìn)行全局性的維護(hù),,當(dāng)系統(tǒng)變得龐大和復(fù)雜時(shí),任務(wù)的維護(hù)會(huì)變得非常麻煩,,同時(shí)程序的可靠性也受到影響,。其次,從任務(wù)級(jí)響應(yīng)時(shí)間來看,,這個(gè)時(shí)間是不確定的,,因?yàn)槌绦蛟谘h(huán)體中檢測(cè)事件發(fā)生的位置是固定的,但事件的發(fā)生是隨機(jī)的,,因此從事件發(fā)生到程序檢測(cè)到事件發(fā)生這段時(shí)間也是不確定的,。 在基于嵌入式操作系統(tǒng)的應(yīng)用程序開發(fā)過程中,應(yīng)用程序開發(fā)人員只需關(guān)心各個(gè)任務(wù)本身,,而任務(wù)調(diào)度由操作系統(tǒng)代勞,。以下的例子說明了基于μCOS—II嵌入式操作系統(tǒng)的應(yīng)用程序開發(fā)模式 其中函數(shù)SysInit的作用是根據(jù)具體應(yīng)用對(duì)處理器芯片進(jìn)行必要的初始化,例如對(duì)系統(tǒng)的時(shí)鐘分配以及通用輸入輸出端口配置,。函數(shù)OSInit是 μCOS—II操作系統(tǒng)的內(nèi)核初始化程序,。第一個(gè)OSTaskCreate函數(shù)創(chuàng)建了任務(wù)Taskl,此任務(wù)的入口地址是Taskl,,優(yōu)先級(jí)是0,。第二個(gè) OSTaskCreate函數(shù)創(chuàng)建了任務(wù)Task2,此任務(wù)的入口地址是Task2,,優(yōu)先級(jí)是1,。函數(shù)OSTaskCrate還會(huì)將其創(chuàng)建的任務(wù)置于就緒態(tài)。文獻(xiàn)敘述了函數(shù)OSTa-skCreate的各個(gè)參數(shù)的含義,。函數(shù)OSStart用于啟動(dòng)多任務(wù)調(diào)度,。OSTimeDly是μCOS—II內(nèi)核提供的系統(tǒng)調(diào)用函數(shù),用于延時(shí)或定時(shí),,這里的參數(shù)5表示延時(shí)5個(gè)時(shí)鐘節(jié)拍,。應(yīng)用程序開發(fā)人員需要做的就是通過調(diào)用μCOS—II內(nèi)核提供的任務(wù)創(chuàng)建函數(shù) OSTaskCreate將編寫好的任務(wù)程序交給操作系統(tǒng)管理,。 該例中在調(diào)用OSStart后,操作系統(tǒng)發(fā)現(xiàn)任務(wù)Taskl的優(yōu)先級(jí)最高,,于是操作系統(tǒng)就調(diào)度任務(wù)Taskl使其投入運(yùn)行,,而任務(wù)Task2暫時(shí)不能獲得處理器的使用權(quán)。任務(wù)Taskl首先點(diǎn)亮一個(gè)LED,,然后延時(shí)一段時(shí)間,當(dāng)運(yùn)行到OSTimeDly處時(shí),,該任務(wù)被掛起而處于等待狀態(tài),,此時(shí)任務(wù) Task2成為優(yōu)先級(jí)最高的就緒態(tài)任務(wù),于是操作系統(tǒng)調(diào)度Task2運(yùn)行,。當(dāng)5個(gè)時(shí)鐘節(jié)拍的延時(shí)時(shí)間結(jié)束時(shí),,系統(tǒng)時(shí)間節(jié)拍中斷服務(wù)子程序會(huì)重新將任務(wù) Taskl置于就緒狀態(tài),此時(shí)任務(wù)Taskl再一次成為優(yōu)先級(jí)最高的就緒態(tài)任務(wù),,于是操作系統(tǒng)保存任務(wù)Task2的狀態(tài),,并恢復(fù)任務(wù)Taskl的狀態(tài)使其又一次獲得處理器的使用權(quán)。此后程序執(zhí)行過程將重復(fù)上述步驟,??梢钥吹剑谶@個(gè)例子中的現(xiàn)象是某個(gè)LED燈不停的閃爍,。 μCOS—II操作系統(tǒng)內(nèi)核是實(shí)時(shí)可剝奪型的,,這意味著在任務(wù)執(zhí)行過程中或中斷服務(wù)子程序中,一旦有一個(gè)新的更高優(yōu)先級(jí)的任務(wù)就緒,,內(nèi)核將立刻調(diào)度此新任務(wù)運(yùn)行,,這說明響應(yīng)任務(wù)的時(shí)間是即刻的、確定的,。 綜上所述,,基于嵌入式操作系統(tǒng)的應(yīng)用程序開發(fā)過程相對(duì)于以往傳統(tǒng)應(yīng)用程序開發(fā)大為簡(jiǎn)化而且任務(wù)級(jí)響應(yīng)時(shí)間也得到最優(yōu)化。 4 結(jié)束語 通過將移植過程中修改的μCOS—II內(nèi)核代碼與上述例子中的應(yīng)用程序代碼在μVision3集成開發(fā)環(huán)境中編輯整合后進(jìn)行編譯,、鏈接并且下載到目標(biāo)硬件平臺(tái)進(jìn)行長(zhǎng)時(shí)間觀察,,發(fā)現(xiàn)LED不停的閃爍,說明本移植過程是成功的 |
|