天天看點

【RTOS】堆棧與任務棧

目錄

前言

概念

雙堆棧指針要點

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(浮點運算單元)也要壓棧)

通用寄存器組:

【RTOS】堆棧與任務棧

特殊功能寄存器組:

【RTOS】堆棧與任務棧

通用寄存器 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通用寄存器

可能有用的參考中斷與子程式調用問題