但是uC/OSIII在Cortex-M3平臺中,任務切換函數卻是使用的同一函數,確切的說是使用了同一樣的一個宏定義,如下:
#define OS_TASK_SW() NVIC_INT_CTRL = NVIC_PENDSVSET
#define OSIntCtxSw() NVIC_INT_CTRL = NVIC_PENDSVSET
(這個宏的作用是調用PendSV中斷。)
爲什麼和書上說的不一致呢?兩種完全不同的場景居然能使用同一個處理過程?
機關就在調用PendSV中斷這裏。uC/OSIII在Cortex-M3平臺下使用PendSV中斷進行任務的調度切換。而Cortex-M3的中斷進入前會自動保存8個寄存器 :xPSR, PC, LR, R12, R0-R3。
也就是說,無論是從任務中調用的任務切換還是從中斷退出中調用的任務切換,都是調用的PendSV中斷。這一點很重要,因此只要是任務切換,結果就是:在進入PendSV處理函數後,肯定有8個寄存器已經保存到原 thread的PSP中了(注意這個thread,uC/OSIII普通任務都是thread模式的,使用PSP。中斷進程叫handler模式,使用MSP。這也是Cortex-M3架構決定的)。
那從任務中調用任務切換和從中斷退出中調用的任務切換就沒有一點區別嗎?還是有一點的,從任務中調用任務切換是直接進入的PendSV中斷;從中斷退出中調用的任務切換是執行的咬尾中斷,先退出原中斷,然後進入PendSV中斷,具體區別就是:從任務中進入PendSV處理函數,那8個寄存器是PendSV中斷自己保存的;從中斷退出後進入PendSV處理函數那8個寄存器是原中斷保存的,不是PendSV保存的。但對PendSV處理函數而言,兩者並無區別,反正給我保存了就行了,不管到底是我自己保存的還是你替我保存的。
所以uC/OSIII在PendSV處理函數中的過程就是:一進來就保存剩下的8個寄存器:R4-R11。當然,要保存到PSP下面,這是原任務使用的堆棧,保存後就保證了原任務自己堆棧內容的完整,注意千萬別弄錯了保存到了MSP下面,MSP是中斷函數使用的。
然後就進行任務優先級查找,出棧全部寄存器,返回thread模式,執行新任務。
附PendSV處理函數的註釋:
Note(s) : 1) PendSV is used to cause a context switch. This is a recommended method for performing context switches with Cortex-M3. This is because the Cortex-M3 auto-saves half of the processor context on any exception, and restores same on return from exception. So only saving of R4-R11 is required and fixing up the stack pointers. Using the PendSV exception this way means that context saving and restoring is identical whether it is initiated from a thread or occurs due to an interrupt or exception.