关于 Cortex-M3 的双堆栈机制

 寄存器简介

Cortex-M 系列 CPU 的寄存器组里有 R0~R15 共 16 个通用寄存器组和若干特殊功能寄存器,如下图所示。下图中我看可以看到MSP和PSP两个堆栈指针寄存器。

关于 Cortex-M3 的双堆栈机制

通用寄存器组里的 R13 作为堆栈指针寄存器 (Stack Pointer,SP);R14 作为连接寄存器 (Link Register,LR),用于在调用子程序时,存储返回地址;R15 作为程序计数器 (Program Counter,PC),其中堆栈指针寄存器可以是主堆栈指针(MSP),也可以是进程堆栈指针(PSP)

Cortex-M 的堆栈寄存器 SP 对应两个物理寄存器 MSP 和 PSP,MSP 为主堆栈,PSP 为进程堆栈,处理模式总是使用 MSP 作为堆栈,线程模式可以选择使用 MSP 或 PSP 作为堆栈,同样通过 CONTROL 特殊寄存器控制。复位后,Cortex-M 默认进入线程模式、特权级、使用 MSP 堆栈。

CONTROL寄存器定义如下:  关于 Cortex-M3 的双堆栈机制

 关于 Cortex-M3 的双堆栈机制

中断栈

  •  在中断处理过程中,在系统响应中断前,软件代码(或处理器)需要把当前线程的上下文保存下来(通常保存在当前线程的线程栈中),再调用中断服务程序进行中断响应、处理;
  • 在进行中断处理时,中断处理函数中很可能会有自己的局部变量,这些都需要相应的栈空间来保存,所以中断响应依然需要一个栈空间来做为上下文,运行中断处理函数。中断栈可以保存在打断线程的栈中,当从中断中退出时,返回相应的线程继续执行;
  • RT-Thread 采用的方式是提供独立的中断栈,即中断发生时,中断的前期处理程序会将用户的栈指针更换到系统事先留出的中断栈空间中,等中断退出时再恢复用户的栈指针。这样中断就不会占用线程的栈空间,从而提高了内存空间的利用率,且随着线程的增加,这种减少内存占用的效果也越明显。
  • 在 Cortex-M 处理器内核里有两个堆栈指针,一个是主堆栈指针(MSP),是默认的堆栈指针,在运行第一个线程之前和在中断和异常服务程序里使用;另一个是线程堆栈指针(PSP),在线程里使用。在中断和异常服务程序退出时,修改 LR 寄存器的第 2 位的值为 1,线程的 SP 就由 MSP 切换到 PSP。保证我们从异常返回时是从PSP中的POP出来的数据到寄存器里,而不是从MSP中POP。

为什么会写LR寄存器的bit2为1呢?LR不是链接寄存器吗?查看Cortex-M系列权威指南有这样一句话The processor saves an EXC_RETURN value to the LR on exception entry. The exception mechanism relies on this value to detect when the processor has completed an exception handler. When the processor loads a value matching this pattern to the PC it detects that the operation is not a normal branch operation and, instead, that the exception is complete. As a result, it starts the exception return sequence. Bits[6:0] of the EXC_RETURN value indicate the required return stack, processor mode, and stack frame as the following table shows.

EXC_RETURN的定义如下图:

 

关于 Cortex-M3 的双堆栈机制

总结:采用的双独立栈的设计,即中断发生时,中断的前期处理程序会将用户的栈指针更换到系统事先留出的中断栈空间中,等中断退出时再恢复用户的栈指针。这样中断就不会占用线程的栈空间,从而提高了内存空间的利用率,且随着线程的增加,这种减少内存占用的效果也越明显。