taskYIELD()任務切換
#define taskYIELD() portYIELD()
#define portYIELD() \
{ \
/* 向中斷控制寄存器bit28位寫入1,将PendSV中斷設定為挂起狀态,
等到優先級高于PendSV的中斷執行完成後,PendSV中斷服務函數将被執行,進行任務切換工作 */ \
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \
__dsb( portSY_FULL_READ_WRITE ); \
__isb( portSY_FULL_READ_WRITE ); \
}
xPortPendSVHandler( )中斷服務函數
__asm void xPortPendSVHandler( void )
{
extern uxCriticalNesting; /*臨界段嵌套計數器,初始化為0xaaaaaaaa,排程器啟動後初始化為0,每進入一次臨界段+1*/
extern pxCurrentTCB; /* 指向目前激活的任務 */
extern vTaskSwitchContext;
PRESERVE8
mrs r0, psp /* PSP内容存入R0 */
isb /* 指令同步隔離,清流水線 */
ldr r3, =pxCurrentTCB /* 将目前指向的TCB的位址賦給R3 */
ldr r2, [r3] /* 将TCB賦給R2 */
stmdb r0!, {r4-r11} /* 以r0為基址,指針先遞減再操作,儲存r4-r11寄存器入棧,并更新r0的值,r0最終指向r4*/
str r0, [r2] /* 将棧頂指針賦給r0 */
stmdb sp!, {r3, r14} /* 将R3和R14臨時壓入堆棧,因為即将調用函數vTaskSwitchContext,調用函數時,傳回位址自動儲存到R14中,是以一旦調用發生,
R14的值會被覆寫,是以需要入棧保護; R3儲存的目前激活的任務TCB指針(pxCurrentTCB)位址,函數調用後會用到,是以也要入棧保護*/
mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
msr basepri, r0 /* 屏蔽中斷,進入臨界區 */
dsb /* 資料和指令同步隔離 */
isb
bl vTaskSwitchContext /* 調用函數,尋找新的任務運作,通過使變量pxCurrentTCB指向新的任務來實作任務切換 */
mov r0, #0 /* 開中斷,退出臨界區*/
msr basepri, r0
ldmia sp!, {r3, r14} /* 恢複R3和R14*/
ldr r1, [r3] /* 将TCB賦給r1*/
ldr r0, [r1] /* 将目前激活的任務TCB的棧頂指針存入R0*/
ldmia r0!, {r4-r11} /* r4-r11出棧*/
msr psp, r0 /*更新psp指針的值,将最新的棧頂指針賦給psp*/
isb
bx r14 /* 異常發生時,R14中儲存異常傳回标志,包括傳回後進入線程模式還是處理器模式、使用PSP堆棧指針還是MSP堆棧指針,
當調用 bx r14指令後,硬體會知道要從異常傳回,然後出棧,這個時候堆棧指針PSP已經指向了新任務堆棧的正确位置,
當新任務的運作位址被出棧到PC寄存器後,新的任務也會被執行。*/
nop
}
taskSELECT_HIGHEST_PRIORITY_TASK()尋找最高優先級任務
vTaskSwitchContext()函數實際上是調用
taskSELECT_HIGHEST_PRIORITY_TASK()這個函數
#define taskSELECT_HIGHEST_PRIORITY_TASK() \
{ \
UBaseType_t uxTopPriority; \
\
/* 尋找最高優先級并加入就緒清單中 */ \
portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority ); \
/* 就緒清單中找到最高優先級任務的TCB,然後更新到 pxCurrentTCB */
listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); \
}