移植μC/OS-Ⅱ
8.05.01OSTaskStkInt()
OSTaskCreate()和OSTaskCreateExt()通過調用OSTaskStkInt()來初始化任務的堆棧結構,因此,堆棧看起來就像剛發生過中斷并將所有的寄存器保存到堆棧中的情形一樣。圖8.3顯示了OSTaskStkInt()放到正被建立的任務堆棧中的東西。注意,在這里我假定了堆棧是從上往下長的。下面的討論同樣適用于從下往上長的堆棧。
在用戶建立任務的時候,用戶會傳遞任務的地址,pdata指針,任務的堆棧棧頂和任務的優先級給OSTaskCreate()和OSTaskCreateExt()。雖然OSTaskCreateExt()還要求有其它的參數,但這些參數在討論OSTaskStkInt()的時候是無關緊要的。為了正確初始化堆棧結構,OSTaskStkInt()只要求剛才提到的前三個參數和一個附加的選項,這個選項只能在OSTaskCreateExt()中得到。
圖 8.3 堆棧初始化(pdata通過堆棧傳遞)
回顧一下,在μC/OS-Ⅱ中,無限循環的任務看起來就像其它的C函數一樣。當任務開始被μC/OS-Ⅱ執行時,任務就會收到一個參數,好像它被其它的任務調用一樣。
voidMyTask(void*pdata)
{
/* 對'pdata'做某些操作 */
for(;;){
/* 任務代碼 */
}
}
如果我想從其它的函數中調用MyTask(),C編譯器就會先將調用MyTask()的函數的返回地址保存到堆棧中,再將參數保存到堆棧中。實際上有些編譯器會將pdata參數傳至一個或多個寄存器中。在后面我會討論這類情況。假定pdata會被編譯器保存到堆棧中,OSTaskStkInit()就會簡單的模仿編譯器的這種動作,將pdata保存到堆棧中[F8.3(1)]。但是結果表明,與C函數調用不一樣,調用者的返回地址是未知的。用戶所擁有的是任務的開始地址,而不是調用該函數(任務)的函數的返回地址!事實上用戶不必太在意這點,因為任務并不希望返回到其它函數中。
這時,用戶需要將寄存器保存到堆棧中,當處理器發現并開始執行中斷的時候,它會自動地完成該過程的。一些處理器會將所有的寄存器存入堆棧,而其它一些處理器只將部分寄存器存入堆棧。一般而言,處理器至少得將程序計數器的值(中斷返回地址)和處理器的狀態字存入堆棧[F8.3(2)]。很明顯,處理器是按一定的順序將寄存器存入堆棧的,而用戶在將寄存器存入堆棧的時候也就必須依照這一順序。
接著,用戶需要將剩下的處理器寄存器保存到堆棧中[F8.3(3)]。保存的命令依賴于用戶的處理器是否允許用戶保存它們。 有些處理器用一個或多個指令就可以馬上將許多寄存器都保存起來。用戶必須用特定的指令來完成這一過程。例如,Intel80x86使用PUSHA指令將8個寄存器保存到堆棧中。對Motorola68HC11處理器而言,在中斷響應期間,所有的寄存器都會按一定順序自動的保存到堆棧中,所以在用戶將寄存器存入堆棧的時候,也必須依照這一順序。
現在是時候討論這個問題了: 如果用戶的C編譯器將pdata參數傳遞到寄存器中而不是堆棧中該作些什么?用戶需要從編譯器的文檔中找到pdata儲存在哪個寄存器中。pdata的內容就會隨著這個寄存器的儲存被放置在堆棧中。
圖 8.4 堆棧初始化(pdata通過寄存器傳遞)
一旦用戶初始化了堆棧,OSTaskStkInit()就需要返回堆棧指針所指的地址[F8.3(4)]。
OSTaskCreate()和OSTaskCreateExt()會獲得該地址并將它保存到任務控制塊(OS_TCB)中。
處理器文檔會告訴用戶堆棧指針會指向下一個堆棧空閑位置, 還是會指向最后存入數據的堆棧單元位置。例如,對Intel80x86處理器而言,堆棧指針會指向最后存入數據的堆棧單元位置,而對Motorola68HC11處理器而言,堆棧指針會指向下一個空閑的位置。
8.05.02OSTaskCreateHook()
當用OSTaskCreate()或OSTaskCreateExt()建立任務的時候就會調用OSTaskCreateHook()。該函數允許用戶或使用用戶的移植實例的用戶擴展μC/OS-Ⅱ的功能。
當μC/OS-Ⅱ設置完了自己的內部結構后,會在調用任務調度程序之前調用OSTaskCreateHook()。該函數被調用的時候中斷是禁止的。因此用戶應盡量減少該函數中的代碼以縮短中斷的響應時間。
當OSTaskCreateHook()被調用的時候,它會收到指向已建立任務的OS_TCB的指針,這樣它就可以訪問所有的結構成員了。當使用OSTaskCreate()建立任務時,OSTaskCreateHook()的功能是有限的。但當用戶使用OSTaskCreateExt()建立任務時,用戶會得到OS_TCB中的擴展指針OSTCBExtPtr),該指針可用來訪問任務的附加數據,如浮點寄存器,MMU寄存器,任務計數器的內容,以及調試信息。
只用當OS_CFG.H中的OS_CPU_HOOKS_EN被置為1時才會產生OSTaskCreateHook()的代碼。這樣,使用用戶的移植實例的用戶可以在其它的文件中重新定義hook函數。
8.05.03OSTaskDelHook()
當任務被刪除的時候就會調用OSTaskDelHook()。 該函數在把任務從μC/OS-Ⅱ的內部任務鏈表中解開之前被調用。當OSTaskDelHook()被調用的時候,它會收到指向正被刪除任務的OS_TCB的指針, 這樣它就可以訪問所有的結構成員了。 OSTaskDelHook()可以用來檢驗TCB擴展是否被建立了(一個非空指針)并進行一些清除操作。OSTaskDelHook()不返回任何值。
只用當OS_CFG.H中的OS_CPU_HOOKS_EN被置為1時才會產生OSTaskDelHook()的代碼。
8.05.04OSTaskSwHook()
當發生任務切換的時候調用OSTaskSwHook()。不管任務切換是通過OSCtxSw()還是OSIntCtxSw()來執行的都會調用該函數。OSTaskSwHook()可以直接訪問OSTCBCur和OSTCBHighRdy,因為它們是全局變量。OSTCBCur指向被切換出去的任務的OS_TCB,而OSTCBHighRdy指向新任務的OS_TCB。 注意在調用OSTaskSwHook()期間中斷一直是被禁止的。
因為代碼的多少會影響到中斷的響應時間,所以用戶應盡量使代碼簡化。OSTaskSwHook()沒有任何參數,也不返回任何值。












評論