uC/OSIII在Cortex-M3的任務切換和中斷退出分析
但是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.