痞子衡嵌入式:ARM Cortex-M内核那些事(6)- 系统堆栈机制


  你们好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给你们介绍的是ARM Cortex-M堆栈机制html

  今天给你们分享的这篇依旧是2016年以前痞子衡写的技术文档,花了点时间从新编排了一下格式。前面痞子衡讲过 《嵌入式里的堆栈原理》,本篇算是堆栈原理的工程实践,更具体点说是在ARM Cortex-M上的应用。ARM Cortex-M家族发展至今已经不少代,咱们且以最简单的Cortex-M0为例来说述堆栈机制:微信

1.基本规则

1.1 R13 / sp寄存器

  R0-R12为通用寄存器,R13为系统堆栈指针sp,堆栈指针是用于访问堆栈,也即系统的RAM区。Cortex-M0中采用了两个堆栈指针:主堆栈指针(MSP)和进程堆栈指针(PSP),R13在任什么时候刻只能是其中一个,默认状况为MSP,能够经过控制寄存器(CONTORL)来改变。app

  MSP是系统复位后(即其处于Handler Mode)的指定sp(vector table的前4Byte自动载入),用于处理异常中断。当结束Reset_Handler后,cpu进入正常运行状态(即其处于Thread Mode),仅在此状态下PSP才能被使用,固然MSP也可使用。其后若有硬中断来临,则进入Handler Mode,若是硬件中断结束,则返回Thread Mode。函数

  关于MSP和PSP的选用,其是经过CONTORL寄存器来配置,仅在Thread Mode下才可设置CONTORL寄存器。通常状况下,没有必要使用PSP,除非是有os存在时,MSP用于os内核的sp,而PSP用于thread级app的sp,这两个sp需严格分开。
  在编译器中,能够经过r13(R13)或sp(SP)来访问堆栈(具体是MSP和PSP由当时环境决定);也能够经过指定的MRS、MSR指令来访问MSP和PSP。.net

1.2栈结构

  无OS的堆栈结构:3d

  有OS的堆栈结构:指针

1.3栈操做

  Cortex-M0中堆栈方向是向低地址方向增加,为满堆栈机制。堆栈操做是经过PUSH和POP来完成操做的。htm

  栈通常放在ARM的 RAM高位区,如某MCU中RAM地址为0x20000000-0x20007fff,共32KByte。栈大小设为4KByte的话,其地址通常就放在0x20007000-0x20007fff,其中0x20007000为绝对栈顶,0x20007ffc为绝对栈底,sp老是指向相对栈顶。第一个PUSH数据被存在绝对栈底(此时绝对栈底也是相对栈顶)。实际上,除了POP指令能够从栈顶中取数据外;MOV指令也可从任意位置取数据,但不会影响栈结构(即不影响其sp)。
  因为ARM寄存器均是32bit,故PUSH和POP指令均是32bit访问,故sp指针老是至少4Byte对齐(低2bit永远为0)。有时编译器也会分配8Byte对齐的栈,这是因为double浮点类型须要占用8Byte,为了处理方便,故将栈设为8Byte对齐。blog

2.入栈顺序

  入栈顺序因编译器、处理器系统、OS而异,C语言中并无强制规定入栈顺序,此处主要是讲ARM Cortex-M系列处理器在指定编译器状况下的入栈顺序。进程

2.1通常函数调用(通用)

  上图展现了在通常函数(无参无局部变量无返回值)嵌套调用时,关于sp的操做。在执行BL FunctionA指令时,LR记录的是BL FunctionA的下一条顺序指令,在进入FunctionA后执行的第一条操做即是PUSH {LR}即将下一条顺序指令压入栈中,而后才开始执行FunctionA函数体。函数体执行结束以后,使用POP {PC}指令将栈顶数据弹到PC中,便可返回继续执行BL FunctionA的下一条顺序指令。

2.2极端函数调用(平台而异)

  考虑一种极端状况来详细讲述入栈顺序,即函数含有4个参数以上,函数体内定义了多个局部变量,而且还有返回值。这个状况比较特殊,痞子衡专门在IAR上作过一次实验,详见下图:

  至此,ARM Cortex-M堆栈机制痞子衡便介绍完毕了,掌声在哪里~~~

欢迎订阅

文章会同时发布到个人 博客园主页CSDN主页微信公众号 平台上。

微信搜索"痞子衡嵌入式"或者扫描下面二维码,就能够在手机上第一时间看了哦。

相关文章
相关标签/搜索