目錄
前言
本筆記基於 stm32+FreeRTOS。
概念
雙堆棧指針
Cortex-M3 和 M4內核具有雙堆棧指針。MSP 和 PSP
- MSP:主堆棧指針
- PSP:進程棧指針
要點
- 用戶程序、中斷和中斷嵌套都是用 MSP。
- M3 內核所有寄存器壓棧時有64B。
- M4 內核所有寄存器壓棧時有200B。(因為FPU(浮點運算單元)也要壓棧)
Cortex-M3寄存器介紹
寄存器圖
通用寄存器組:
特殊功能寄存器組:
簡要介紹
-
通用寄存器 R0-R7
- R0-R7被稱為低組寄存器。
- 所有指令都能訪問它們。
- 字長全是32位,復位后不可預料。
-
通用寄存器 R8-R12
- R0-R7被稱為高組寄存器。
- 只有很少16位Thumb指令能訪問它們,32位指令不受限制。
- 字長全是32位,復位后不可預料。
-
堆棧指針 R13(SP)
- CM3處理器內核中央有兩個堆棧指針,分別是MSP和PSP。
- 當前使用MSP,則PSP只能通過特殊指令(MRS,MSR指令)來訪問。
- MSP:主堆棧指針
- 缺省的堆棧指針,由OS內核、異常服務例程及所有需要特權訪問的應用程序代碼來使用。
- PSP:線程堆棧指針
- 用於常規的應用程序代碼。
- 注意:並不是每個應用都需要兩個堆棧指針,簡單的應用程序只需要MSP即可
-
連接寄存器 R14(LR)
- 保存調用子程序時返回的地址
-
連接寄存器 R15(PC)
知識
出入棧
出入棧用於上下文切換。
- 例子:stm32F103自動出入棧的寄存器有 R0-R3,R12,LR,PC,xPSR
入棧(壓棧)
入棧:上文保存
- 先自動壓棧(進入異常時,硬件自動完成)
- 再手動壓棧
出棧
出棧:下文加載
- 先手動出棧
- 再自動出棧(退出異常時,硬件自動完成)
重點知識
異常的響應序列*
參考《Cortex-M3 權威指南》第九章
當CM3開始響應一個中斷時,會在它看不見的體內奔涌起三股暗流:
- 入棧:把8個寄存器的值壓入棧(硬件完成)
- 取向量:從向量表中找出對應的服務程序入口地址
- 選擇堆棧指針MSP/PSP,更新堆棧指針SP,更新連接寄存器LR,更新程序計數器PC
入棧
取向量
更新寄存器
在入棧和取向量的工作都完畢之后,執行服務例程之前,還要更新一系列的寄存器:
- SP:在入棧中會把堆棧指針(PSP或MSP)更新到新的位置。在執行服務例程后,
將由MSP負責對堆棧的訪問。 - PSR:IPSR位段(地處PSR的最低部分)會被更新為新響應的異常編號。
- PC:在向量取出完畢后,PC將指向服務例程的入口地址,
- LR:LR的用法將被重新解釋,其值也被更新成一種特殊的值,稱為“EXC_RETURN”,並且在異常返回時使用。EXC_RETURN的二進制值除了最低4位外全為1,而其最低4位則有另外的含義。
以上是在響應異常時通用寄存器的變化。另一方面,在NVIC中,也伴隨着更新了與之相關的若干寄存器。例如,新響應異常的懸起位將被清除,同時其活動位將被置位。
小結知識*
- Cortex-M3 中發生異常時,會硬件壓棧;
- Cortex-M3 函數調用時是不會硬件壓棧的,需要軟件壓棧。但是,用C語言時編譯器會自動生成壓棧的匯編語句。若用匯編編寫,則需要手寫壓棧。
- 網友一句很好理解的話:
- 當程序跳到中斷向量表時就會硬件自動壓棧
- 網友一句很好理解的話:
- 進入異常后,異常不用LR寄存器(R14)保存返回地址,但是需要使用LR寄存器觸發異常返回機制
FreeRTOS任務切換源碼分析
__asm void xPortPendSVHandler( void )
{
extern uxCriticalNesting;
extern pxCurrentTCB;
extern vTaskSwitchContext;
PRESERVE8
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}
mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
msr basepri, r0
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 and the critical nesting count. */
msr psp, r0
isb
bx r14
nop
- stmdb sp!, {r3, r14}
- r3 壓棧保護,因為調用函數vTaskSwitchContext時可能會用到 r3 寄存器。
- r14 壓棧保護,因為調用函數vTaskSwitchContext時,r14將被改寫。
話語
- 任務切換的時候,在PendSV中斷函數中,由於任務使用 PSP ,中斷使用 MSP。如果在中斷函數中調用函數或者中斷嵌套時,壓棧2,會覆蓋 R14。PendSV結束返回時找不到正確的返回機制。
參考
重要參考 《Cortex-M3權威指南》
主要參考野火、安富萊。
主要參考鏈接Cortex-M3通用寄存器
可能有用的參考中斷與子程序調用問題