知識點:
MSP:主堆棧指針,系統復位后,默認使用MSP指針,MSP指針用於操作內核以及處理異常和中斷(異常是中斷的一種,中斷服務程序默認強制使用MSP指針,這是硬件自動設置的)
不使用OS,非中斷函數和中斷函數都使用MSP
PSP:進程堆棧指針,任務(進程)使用PSP指針,在vPortSVCHandler中斷服務函數中,通過修改 R14 的值從MSP指針切換到PSP指針
使用OS,main函數和中斷使用MSP,各個task使用PSP
R13: 堆棧指針SP,分為MSP和PSP
在執行異常的時候,SP以MSP為棧指針,在執行任務時SP以PSP為棧指針
每個任務都有一個任務棧
棧的地址是從高往低生長,棧指針最低兩位永遠是0,意味着棧總是4字節對齊
任務TCB數據結構第一個成員是一個指針變量(pxTopOfStack),指向任務當前棧的棧頂
R14作用:連接寄存器。調用子函數時存儲返回地址;異常(中斷)發生時,R14中保存異常返回標志,包括返回后進入線程模式還是處理器模式、指定SP使用PSP堆棧指針還是MSP堆棧指針。當調用 BX r14 指令后,硬件會知道要從異常返回,然后出棧,這個時候堆棧指針PSP已經指向了新任務堆棧的正確位置,當新任務的運行地址被出棧到PC寄存器后,新的任務也會被執行。
PC(R15):程序計數器,記錄下一個要執行指令的地址,改變它的值就能改變程序的執行流
R0:任務形參
通用寄存器:用於數據操作
切換流程:
1、進入PendSV中斷前,硬件自動將xPSR、PC(R15)、LR(R14)、R12、R0~R3壓入任務堆棧中(使用PSP堆棧指針)
2、手動將R4~R11壓入堆棧,將PSP棧頂值存入TCB(任務控制塊)
3、關 FreeRTOS 可屏蔽中斷
4、調用任務切換函數獲得新的任務控制塊
5、開中斷
6、通過新的任務控制塊更新PSP棧頂值,手動將R4~R11出棧
7、退出中斷時,硬件自動將xPSR、PC、LR、R12、R0~R3任務堆棧中出棧(使用PSP堆棧指針)
8、根據新的寄存器值和PSP執行新的任務
xPortPendSVHandler: mrs r0, psp isb ldr r3, =pxCurrentTCB /* Get the location of the current TCB. */ ldr r2, [r3] stmdb r0!, {r4-r11} /* Save the remaining registers. */ str r0, [r2] /* Save the new top of stack into the first member of the TCB. */ stmdb sp!, {r3, r14}
/* 接下來兩句是進入臨界區,即關FreeRTOS可屏蔽中斷 */ mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY msr basepri, r0 dsb isb bl vTaskSwitchContext
/* 接下來兩句是退出臨界區,即開中斷 */ mov r0, #0 msr basepri, r0 ldmia sp!, {r3, r14} ldr r1, [r3] ldr r0, [r1] /* The first item in pxCurrentTCB is the task top of stack. */ ldmia r0!, {r4-r11} /* Pop the registers. */ msr psp, r0 isb bx r14
isb:清流水線,保證此操作完成后再執行下一條指令
ldr r3, =pxCurrentTCB:pxCurrentTCB是一個指針,相當於兩個指針變量的賦值操作
ldr r2, [r3]:把r3指向的內容賦值給r2,因為指針pxCurrentTCB指向的結構體第一個成員變量是一個指針(pxTopOfStack),執行棧頂,所以此時 r2 為第一個成員變量指針
stmdb r0!, {r4-r11}:先將 r0 指向的地址遞減,再以新 r0 將 CPU 的 R4-R11 手動入棧,此時 R0 具體指向如下圖:
str r0, [r2]:將R2指向的內容更新為R0的值,即將棧頂值存到第一成員指針變量指向的位置,完成了上文的保存
stmdb sp!, {r3, r14}:將 R3 和 R14 入棧,此刻的 SP 指向 MSP。對這兩個寄存器入棧的原因:此刻的 R3 指向了 pxCurrentTCB(R3 保存了 pxCurrentTCB 的地址),在接下來的函數調用可能被修改,而這個值在函數調用后還要用到;R14 值在函數調用后同樣要用到,而函數調用會修改 R14 的值(存儲調用子函數后的返回地址)
ldr r1, [r3]: 調用函數 vTaskSwitchContext 后,pxCurrentTCB指向的內容就是新的TCB,進而 R3 指向的內容也是新的TCB
參考鏈接:
https://blog.csdn.net/qingzhuyuxian/article/details/80604129
https://blog.csdn.net/qq_15100379/article/details/86166994