版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
嵌入式系統(tǒng)設(shè)計(jì)與實(shí)例開(kāi)發(fā)——ARM與C/OS-Ⅱ第五講實(shí)時(shí)嵌入式操作系統(tǒng)C/OS-Ⅱ的移植移植:程序或應(yīng)用軟件從一個(gè)系統(tǒng)平臺(tái)移動(dòng)另一個(gè)系統(tǒng)平臺(tái),其功能、結(jié)構(gòu)、執(zhí)行結(jié)果保持不變。移植的目的:1、硬件平臺(tái)的升級(jí)2、實(shí)現(xiàn)軟件重用3、實(shí)現(xiàn)軟件/硬件并行設(shè)計(jì)移植的要求:1、移植對(duì)象具有硬件無(wú)關(guān)性2、移植對(duì)象具有系統(tǒng)無(wú)關(guān)性3、移植對(duì)象采用標(biāo)準(zhǔn)語(yǔ)言編程一、移植的概念和目的二、嵌入式操作系統(tǒng)的移植——μC/OS-IIμC/OS-II的軟硬件體系結(jié)構(gòu)μC/OS-II的移植需要滿足的要求μC/OS-II移植的主要工作BSP的概念及應(yīng)用2.1μC/OS-II的軟硬件體系結(jié)構(gòu)
2.2μC/OS-II的移植需要滿足以下要求(1)處理器的C編譯器可以產(chǎn)生可重入代碼;(2)可以使用C調(diào)用進(jìn)入和退出CriticalCode(臨界區(qū)代碼);(3)處理器必須支持硬件中斷,并且需要一個(gè)定時(shí)中斷源;(4)處理器需要能夠容納一定數(shù)據(jù)的硬件堆棧;(5)處理器需要有能夠在CPU寄存器與內(nèi)存和堆棧交換數(shù)據(jù)的指令。
打開(kāi)/關(guān)閉中斷在
COS-II中,可以通過(guò):OS_ENTER_CRITICAL()OS_EXIT_CRITICAL()宏來(lái)控制系統(tǒng)關(guān)閉或者打開(kāi)中斷。這需要處理器的支持。在處理器上,可以設(shè)置相應(yīng)的寄存器來(lái)關(guān)閉或者打開(kāi)系統(tǒng)的所有中斷。處理器支持中斷并且
能產(chǎn)生定時(shí)中斷
COS-II是通過(guò)處理器產(chǎn)生的定時(shí)器的中斷來(lái)實(shí)現(xiàn)多任務(wù)之間的調(diào)度的。CortexM3可以產(chǎn)生定時(shí)器中斷。本系統(tǒng)工作在80MHz的主頻下,PCLK0=PCLK1=PCLK2=40MHz.定時(shí)器的中斷的頻率為50Hz。也就是系統(tǒng)的響應(yīng)時(shí)間為20ms。處理器支持硬件堆棧
COS-II進(jìn)行任務(wù)調(diào)度的時(shí)候,會(huì)把當(dāng)前任務(wù)的CPU寄存器存放到此任務(wù)的堆棧中,然后,再?gòu)牧硪粋€(gè)任務(wù)的堆棧中恢復(fù)原來(lái)的工作寄存器,繼續(xù)運(yùn)行另一個(gè)任務(wù)。所以,寄存器的入棧和出棧是
COS-II多任務(wù)調(diào)度的基礎(chǔ)。處理器中有專(zhuān)門(mén)的指令處理堆棧,可以靈活的使用堆棧。移植
COS-II滿足的條件處理器的C編譯器能產(chǎn)生可重入代碼在程序中可以打開(kāi)或者關(guān)閉中斷處理器支持中斷,并且能產(chǎn)生定時(shí)中斷(通常在10—1000Hz之間)本系統(tǒng)選擇50Hz。處理器支持能夠容納一定量數(shù)據(jù)的硬件堆棧處理器有將堆棧指針和其他CPU寄存器存儲(chǔ)和讀出到堆棧(或者內(nèi)存)的指令2.3μC/OS-II移植的主要工作處理器和編譯器相關(guān)代碼μC/OS-II的BSP的編寫(xiě)
移植文件及目錄示例可以采用如下目錄結(jié)構(gòu)存放移植的文件:所有的移植實(shí)例放在用戶硬盤(pán)的\SOFTWARE\μCOS-Ⅱ目錄下。各個(gè)微處理器或微控制器的移植源代碼必須在以下兩個(gè)或三個(gè)文件中找到:OS_CPU.H,OS_CPU_C.C,OS_CPU_A.ASM。匯編語(yǔ)言文件OS_CPU_A.ASM是可選擇的,因?yàn)槟承〤編譯器允許用戶在C語(yǔ)言中插入?yún)R編語(yǔ)言,所以用戶可以將所需的匯編語(yǔ)言代碼直接放到OS_CPU_C.C中。放置移植實(shí)例的目錄決定于用戶所用的處理器,例如在下面的表中所示的放置不同移植實(shí)例的目錄結(jié)構(gòu)。注意,各個(gè)目錄雖然針對(duì)完全不同的目標(biāo)處理器,但都包括了相同的文件名。Intel/AMD80186\SOFTWARE\uCOS-II\Ix86S\OS_CPU.H\OS_CPU_A.ASM\OS_CPU_C.C\SOFTWARE\uCOS-II\Ix86L\OS_CPU.H\OS_CPU_A.ASM\OS_CPU_C.CMotorola68HC11\SOFTWARE\uCOS-II\68HC11\OS_CPU.H\OS_CPU_A.ASM\OS_CPU_C.C
COS-II在ARM7上的移植 所謂移植,是指使一個(gè)實(shí)時(shí)操作系統(tǒng)能夠在某個(gè)微處理器平臺(tái)上運(yùn)行。
COS-II的主要代碼都是由標(biāo)準(zhǔn)的C語(yǔ)言寫(xiě)成的,移植方便。但仍需要用C和匯編語(yǔ)言寫(xiě)一些與處理器相關(guān)的代碼,這是因?yàn)棣藽/OS-Ⅱ在讀寫(xiě)處理器寄存器時(shí)只能通過(guò)匯編語(yǔ)言來(lái)實(shí)現(xiàn)。移植工作uC/OS-II實(shí)際上可以簡(jiǎn)單地看作是一個(gè)多任務(wù)的調(diào)度器,在這個(gè)任務(wù)調(diào)度器之上完善并添加了和多任務(wù)操作系統(tǒng)相關(guān)的一些系統(tǒng)服務(wù),如信號(hào)量、郵箱等。它的90%的代碼都是用C語(yǔ)言寫(xiě)的,因此只要有相應(yīng)的C語(yǔ)言編譯器,基本上就可以直接移植到特定處理器上,這也是uC/OS-II具有良好的可移植性的原因。移植工作的絕大部分都集中在多任務(wù)切換的實(shí)現(xiàn)上,因?yàn)檫@部分代碼主要是用來(lái)保存和恢復(fù)處理器現(xiàn)場(chǎng)(即相關(guān)寄存器),因此不能用C語(yǔ)言,只能使用特定的處理器匯編語(yǔ)言完成。uC/OS-II的全部源代碼量大約是6000-7000行,一共有15個(gè)文件。將uC/OS-II移植到ARM處理器上,需要完成的工作也非常簡(jiǎn)單,只需要修改三個(gè)和ARM體系結(jié)構(gòu)相關(guān)的文件,代碼量大約是500行。移植工作 如果處理器和編譯器滿足了μC/OS-Ⅱ的要求,并且已經(jīng)有了必要工具。移植工作包括以下幾個(gè)內(nèi)容:(1)用#define設(shè)置一些常量的值(OS_CPU.H)(2)聲明10個(gè)數(shù)據(jù)類(lèi)型(OS_CPU.H)(3)用#define聲明三個(gè)宏(OS_CPU.H)(4)用C語(yǔ)言編寫(xiě)六個(gè)簡(jiǎn)單的函數(shù)(OS_CPU_C.C)(5)編寫(xiě)四個(gè)匯編語(yǔ)言函數(shù)(OS_CPU_A.ASM)1、OS_CPU.H
(1)數(shù)據(jù)類(lèi)型定義
這部分的修改是和所用的編譯器相關(guān)的,不同的編譯器會(huì)使用不同的字節(jié)長(zhǎng)度來(lái)表示同一數(shù)據(jù)類(lèi)型,比如int,同樣在x86平臺(tái)上,如果用GNU的gcc編譯器,則編譯為4bytes,而使用MSVC++則編譯為2bytes。我們這里使用的是GNU的arm-elf-gcc,這是一個(gè)免費(fèi)并且開(kāi)放源碼的編譯器。相關(guān)的數(shù)據(jù)類(lèi)型的定義如下:程序清單 OS_CPU.H.#ifdefOS_CPU_GLOBALS#defineOS_CPU_EXT#else#defineOS_CPU_EXTextern#endif1、OS_CPU.H
/**************數(shù)據(jù)類(lèi)型*****************************(與編譯器相關(guān))**/***************************************************typedefunsignedcharBOOLEAN;typedefunsignedcharINT8U;/*無(wú)符號(hào)8位整數(shù)*/typedefsignedcharINT8S;/*有符號(hào)8位整數(shù)*/typedefunsignedintINT16U;/*無(wú)符號(hào)16位整數(shù)*/typedefsignedintINT16S;/*有符號(hào)16位整數(shù)*/typedefunsignedlongINT32U;/*無(wú)符號(hào)32位整數(shù)*/typedefsignedlongINT32S;/*有符號(hào)32位整數(shù)*/typedeffloatFP32;/*單精度浮點(diǎn)數(shù)*/typedefdoubleFP64;/*雙精度浮點(diǎn)數(shù)*/1、OS_CPU.H
堆棧單位
因?yàn)樘幚砥鳜F(xiàn)場(chǎng)的寄存器在任務(wù)切換時(shí)都將會(huì)保存在當(dāng)前運(yùn)行任務(wù)的堆棧中,所以O(shè)S_STK數(shù)據(jù)類(lèi)型應(yīng)該是和處理器的寄存器長(zhǎng)度一致的。typedefunsignedintOS_STK;/*堆棧入口寬度為16位*/堆棧增長(zhǎng)方向
堆棧由高地址向低地址增長(zhǎng),這個(gè)也是和編譯器有關(guān)的,當(dāng)進(jìn)行函數(shù)調(diào)用時(shí),入口參數(shù)和返回地址一般都會(huì)保存在當(dāng)前任務(wù)的堆棧中,編譯器的編譯選項(xiàng)和由此生成的堆棧指令就會(huì)決定堆棧的增長(zhǎng)方向。#defineOS_STK_GROWTH1/*定義堆棧的增長(zhǎng)方向 :1=向下,0=向上*/1、OS_CPU.H
(2)宏定義 包括開(kāi)關(guān)中斷的宏定義,以及進(jìn)行任務(wù)切換的宏定義。/****************與處理器相關(guān)的代碼*******************/#defineOS_ENTER_CRITICAL()???/*禁止中斷*/#defineOS_EXIT_CRITICAL()???/*允許中斷*/#defineOS_TASK_SW()??? 1、OS_CPU.H
OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()
方法1 執(zhí)行這兩個(gè)宏的第一個(gè)也是最簡(jiǎn)單的方法是在OS_ENTER_CRITICAL()中調(diào)用處理器指令來(lái)禁止中斷,以及在OS_EXIT_CRITICAL()中調(diào)用允許中斷指令。1、OS_CPU.H
缺點(diǎn):如果在禁止中斷的情況下調(diào)用μC/OS-Ⅱ函數(shù),從μC/OS-Ⅱ函數(shù)返回的時(shí)候要求中斷狀態(tài)還是禁止時(shí)的狀態(tài)。在這種情況下,這種執(zhí)行方法可能是不夠的。方法2 執(zhí)行OS_ENTER_CRITICAL()的第二個(gè)方法是先將中斷禁止?fàn)顟B(tài)保存到堆棧中,然后禁止中斷。而執(zhí)行OS_EXIT_CRITICAL()的時(shí)候只是從堆棧中恢復(fù)中斷狀態(tài)。如果用這個(gè)方法的話,不管用戶是在中斷禁止還是允許的情況下調(diào)用μC/OS-Ⅱ服務(wù),在整個(gè)調(diào)用過(guò)程中都不會(huì)改變中斷狀態(tài)。1、OS_CPU.H
舉例:方法1:#defineOS_ENTER_CRITICAL()asmCLI#defineOS_EXIT_CRITICAL()asmSTI CLI和SCI指令都會(huì)在兩個(gè)時(shí)鐘周期內(nèi)被馬上執(zhí)行(總共為四個(gè)周期)。為了保持中斷狀態(tài),用戶需要用下面的方法來(lái)執(zhí)行宏:1、OS_CPU.H
方法2:#defineOS_ENTER_CRITICAL()asmPUSHF;CLI#defineOS_EXIT_CRITICAL()asmPOPF 在這種情況下,OS_ENTER_CRITICAL()需要12個(gè)時(shí)鐘周期,而OS_EXIT_CRITICAL()需要另外的8個(gè)時(shí)鐘周期(總共有20個(gè)周期)。1、OS_CPU.H
(3)OS_STK_GROWTH 絕大多數(shù)的微處理器和微控制器的堆棧是從上往下長(zhǎng)的。但是某些處理器是用另外一種方式工作的。μC/OS-Ⅱ被設(shè)計(jì)成兩種情況都可以處理,只要在結(jié)構(gòu)常量OS_STK_GROWTH中指定堆棧的生長(zhǎng)方式(如下所示)就可以了 置OS_STK_GROWTH為0表示堆棧從下往上長(zhǎng)。 置OS_STK_GROWTH為1表示堆棧從上往下長(zhǎng)。1、OS_CPU.H
(4)OS_TASK_SW() OS_TASK_SW()是一個(gè)宏,它是在μC/OS-Ⅱ從低優(yōu)先級(jí)任務(wù)切換到最高優(yōu)先級(jí)任務(wù)時(shí)被調(diào)用的。OS_TASK_SW()總是在任務(wù)級(jí)代碼中被調(diào)用的。另一個(gè)函數(shù)OSIntExit()被用來(lái)在ISR使得更高優(yōu)先級(jí)任務(wù)處于就緒狀態(tài)時(shí),執(zhí)行任務(wù)切換功能。任務(wù)切換只是簡(jiǎn)單的將處理器寄存器保存到將被掛起的任務(wù)的堆棧中,并將更高優(yōu)先級(jí)的任務(wù)從堆棧中恢復(fù)出來(lái)。#defineOS_TASK_SW()OSCtxSw()2、OS_CPU_C.C
2、OS_CPU_C.C
μC/OS-Ⅱ的移植實(shí)例要求用戶編寫(xiě)六個(gè)簡(jiǎn)單的C函數(shù): OSTaskStkInit() OSTaskCreateHook() OSTaskDelHook() OSTaskSwHook() OSTaskStatHook() OSTimeTickHook() 唯一必要的函數(shù)是OSTaskStkInit(),其它五個(gè)函數(shù)必須聲明但沒(méi)必要包含代碼。2、OS_CPU_C.C
任務(wù)堆棧初始化
這里涉及到任務(wù)初始化時(shí)的一個(gè)堆棧設(shè)計(jì),也就是在堆棧增長(zhǎng)方向上如何定義每個(gè)需要保存的寄存器位置,在ARM體系結(jié)構(gòu)下,任務(wù)堆??臻g由高至低依次將保存著pc、lr、r12、r11、r10、…r1、r0、CPSR、SPSR。低地址pc lr R12 R11 … ... R1 R0 CPSR SPSR 增長(zhǎng)方向高地址2、OS_CPU_C.C
2、OS_CPU_C.C
這里需要說(shuō)明兩點(diǎn):一是當(dāng)前任務(wù)堆棧初始化完成后,OSTaskStkInit返回新的堆棧指針stk,在OSTaskCreate()執(zhí)行時(shí)將會(huì)調(diào)用OSTaskStkInit的初始化過(guò)程,然后通過(guò)OSTCBInit()函數(shù)調(diào)用,將返回的sp指針保存到該任務(wù)的TCB塊中。二是初始狀態(tài)的堆棧其實(shí)是模擬了一次中斷發(fā)生后的堆棧結(jié)構(gòu),因?yàn)槿蝿?wù)被創(chuàng)建后并不是直接就獲得執(zhí)行的,而是通過(guò)OSSched()函數(shù)進(jìn)行調(diào)度分配,滿足執(zhí)行條件后才能獲得執(zhí)行的。為了使這個(gè)調(diào)度簡(jiǎn)單一致,就預(yù)先將該任務(wù)的pc指針和返回地址lr都指向函數(shù)入口,以便被調(diào)度時(shí)從堆棧中恢復(fù)剛開(kāi)始運(yùn)行時(shí)的處理器現(xiàn)場(chǎng)。2、OS_CPU_C.C
系統(tǒng)hook函數(shù)
此外,在這個(gè)文件里面還需要實(shí)現(xiàn)幾個(gè)操作系統(tǒng)規(guī)定的hook函數(shù),如下:OSSTaskCreateHook()OSTaskDelHook()OSTaskSwHook()OSTaskStatHook()OSTimeTickHook() 如果沒(méi)有特殊需求,則只需要簡(jiǎn)單地將它們都實(shí)現(xiàn)為空函數(shù)就可以了。3、OS_CPU_A.ASM
μC/OS-Ⅱ的移植實(shí)例要求用戶編寫(xiě)四個(gè)簡(jiǎn)單的匯編語(yǔ)言函數(shù): OSStartHighRdy() OSCtxSw() OSIntCtxSw() OSTickISR() 如果用戶的編譯器支持插入?yún)R編語(yǔ)言代碼的話,用戶就可以將所有與處理器相關(guān)的代碼放到OS_CPU_C.C文件中,而不必再擁有一些分散的匯編語(yǔ)言文件。3、OS_CPU_A.ASM
(1)OSStartHighRdy()
此函數(shù)是在OSStart()多任務(wù)啟動(dòng)之后,負(fù)責(zé)從最高優(yōu)先級(jí)任務(wù)的TCB控制塊中獲得該任務(wù)的堆棧指針sp,通過(guò)sp依次將cpu現(xiàn)場(chǎng)恢復(fù),這時(shí)系統(tǒng)就將控制權(quán)交給用戶創(chuàng)建的該任務(wù)進(jìn)程,直到該任務(wù)被阻塞或者被其他更高優(yōu)先級(jí)的任務(wù)搶占cpu。該函數(shù)僅僅在多任務(wù)啟動(dòng)時(shí)被執(zhí)行一次,用來(lái)啟動(dòng)第一個(gè),也就是最高優(yōu)先級(jí)的任務(wù)執(zhí)行,之后多任務(wù)的調(diào)度和切換就是由OSCtxSw()函數(shù)來(lái)實(shí)現(xiàn)。3、OS_CPU_A.ASM
voidOSStartHighRdy(void){CalluserdefinableOSTaskSwHook();Getthestackpointerofthetasktoresume:Stackpointer=OSTCBHighRdy->OSTCBStkPtr;OSRunning=TRUE;Restoreallprocessorregistersfromthenewtask'sstack;Executeareturnfrominterruptinstruction;} OSStartHighRdy()必須調(diào)用OSTaskSwHook(),OSTaskSwHook()可以通過(guò)檢查OSRunning來(lái)知道是OSStartHighRdy()在調(diào)用它(OSRunning為FALSE)還是正常的任務(wù)切換在調(diào)用它(OSRunning為T(mén)RUE).3、OS_CPU_A.ASM
(2)OSCtxSw()
任務(wù)級(jí)的上下文切換,它是當(dāng)任務(wù)因?yàn)楸蛔枞鲃?dòng)請(qǐng)求cpu調(diào)度時(shí)被執(zhí)行,由于此時(shí)的任務(wù)切換都是在非異常模式下進(jìn)行的,因此區(qū)別于中斷級(jí)別的任務(wù)切換。它的工作是先將當(dāng)前任務(wù)的cpu現(xiàn)場(chǎng)保存到該任務(wù)堆棧中,然后獲得最高優(yōu)先級(jí)任務(wù)的堆棧指針,從該堆棧中恢復(fù)此任務(wù)的cpu現(xiàn)場(chǎng),使之繼續(xù)執(zhí)行。這樣就完成了一次任務(wù)切換。3、OS_CPU_A.ASM
voidOSCtxSw(void){
保存處理器寄存器;
將當(dāng)前任務(wù)的堆棧指針保存到當(dāng)前任務(wù)的OS_TCB中:OSTCBCur->OSTCBStkPtr=Stackpointer;
調(diào)用用戶定義的OSTaskSwHook();OSTCBCur=OSTCBHighRdy; OSPrioCur=OSPrioHighRdy;得到需要恢復(fù)的任務(wù)的堆棧指針:Stackpointer=OSTCBHighRdy->OSTCBStkPtr;
將所有處理器寄存器從新任務(wù)的堆棧中恢復(fù)出來(lái);
執(zhí)行中斷返回指令;}3、OS_CPU_A.ASM
(3)OSIntCtxSw()
中斷級(jí)的任務(wù)切換,它是在時(shí)鐘中斷ISR(中斷服務(wù)例程)中發(fā)現(xiàn)有高優(yōu)先級(jí)任務(wù)等待的時(shí)鐘信號(hào)到來(lái),則需要在中斷退出后并不返回被中斷任務(wù),而是直接調(diào)度就緒的高優(yōu)先級(jí)任務(wù)執(zhí)行。這樣做的目的主要是能夠盡快地讓高優(yōu)先級(jí)的任務(wù)得到響應(yīng),保證系統(tǒng)的實(shí)時(shí)性能。它的原理基本上與任務(wù)級(jí)的切換相同,但是由于進(jìn)入中斷時(shí)已經(jīng)保存過(guò)了被中斷任務(wù)的cpu現(xiàn)場(chǎng),因此這里就不用再進(jìn)行類(lèi)似的操作,只需要對(duì)堆棧指針做相應(yīng)的調(diào)整。3、OS_CPU_A.ASM
voidOSIntCtxSw(void){
調(diào)整堆棧指針來(lái)去掉在調(diào)用:OSIntExit(),OSIntCtxSw()過(guò)程中壓入堆棧的多余內(nèi)容;
將當(dāng)前任務(wù)堆棧指針保存到當(dāng)前任務(wù)的OS_TCB中:OSTCBCur->OSTCBStkPtr=堆棧指針;
調(diào)用用戶定義的OSTaskSwHook();OSTCBCur=OSTCBHighRdy;OSPrioCur=OSPrioHighRdy;
得到需要恢復(fù)的任務(wù)的堆棧指針:
堆棧指針=OSTCBHighRdy->OSTCBStkPtr;
將所有處理器寄存器從新任務(wù)的堆棧中恢復(fù)出來(lái);
執(zhí)行中斷返回指令;}3、OS_CPU_A.ASM
(4)OSTickISR()
時(shí)鐘中斷處理函數(shù),它的主要任務(wù)是負(fù)責(zé)處理時(shí)鐘中斷,調(diào)用系統(tǒng)實(shí)現(xiàn)的OSTimeTick函數(shù),如果有等待時(shí)鐘信號(hào)的高優(yōu)先級(jí)任務(wù),則需要在中斷級(jí)別上調(diào)度其執(zhí)行。其他相關(guān)的兩個(gè)函數(shù)是OSIntEnter()和OSIntExit(),都需要在ISR中執(zhí)行。 用戶必須在開(kāi)始多任務(wù)調(diào)度后(即調(diào)用OSStart()后)允許時(shí)鐘節(jié)拍中斷。3、OS_CPU_A.ASM
3、OS_CPU_A.ASM
voidOSTickISR(void){保存處理器寄存器;調(diào)用OSIntEnter()或者直接將OSIntNesting加1;調(diào)用OSTimeTick();調(diào)用OSIntExit();恢復(fù)處理器寄存器;執(zhí)行中斷返回指令;}(5)ARMEnableInt()&ARMDisableInt() 分別是退出臨界區(qū)和進(jìn)入臨界區(qū)的宏指令實(shí)現(xiàn)。主要用于在進(jìn)入臨界區(qū)之前關(guān)閉中斷,在退出臨界區(qū)的時(shí)候恢復(fù)原來(lái)的中斷狀態(tài)。它的實(shí)現(xiàn)比較簡(jiǎn)單,可以采用方法1直接開(kāi)關(guān)中斷來(lái)實(shí)現(xiàn),也可以采用方法2通過(guò)保存關(guān)閉/恢復(fù)中斷屏蔽位來(lái)實(shí)現(xiàn)。例:C/OS-II在S3C44B0X上的移植設(shè)置OS_CPU.H中與處理器和編譯器相關(guān)的代碼用C語(yǔ)言編寫(xiě)六個(gè)操作系統(tǒng)相關(guān)的函數(shù)(OS_CPU_C.C)用匯編語(yǔ)言編寫(xiě)四個(gè)與處理器相關(guān)的函數(shù)(OS_CPU.ASM)設(shè)置與處理器和編譯器相關(guān)的代碼OS_CPU.H中定義了與編譯器相關(guān)的數(shù)據(jù)類(lèi)型。比如:INT8U、INT8S等。與ARM處理器相關(guān)的代碼,使用OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()宏開(kāi)啟/關(guān)閉中斷設(shè)施堆棧的增長(zhǎng)方向:堆棧由高地址向低地址增長(zhǎng)用C語(yǔ)言編寫(xiě)六個(gè)操作系統(tǒng)相關(guān)的函數(shù)void*OSTaskStkInit(void(*task)(void*pd),void*pdata,void*ptos,INT16Uopt)voidOSTaskCreateHook(OS_TCB*ptcb)voidOSTaskDelHook(OS_TCB*ptcb)voidOSTaskSwHook(void)voidOSTaskStatHook(void)voidOSTimeTickHook(void)后5個(gè)函數(shù)為鉤子函數(shù),可以不加代碼用匯編語(yǔ)言編寫(xiě)四個(gè)
與處理器相關(guān)的函數(shù)OSStartHighRdy()OSCtxSw()OSIntCtxSw()OSTickISR()關(guān)于移植相對(duì)于其他的嵌入式操作系統(tǒng),uCOS-II的移植雖然是一個(gè)很簡(jiǎn)單的過(guò)程,但是,對(duì)于不熟悉uCOS-II的開(kāi)發(fā)者,移植還是有一定難度的。2.4μC/OS-IIBSP編寫(xiě)
BSP(板級(jí)支持包)是介于底層硬件和操作系統(tǒng)之間的軟件層次,它完成系統(tǒng)上電后最初的硬件和軟件初始化,并對(duì)底層硬件進(jìn)行封裝,使得操作系統(tǒng)不再面對(duì)具體的操作。BSP的特點(diǎn):硬件相關(guān)性:因?yàn)榍度胧綄?shí)時(shí)系統(tǒng)的硬件環(huán)境具有應(yīng)用相關(guān)性,所以,作為高層軟件與硬件之間的接口,BSP必須為操作系統(tǒng)提供操作和控制具體硬件的方法。操作系統(tǒng)相關(guān)性:不同的操作系統(tǒng)具有各自的軟件層次結(jié)構(gòu),因此,不同的操作系統(tǒng)具有特定的硬件接口形式。BSP的功能操作系統(tǒng)初始化A、片級(jí)初始化B、板級(jí)初始化C、系統(tǒng)級(jí)初始化硬件相關(guān)的設(shè)備驅(qū)動(dòng)程序嵌入式系統(tǒng)初始化過(guò)程及BSP功能系統(tǒng)調(diào)用通用設(shè)備驅(qū)動(dòng)程序與BSP的關(guān)系設(shè)計(jì)BSP的方法一、以典型的BSP做為參考二、參照操作系統(tǒng)或芯片廠商提供的BSP模板μC/OS-II
BSPforARMμC/OS-II編寫(xiě)一個(gè)簡(jiǎn)單的BSP。它首先設(shè)置CPU內(nèi)部寄存器和系統(tǒng)堆棧,并初始化堆棧指針,建立程序的運(yùn)行和調(diào)用環(huán)境;然后可以方便地使用C語(yǔ)言設(shè)置ARM片選地址(CS0~CS7)、GPIO以及SDRAM控制器,初始化串口(UART0)作為默認(rèn)打印口,并向操作系統(tǒng)提供一些硬件相關(guān)例程和函數(shù)如dprintf(),以方便調(diào)試;在CPU、板級(jí)和程序自身初始化完成后,就可以把CPU的控制權(quán)交給操作系統(tǒng)了
二、向嵌入式平臺(tái)移植軟件
大部分嵌入式開(kāi)發(fā)人員選用的軟件開(kāi)發(fā)模式是先在PC機(jī)上編寫(xiě)軟件,再進(jìn)行軟件的移植工作。在PC機(jī)上編寫(xiě)軟件時(shí),要注意軟件的可移植性。1、選用具有較高移植性的編程語(yǔ)言(如C語(yǔ)言)2、盡量少調(diào)用操作系統(tǒng)函數(shù)3、注意屏蔽不同硬件平臺(tái)帶來(lái)的字節(jié)順序、字節(jié)對(duì)齊等問(wèn)題。
字節(jié)順序
字節(jié)順序是指占內(nèi)存多于一個(gè)字節(jié)類(lèi)型的數(shù)據(jù)在內(nèi)存中的存放順序,通常有小端、大端兩種字節(jié)順序。 (1)小端字節(jié)序:指低字節(jié)數(shù)據(jù)存放在內(nèi)存低地址處,高字節(jié)數(shù)據(jù)存放在內(nèi)存高地址處; (2)大端字節(jié)序:是高字節(jié)數(shù)據(jù)存放在低地址處,低字節(jié)數(shù)據(jù)存放在高地址處。 基于X86平臺(tái)的PC機(jī)是小端字節(jié)序的,而有的嵌入式平臺(tái)則是大端字節(jié)序的。因而對(duì)int、uint16、uint32等多于1字節(jié)類(lèi)型的數(shù)據(jù),在這些嵌入式平臺(tái)上應(yīng)該變換其存儲(chǔ)順序。
字節(jié)對(duì)齊[1]有的嵌入式處理器的尋址方式?jīng)Q定了:在內(nèi)存中占2字節(jié)的int16、uint16等類(lèi)型數(shù)據(jù)只能存放在偶數(shù)內(nèi)存地址處,占4字節(jié)的int32、uint32等類(lèi)型數(shù)據(jù)只能存放在4的整數(shù)倍的內(nèi)存地址處;占8字節(jié)的類(lèi)型數(shù)據(jù)只能存放在8的整數(shù)倍的內(nèi)存地址處;而在內(nèi)存中只占1字節(jié)的類(lèi)型數(shù)據(jù)可以存放在任意地址處。
字節(jié)對(duì)齊[1]由于這些限制,在這些平臺(tái)上編程時(shí)有很大的不同。首先,結(jié)構(gòu)體成員之間會(huì)有空洞,比如這樣一個(gè)結(jié)構(gòu):
typedefstructtest{
chara;
uint16b;
}TEST
字節(jié)對(duì)齊[2]對(duì)于結(jié)構(gòu)TEST:在單字節(jié)對(duì)齊的平臺(tái)上占內(nèi)存三個(gè)字節(jié),而在以上所述的嵌入式平臺(tái)上有可能占三個(gè)或四個(gè)字節(jié),視成員a的存儲(chǔ)地址而定。
字節(jié)對(duì)齊[2]當(dāng)a存儲(chǔ)地址為奇數(shù)時(shí),該結(jié)構(gòu)占三個(gè)字節(jié),在a與b之間不存在一個(gè)字節(jié)的空洞。當(dāng)a存儲(chǔ)地址為偶數(shù)時(shí),該結(jié)構(gòu)占四個(gè)字節(jié),在a與b之間存在一個(gè)字節(jié)的空洞。對(duì)于通信雙方都是對(duì)結(jié)構(gòu)成員操作的,這種情況不會(huì)出錯(cuò),但如果有一方是逐字節(jié)讀取內(nèi)容的(通信協(xié)議大都如此),就會(huì)錯(cuò)誤地讀到其它字節(jié)的內(nèi)容。
字節(jié)對(duì)齊[2]其次,若對(duì)內(nèi)存中數(shù)據(jù)以強(qiáng)制類(lèi)型轉(zhuǎn)換的方式讀取,字節(jié)對(duì)齊的不同會(huì)引起數(shù)據(jù)讀取的錯(cuò)誤。因?yàn)椋海?)假如指針指在奇數(shù)內(nèi)存地址處,(2)我們想取得占內(nèi)存兩個(gè)字節(jié)的數(shù)據(jù)存放在uint16型的變量中,則:強(qiáng)制類(lèi)型轉(zhuǎn)換的結(jié)果是取得了該指針?biāo)傅刂放c第一個(gè)字節(jié)的數(shù)據(jù),第二個(gè)數(shù)據(jù)沒(méi)有被讀取。
位
段
由于位段的空間分配方向因硬件平臺(tái)的不同而不同(1)對(duì)X86平臺(tái),位段是從右向左分配的;(2)而一些嵌入式平臺(tái),位段是從左向右分配的。則: 分配順序的不同導(dǎo)致了數(shù)據(jù)存取的錯(cuò)誤。解決這一問(wèn)題的一種方法
是采用條件編譯的方式,針對(duì)不同的平臺(tái)定義順序不同的位段;也可以在前面所述的兩個(gè)函數(shù)中加上對(duì)位段的處理。
代碼優(yōu)化的問(wèn)題嵌入式系統(tǒng)對(duì)應(yīng)用軟件的質(zhì)量要求更高,因而在嵌入式開(kāi)發(fā)中尤其須注意對(duì)代碼進(jìn)行優(yōu)化,盡可能地提高代碼的效率,減少代碼的大小。雖然現(xiàn)代C和C++編譯器都提供了一定程度的代碼優(yōu)化,但大部分由編譯器執(zhí)行的優(yōu)化技術(shù)僅涉及執(zhí)行速度和代碼大小的平衡,不可能使程序既快又小因而必須在編寫(xiě)嵌入式軟件時(shí)采取必要的措施。
(1)提高代碼的效率
①switch-case語(yǔ)句。在程序中經(jīng)常會(huì)使用switch-case語(yǔ)句,每一個(gè)由機(jī)器語(yǔ)言實(shí)現(xiàn)的測(cè)試和跳轉(zhuǎn)僅僅是為了決定下一步要做什么,就浪費(fèi)了處理器時(shí)間。為了提高速度,可以把具體的情況按照它們發(fā)生的相對(duì)頻率排序。即把最可能發(fā)生的情況放在第一,最不可能發(fā)生的情況放在最后,這樣會(huì)減少平均的代碼執(zhí)行時(shí)間。
②
全局變量。使用全局變量比向函數(shù)傳遞參數(shù)更加有效率,這樣做去除了函數(shù)調(diào)用前參數(shù)入棧和函數(shù)完成后參數(shù)出棧的需要。當(dāng)然,使用全局變量會(huì)對(duì)程序有一些負(fù)作用。
(2)減小代碼的大小
嵌入式系統(tǒng)編程應(yīng)避免使用標(biāo)準(zhǔn)庫(kù)例程,因?yàn)楹芏啻蟮膸?kù)例程設(shè)法處理所有可能的情況,所以占用了龐大的內(nèi)存空間,因而應(yīng)盡可能地減少使用標(biāo)準(zhǔn)庫(kù)例程。
(3)避免內(nèi)存泄漏
用戶內(nèi)存空間(堆)為RAM中全局?jǐn)?shù)據(jù)和任務(wù)堆??臻g都分配后的剩余空間,為了使程序能有足夠的內(nèi)存運(yùn)行,必須在申請(qǐng)的內(nèi)存不用后及時(shí)地將其釋放,以確保再次申請(qǐng)時(shí)能有空間。如果程序中存在內(nèi)存泄漏(即申請(qǐng)內(nèi)存后沒(méi)有及時(shí)釋放)的情況,程序最終會(huì)因?yàn)闆](méi)有足夠的內(nèi)存空間而無(wú)法運(yùn)行。
ucos-II在FM3上的移植開(kāi)發(fā)板開(kāi)發(fā)板資源(1)微控制器MB9BF506R2xUART通道(母頭DB9接口)2x高速CAN通道(2針接插件)1xUSB主機(jī)接口(Type-AUSB接口)1xUSB設(shè)備接口(Type-BUSB接口)32Mx8bitNandFlash(K9F5608U0D)高精度I2C接口的實(shí)時(shí)時(shí)鐘模塊(RX-8025T)開(kāi)發(fā)板資源(2)128x64點(diǎn)陣LCD3個(gè)用戶LED4個(gè)用戶按鍵、1個(gè)復(fù)位鍵1個(gè)電位計(jì)(可以調(diào)節(jié)AD輸入電壓)120針的測(cè)試焊盤(pán)(MCU所有引腳)5V和3V供電的電壓選擇支持USB,JTAG和外部15V電源供電板上標(biāo)準(zhǔn)20針JTAG接口支持IAR和Keil的調(diào)試工具ucos-II軟硬件相關(guān)架構(gòu)ucos-II在FM3上的移植三個(gè)處理器相關(guān)的代碼:用#define設(shè)置1個(gè)常數(shù)、聲明10個(gè)數(shù)據(jù)類(lèi)型、用#define定義3個(gè)宏(OS_CPU.H)編寫(xiě)5個(gè)匯編語(yǔ)言函數(shù)(OS_CPU_A.ASM)編寫(xiě)2個(gè)c函數(shù)(OS_CPU_C.C)修改OS_CPU.H設(shè)置一個(gè)常量/*StackgrowsfromHIGHtoLOWmemoryonARM*/#defineOS_STK_GROWTH1修改OS_CPU.H聲明10個(gè)數(shù)據(jù)類(lèi)型typedefunsignedcharBOOLEAN;typedefunsignedcharINT8U;/*Unsigned8bitquantity*/typedefsignedcharINT8S;/*Signed8bitquantity*/typedefunsignedshortINT16U;/*Unsigned16bitquantity*/typedefsignedshortINT16S;/*Signed16bitquantity*/typedefunsignedintINT32U;/*Unsigned32bitquantity*/typedefsignedintINT32S;/*Signed32bitquantity*/(1)typedeffloatFP32;/*Singleprecisionfloatingpoint*/typedefdoubleFP64;/*Doubleprecisionfloatingpoint*/typedefunsignedintOS_STK;/*Eachstackentryis32-bitwide*/(2)typedefunsignedintOS_CPU_SR;/*DefinesizeofCPUstatusregister(PSR=32bits)*/(3)修改OS_CPU.H(1)因?yàn)锳RMCotex-M3是32位微處理器,所以定義unsignedshort和signedshort為INT16S和INT16U,定義int和signedint為INT32U和INT32S.(2)因?yàn)槲⑻幚砥鞫褩J?2位結(jié)構(gòu),因此定義OS_STK的類(lèi)型為unsignedint(3)因?yàn)镃PU狀態(tài)寄存器是32位,所以定義OS_CPU_SR為unsignedint類(lèi)型修改OS_CPU.H定義3個(gè)宏#defineOS_CRITICAL_METHOD3#ifOS_CRITICAL_METHOD==3#defineOS_ENTER_CRITICAL(){cpu_sr=OS_CPU_SR_Save();}#defineOS_EXIT_CRITICAL(){OS_CPU_SR_Restore(cpu_sr);}(1)#endif#defineOS_TASK_SW()OSCtxSw()(2)修改OS_CPU.H(1)為隱藏編譯器相關(guān)的實(shí)現(xiàn)方法,μC/OS-II定義了兩個(gè)開(kāi)關(guān)中斷的宏:OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL().方法3是采用中斷狀態(tài)預(yù)處理的方法開(kāi)關(guān)中斷。通常在本地變量'cpu_sr'中保存中斷禁止標(biāo)志的狀態(tài),然后通過(guò)拷貝'cpu_sr到CPU狀態(tài)寄存器來(lái)控制中斷管理.(2)μC/OS-II在任務(wù)切換時(shí)需要從就緒任務(wù)的堆棧中恢復(fù)所有的微處理器寄存器,然后執(zhí)行中斷返回指令。因此,為實(shí)現(xiàn)上下文切換,需要編寫(xiě)OS_TASK_SW()函數(shù)以模擬一次中斷的發(fā)生,OS_TASK_SW()定義為OSCtxSw,OSCtxSw是用匯編語(yǔ)言編寫(xiě)的代碼,在軟件中斷中調(diào)用。修改OS_CPU_A.ASM需要編寫(xiě)5個(gè)匯編語(yǔ)言函數(shù)OSStartHighRdy()OSCtxSw()OSIntCtxSw()OS_CPU_SR_Save()和OS_CPU_SR_Restore()OS_CPU_PendSVHandler修改OS_CPU_A.ASM編寫(xiě)OSStartHighRdy()*********************************************************************************************************LDRR0,=NVIC_SYSPRI14 ;SetthePendSVexceptionpriority(1)LDRR1,=NVIC_PENDSV_PRISTRBR1,[R0]MOVSR0,#0 ;SetthePSPto0forinitialcontextswitchcall(2)MSRPSP,R0LDRR0,=OSRunning;OSRunning=TRUE (3)MOVSR1,#1STRBR1,[R0]LDRR0,=NVIC_INT_CTRL ;TriggerthePendSVexception(causescontextswitch)LDRR1,=NVIC_PENDSVSETSTRR1,[R0]CPSIEI ;Enableinterruptsatprocessorlevel(4)OSStartHangBOSStartHang ;Shouldnevergethere修改OS_CPU_A.ASM(1)這個(gè)函數(shù)由OSStart()執(zhí)行以啟動(dòng)最高優(yōu)先級(jí)任務(wù),設(shè)置PendSV中斷優(yōu)先級(jí)為最低以確保它不會(huì)打斷用戶的中斷。(2)設(shè)置PSP=0,告訴上下文切換函數(shù)這是第一次運(yùn)行。(3)設(shè)置OSRunning=TRUE以啟動(dòng)多任務(wù)調(diào)度(4)PendSV中斷只有在被允許后才獲得響應(yīng)。修改OS_CPU_A.ASM編寫(xiě)OSCtxSw()*********************************************************************************************LDRR0,=NVIC_INT_CTRL;觸發(fā)PendSV中斷(引起上下文切換)(1)LDRR1,=NVIC_PENDSVSETSTRR1,[R0]BXLR(1)當(dāng)OS執(zhí)行上下文切換時(shí)調(diào)用OSCtxSw().這個(gè)函數(shù)將觸發(fā)PendSV中斷,實(shí)際的切換在該中斷中執(zhí)行。修改OS_CPU_A.ASM編寫(xiě)OSIntCtxSw()*******************************************************************************************LDRR0,=NVIC_INT_CTRL;觸發(fā)PendSV中斷(引起上下文切換)(1)LDRR1,=NVIC_PENDSVSETSTRR1,[R0]BXLR(1)從中斷返回時(shí),如果需要上下文切換OSIntExit()調(diào)用將調(diào)用OSIntCtxSw().這個(gè)函數(shù)只是簡(jiǎn)單的觸發(fā)PendSV中斷,如果沒(méi)有中斷嵌套且中斷被允許的情況下,將響應(yīng)PendSV中斷.修改OS_CPU_A.ASM編寫(xiě)OS_CPU_SR_Save()和OS_CPU_SR_Restore()*******************************************************************************************OS_CPU_SR_SaveMRSR0,PRIMASK ;屏蔽所有中斷,并保存PRIMASK的值CPSIDIBXLROS_CPU_SR_RestoreMSRPRIMASK,R0 ;恢復(fù)PRIMASK的值BXLR修改OS_CPU_A.ASM編寫(xiě)OS_CPU_PendSVHandler*******************************************************************************************
PendSV中斷用于引起上下文切換。任何中斷發(fā)生時(shí)Cortex-M3都自動(dòng)保存了一半的微處理器寄存器,并且在返回時(shí)自動(dòng)恢復(fù)這些寄存器,所以移植時(shí)只需要保存R4-R11,并固定堆棧指針。也就是說(shuō),無(wú)論是從一個(gè)線程啟動(dòng)或發(fā)生因中斷或異常,上下文保存和恢復(fù)是相同的。修改OS_CPU_A.ASM編寫(xiě)OS_CPU_PendSVHandler**********************************************************************代碼如下:CPSIDI ;上下文切換時(shí)關(guān)中斷MRSR0,PSP ;PSP是堆棧指針CBZR0,OS_CPU_PendSVHandler_nosave;第一次發(fā)生需要保存堆棧指針SUBSR0,R0,#0x20 ;在堆棧中保存r4-11
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 二手房購(gòu)買(mǎi)協(xié)議書(shū)七篇
- 關(guān)于土地征用協(xié)議書(shū)
- 舞蹈癥病因介紹
- (立項(xiàng)備案申請(qǐng)模板)鋁型材模板項(xiàng)目可行性研究報(bào)告參考范文
- (2024)年產(chǎn)300萬(wàn)噸水穩(wěn)站項(xiàng)目可行性研究報(bào)告寫(xiě)作模板立項(xiàng)備案文件一
- 2024-2025學(xué)年人教版七年級(jí)英語(yǔ)上學(xué)期期末復(fù)習(xí) 專(zhuān)題07 語(yǔ)法填空 【期末必刷15篇】
- 2023年天津市紅橋區(qū)高考語(yǔ)文一模試卷
- 云南省保山市智源初級(jí)中學(xué)2024-2025學(xué)年七年級(jí)上學(xué)期12月月考道德與法治試卷-A4
- 2023年布展裝修項(xiàng)目籌資方案
- 2023年可調(diào)控輥型四輥液壓軋機(jī)項(xiàng)目籌資方案
- 2025高考語(yǔ)文步步高大一輪復(fù)習(xí)講義教材文言文點(diǎn)線面答案精析
- 《工程勘察設(shè)計(jì)收費(fèi)標(biāo)準(zhǔn)》(2002年修訂本)-工程設(shè)計(jì)收費(fèi)標(biāo)準(zhǔn)2002修訂版
- 2024-2030年中國(guó)眼部保健品行業(yè)市場(chǎng)發(fā)展趨勢(shì)與前景展望戰(zhàn)略分析報(bào)告
- 2024山東能源集團(tuán)中級(jí)人才庫(kù)選拔(高頻重點(diǎn)提升專(zhuān)題訓(xùn)練)共500題附帶答案詳解
- T-CCIIA 0004-2024 精細(xì)化工產(chǎn)品分類(lèi)
- 低年級(jí)革命文化類(lèi)課文教學(xué)探析
- TPM知識(shí)競(jìng)賽題庫(kù)含答案
- 中國(guó)成人失眠診斷與治療指南(2023版)解讀
- 解析德意志意識(shí)形態(tài)中的難解之謎生產(chǎn)關(guān)系概念與交往形式等術(shù)語(yǔ)的關(guān)系
- 皮膚疾病超聲檢查指南(2022版)
- 國(guó)開(kāi)機(jī)考答案-工程力學(xué)(本)(閉卷)
評(píng)論
0/150
提交評(píng)論