uCOS中任务调度时的上下文切换
uCOS中任務調度時的上下文切換
這里以STM32處理器為例,也就是Cortex-M3內核。
所謂的上下文切換呢,就是當?uC/OS轉向執行另一個任務的時候,它保存了當前任務的CPU?寄存器到堆棧。并從新任務的的堆棧中?CPU?寄存器載入?CPU。
在這里上下文切換分為兩種:一個是任務級的,一個是中斷級的。
(1)?開始執行切換,保存狀態寄存器和程序指針寄存器到當前的任務堆棧。保存的順序與中斷發生時?CPU?保存寄存器的順序相同。假定?SR?先入棧,然后其它寄存器入棧。
(2)?當任務被停止時,保存?CPU?的?TSP?到該任務的OS_TCB?中,換句話說,OSTCBCurPtr->StkPtr=R14。
(3)?然后將新任務?OS_TCB?的頂部地址存入?CPU?的TSP?中。換句話說,R14=OSTCBCurPtr->StkPtr。
(4)?最后,?將新任務堆棧中?R13~~R0?關內容載入?CPU寄存器。再然后(此時的會?TSP?指向?PC,如圖),通過一個中斷返回指令{比如匯編中的?IRET},程序指針寄存器和狀態寄存器被恢復到?CPU?的寄存器中。
?
以上是一個大概的流程分析,下面來看看其具體的代碼實現過程,當然,這里是用匯編來實現。
?
PendSV_Handler
????CPSID???I???????????????????????????????????????????????????;?Prevent?interruption?during?context?switch關所以中斷
????MRS?????R0,?PSP?????????????????????????????????????????????;?PSP?is?process?stack?pointer??PSP是當前進程堆棧的指針,將PSP賦值給R0
????CBZ?????R0,?PendSV_Handler_Nosave?????????????????????;?Skip?register?save?the?first?time如果R0為0時跳轉到PendSV_Handler_Nosave
?
????SUBS????R0,?R0,?#0x20???????????????????????????????????????;?Save?remaining?regs?r4-11?on?process?stack偏移0x20的位置用來保存R4至R11
????STM?????R0,?{R4-R11}?;將剩下的R4至R11寄存器保存在此進程的堆棧中
?
????LDR?????R1,?=p_OSTCBCur?????????????????????????????????????;?OSTCBCur->OSTCBStkPtr?=?SP;?即OSTCBCur->OSTCBStkPtr這個保存當前的棧尾,以便下次彈出
????LDR?????R1,?[R1]
????STR?????R0,?[R1]????????????????????????????????????????????;?R0?is?SP?of?process?being?switched?out
?
????????????????????????????????????????????????????????????????;?At?this?point,?entire?context?of?process?has?been?saved此時,整個上下文的過程已經被保存
PendSV_Handler_Nosave
????PUSH????{R14}???????????????????????????????????????????????;?Save?LR?exc_return?value
????LDR?????R0,?=OSTaskSwHook???????????????????????????????????;?OSTaskSwHook();??這里的話可以刪除的,用于用戶擴展呵呵
????BLX?????R0
????POP?????{R14}
?
????LDR?????R0,?=OSPrioCur??????????????????????????????????????;?OSPrioCur?=?OSPrioHighRdy;
????LDR?????R1,?=OSPrioHighRdy?;將當前優先級變量指向最高優先級
????LDRB????R2,?[R1]
????STRB????R2,?[R0]
?
????LDR?????R0,?=p_OSTCBCur?????????????????????????????????????;?OSTCBCur??=?OSTCBHighRdy;
????LDR?????R1,?=p_OSTCBHighRdy?;TCB表也一樣
????LDR?????R2,?[R1]
????STR?????R2,?[R0]
;到這里,[R2]保存的是新的進程的堆棧指針SP
????LDR?????R0,?[R2]????????????????????????????????????????????;?R0?is?new?process?SP;?SP?=?OSTCBHighRdy->OSTCBStkPtr;??將堆棧指針賦值給SP
????LDM?????R0,?{R4-R11}????????????????????????????????????????;?Restore?r4-11?from?new?process?stack?彈出其它寄存器,和前面的是一個逆過程
????ADDS????R0,?R0,?#0x20?;和前面的逆過程對比可知
????MSR?????PSP,?R0?????????????????????????????????????????????;?Load?PSP?with?new?process?SP將R0中的SP賦值給PSP寄存器
????ORR?????LR,?LR,?#0x04???????????????????????????????????????;?Ensure?exception?return?uses?process?stack確保異常返回時使用進程堆棧
????CPSIE???I?;開中斷
????BX??????LR??????????????????????????????????????????????????;?Exception?return?will?restore?remaining?context異常返回將恢復那些自動出棧的剩余寄存器
?
暈,排版有點亂,勉強湊合著看吧。。。
可以看出這其實是一個PendSV中斷來的,也就是M3的可編程掛起中斷,為什么用這個中斷來進行上下文切換呢?后面將會進行說明下。
CBZ?????R0,?PendSV_Handler_Nosave
這句是用來判斷是否第一次進入切換,也就是系統剛啟動的時候,則直接跳到PendSV_Handler_Nosave這個標號來執行了,因為系統剛啟動還沒有當前任務嘛。
當不是剛啟動的,進行上下文切換,首先是要將當前任務的寄存器保存下來,保存到當前任務的堆棧里,R4-R11手動保存到堆棧,其余會自動保存。
然后
????LDR?????R0,?=OSPrioCur??????????????????????????????????????;?OSPrioCur?=?OSPrioHighRdy;
????LDR?????R1,?=OSPrioHighRdy?;將當前優先級變量指向最高優先級
????LDRB????R2,?[R1]
????STRB????R2,?[R0]
?
????LDR?????R0,?=p_OSTCBCur?????????????????????????????????????;?OSTCBCur??=?OSTCBHighRdy;
????LDR?????R1,?=p_OSTCBHighRdy?;TCB表也一樣
????LDR?????R2,?[R1]
????STR?????R2,?[R0]
這里是將優先級最高的,也就是需要切換到的那個任務替換為當前任務。
然后讓PSP指向任務堆棧,再然后是一個逆過程,彈出堆棧里的數據到對應的寄存器。
?
上下文切換就差不多這樣。。。
關于在M3內核,為什么使用PendSV這個中斷來進行上下文切換呢?其原因是這個中斷擁有最低優先級的軟件中斷。
又問,為什么要在擁有最低優先級的軟件中斷中進行切換呢?這個答案在《Cortex-M3權威指南》第7章?異常???里有詳細的答案。
總結
以上是生活随笔為你收集整理的uCOS中任务调度时的上下文切换的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 任务调度与上下文切换时间测试
- 下一篇: 机器如何区分和判定指令和数据