新聞中心

移植μC/OS-Ⅱ

作者: 時(shí)間:2016-10-08 來源:網(wǎng)絡(luò) 收藏

圖 8.2 在ISR執(zhí)行過程中的堆棧內(nèi)容.

接著,CPU會(huì)調(diào)用正確的ISR。μC/OS-Ⅱ要求用戶的ISR在開始時(shí)要保存剩下的處理器寄存器[F8.2(2)]。一旦寄存器保存好了,μC/OS-Ⅱ就要求用戶或者調(diào)用OSIntEnter(),或者將變量OSIntNesting加1。在這個(gè)時(shí)候,被中斷任務(wù)的堆棧中只包含了被中斷任務(wù)的寄存器內(nèi)容?,F(xiàn)在,ISR可以執(zhí)行中斷服務(wù)了。并且如果ISR發(fā)消息給任務(wù)(通過調(diào)用OSMboxPost()或OSQPost()), 恢復(fù)任務(wù)(通過調(diào)用OSTaskResume()), 或者調(diào)用OSTimeTick()或OSTimeDlyResume()的話,有可能使更高優(yōu)先級(jí)的任務(wù)處于就緒狀態(tài)。

假設(shè)有一個(gè)更高優(yōu)先級(jí)的任務(wù)處于就緒狀態(tài)。μC/OS-Ⅱ要求用戶的ISR在完成中斷服務(wù)的時(shí)候調(diào)用OSIntExit()。OSIntExit()會(huì)告訴μC/OS-Ⅱ到了返回任務(wù)級(jí)代碼的時(shí)間了。

調(diào)用OSIntExit()會(huì)導(dǎo)致調(diào)用者的返回地址被保存到被中斷的任務(wù)的堆棧中[F8.2(3)]。

OSIntExit()剛開始時(shí)會(huì)禁止中斷,因?yàn)樗枰獔?zhí)行臨界段的代碼。根據(jù)OS_ENTER_CRITICAL()的不同執(zhí)行過程(參看8.03.02),處理器的狀態(tài)寄存器會(huì)被保存到被中斷的任務(wù)的堆棧中[F8.2(4)]。OSIntExit()注意到由于有更高優(yōu)先級(jí)的任務(wù)處于就緒狀態(tài),被中斷的任務(wù)已經(jīng)不再是要繼續(xù)執(zhí)行的任務(wù)了。在這種情況下,指針OSTCBHighRdy會(huì)被指向新任務(wù)的OS_TCB,并且OSIntExit()會(huì)調(diào)用OSIntCtxSw()來執(zhí)行任務(wù)切換。調(diào)用OSIntCtxSw()也同樣使返回地址被保存到被中斷的任務(wù)的堆棧中[F8.2(5)]。

在用戶切換任務(wù)的時(shí)候,用戶只想將某些項(xiàng)([F8.2(1)]和[F8.2(2)])保留在堆棧中,并忽略其它項(xiàng)(F8.2(3),(4)和(5)) 。這是通過調(diào)整堆棧指針(加一個(gè)數(shù)在堆棧指針上)來完成的[F8.2(6)]。加在堆棧指針上的數(shù)必須是明確的,而這個(gè)數(shù)主要依賴于移植的目標(biāo)處理器(地址空間可能是16,32或64位),所用的編譯器,編譯器選項(xiàng),內(nèi)存模式等等。另外,處理器狀態(tài)字可能是8,16,32甚至64位寬,并且OSIntExit()可能會(huì)分配局部變量。有些處理器允許用戶直接增加常量到堆棧指針中,而有些則不允許。在后一種情況下,可以通過簡(jiǎn)單的執(zhí)行一定數(shù)量的pop(出棧)指令來實(shí)現(xiàn)相同的功能。一旦堆棧指針完成調(diào)整,新的堆棧指針會(huì)被保存到被切換出去的任務(wù)的OS_TCB中[F8.2(7)]。

OSIntCtxSw()的原型如程序清單L8.3所示。這些代碼必須寫在匯編語(yǔ)言中,因?yàn)橛脩舨荒苤苯訌腃語(yǔ)言中訪問CPU寄存器。如果用戶的編譯器支持插入?yún)R編語(yǔ)言代碼的話,用戶就可以將OSIntCtxSw()代碼放到OS_CPU_C.C文件中,而不放到OS_CPU_A.ASM文件中。正如用戶所看到的那樣,除了第一行以外,OSIntCtxSw()的代碼與OSCtxSw()是一樣的。這樣在移植實(shí)例中,用戶可以通過“跳轉(zhuǎn)”到OSCtxSw()中來減少 OSIntCtxSw()代碼量。

程序清單 L8.3 OSIntCtxSw()的原型

voidOSIntCtxSw(void)

{

調(diào)整堆棧指針來去掉在調(diào)用:

OSIntExit(),

OSIntCtxSw()過程中壓入堆棧的多余內(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ù)出來;

執(zhí)行中斷返回指令;

}

OSIntCtxSw()是μC/OS-Ⅱ(和μC/OS)中唯一的與編譯器相關(guān)的函數(shù);在我收到的e-mail中,關(guān)于該函數(shù)的e-mail明顯多于關(guān)于μC/OS其它方面的。如果在多次任務(wù)切換后用戶的系統(tǒng)崩潰了,用戶應(yīng)該懷疑堆棧指針在OSIntCtxSw()中是否被正確地調(diào)整了。

8.04.04OSTickISR()

μC/OS-Ⅱ要求用戶提供一個(gè)時(shí)鐘資源來實(shí)現(xiàn)時(shí)間的延時(shí)和期滿功能。時(shí)鐘節(jié)拍應(yīng)該每秒鐘發(fā)生10-100次。 為了完成該任務(wù), 可以使用硬件時(shí)鐘, 也可以從交流電中獲得50/60Hz的時(shí)鐘頻率。

用戶必須在開始多任務(wù)調(diào)度后(即調(diào)用OSStart()后)允許時(shí)鐘節(jié)拍中斷。換句話說,就是用戶應(yīng)該在OSStart()運(yùn)行后,μC/OS-Ⅱ啟動(dòng)運(yùn)行的第一個(gè)任務(wù)中初始化節(jié)拍中斷。通常所犯的錯(cuò)誤是在調(diào)用OSInit()和OSStart()之間允許時(shí)鐘節(jié)拍中斷(如程序清單L8.4所示)。

程序清單 L8.4 在不正確的位置啟動(dòng)時(shí)鐘節(jié)拍中斷

voidmain(void)

{

.

.

OSInit();/* 初始化 ? μC/OS-II*/

.

.

/* 應(yīng)用程序初始化代碼 ...*/

/*... 調(diào)用OSTaskCreate()建立至少一個(gè)任務(wù) */

.

.

允許時(shí)鐘節(jié)拍中斷;/* 千萬不要在這里允許!!! */

.

.

OSStart();/* 開始多任務(wù)調(diào)度 */

}

有可能在μC/OS-Ⅱ開始執(zhí)行第一個(gè)任務(wù)前時(shí)鐘節(jié)拍中斷就發(fā)生了。在這種情況下,μC/OS-Ⅱ的運(yùn)行狀態(tài)不確定,用戶的應(yīng)用程序也可能會(huì)崩潰。

時(shí)鐘節(jié)拍ISR的原型如程序清單L8.5所示。這些代碼必須寫在匯編語(yǔ)言中,因?yàn)橛脩舨荒苤苯訌腃語(yǔ)言中訪問CPU寄存器。如果用戶的處理器可以通過單條指令來增加OSIntNesting,那么用戶就沒必要調(diào)用 OSIntEnter()了。增加OSIntNesting要比通過函數(shù)調(diào)用和返回快得多。OSIntEnter()只增加OSIntNesting,并且作為臨界段代碼中受到保護(hù)。

程序清單 L8.5 時(shí)鐘節(jié)拍ISR的原型

voidOSTickISR(void)

{

保存處理器寄存器;

調(diào)用OSIntEnter()或者直接將 OSIntNesting加1;

調(diào)用OSTimeTick();

調(diào)用OSIntExit();

恢復(fù)處理器寄存器;

執(zhí)行中斷返回指令;

}

8.05OS_CPU_C.C

μC/OS-Ⅱ的移植實(shí)例要求用戶編寫六個(gè)簡(jiǎn)單的C函數(shù):

OSTaskStkInit()

OSTaskCreateHook()

OSTaskDelHook()

OSTaskSwHook()

OSTaskStatHook()

OSTimeTickHook()

唯一必要的函數(shù)是OSTaskStkInit(),其它五個(gè)函數(shù)必須得聲明但沒必要包含代碼。



關(guān)鍵詞:

評(píng)論


相關(guān)推薦

技術(shù)專區(qū)

關(guān)閉