目錄
前言
概念
雙堆棧指針要點
Cortex-M3寄存器介紹
寄存器圖
簡要介紹
知識
出入棧
入棧(壓棧)
出棧
重點知識
異常的響應序列*
入棧
取向量
更新寄存器
小結知識*
FreeRTOS任務切換源碼分析
話語
參考
本筆記基于 stm32+FreeRTOS。
李柱明部落格:https://www.cnblogs.com/lizhuming/
本文連結:https://www.cnblogs.com/lizhuming/p/13811237.html
Cortex-M3 和 M4核心具有雙堆棧指針。MSP 和 PSP
MSP:主堆棧指針
PSP:程序棧指針
使用者程式、中斷和中斷嵌套都是用 MSP。
M3 核心所有寄存器壓棧時有64B。
M4 核心所有寄存器壓棧時有200B。(因為FPU(浮點運算單元)也要壓棧)
通用寄存器組:

特殊功能寄存器組:
通用寄存器 R0-R7
R0-R7被稱為低組寄存器。
所有指令都能通路它們。
字長全是32位,複位後不可預料。
通用寄存器 R8-R12
R0-R7被稱為高組寄存器。
隻有很少16位Thumb指令能通路它們,32位指令不受限制。
堆棧指針 R13(SP)
CM3處理器核心中央有兩個堆棧指針,分别是MSP和PSP。
目前使用MSP,則PSP隻能通過特殊指令(MRS,MSR指令)來通路。
預設的堆棧指針,由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寄存器觸發異常傳回機制
stmdb sp!, {r3, r14}
r3 壓棧保護,因為調用函數vTaskSwitchContext時可能會用到 r3 寄存器。
r14 壓棧保護,因為調用函數vTaskSwitchContext時,r14将被改寫。
任務切換的時候,在PendSV中斷函數中,由于任務使用 PSP ,中斷使用 MSP。如果在中斷函數中調用函數或者中斷嵌套時,壓棧2,會覆寫 R14。PendSV結束傳回時找不到正确的傳回機制。
重要參考 《Cortex-M3權威指南》
主要參考野火、安富萊。
主要參考連結Cortex-M3通用寄存器
可能有用的參考中斷與子程式調用問題