痞子衡嵌入式:ARM Cortex-M内核那些事(6)- 系统堆栈机制
大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是ARM Cortex-M堆栈机制。
今天给大家分享的这篇依旧是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)来改变。
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。
1.2栈结构
无OS的堆栈结构:
有OS的堆栈结构:
1.3栈操作
Cortex-M0中堆栈方向是向低地址方向增长,为满堆栈机制。堆栈操作是通过PUSH和POP来完成操作的。
栈一般放在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对齐。
2.入栈顺序
入栈顺序因编译器、处理器系统、OS而异,C语言中并没有强制规定入栈顺序,此处主要是讲ARM Cortex-M系列处理器在指定编译器情况下的入栈顺序。
2.1一般函数调用(通用)
上图展示了在一般函数(无参无局部变量无返回值)嵌套调用时,关于sp的操作。在执行BL FunctionA指令时,LR记录的是BL FunctionA的下一条顺序指令,在进入FunctionA后执行的第一条操作便是PUSH 即将下一条顺序指令压入栈中,然后才开始执行FunctionA函数体。函数体执行结束之后,使用POP 指令将栈顶数据弹到PC中,即可返回继续执行BL FunctionA的下一条顺序指令。
2.2极端函数调用(平台而异)
考虑一种极端情况来详细讲述入栈顺序,即函数含有4个参数以上,函数体内定义了多个局部变量,并且还有返回值。这个情况比较特殊,痞子衡专门在IAR上做过一次实验,详见下图:
至此,ARM Cortex-M堆栈机制痞子衡便介绍完毕了,掌声在哪里~~~
欢迎订阅
文章会同时发布到我的 博客园主页、CSDN主页、微信公众号 平台上。
微信搜索"痞子衡嵌入式"或者扫描下面二维码,就可以在手机上第一时间看了哦。
- 基于ARM 的嵌入式系统程序开发要点--(四)异常处理机制的设计
- Linux嵌入式 -- 内核 (arm) & 文件系统
- 嵌入式系统的组成、嵌入式处理器分类总结、ARM处理器系列总结、ARM Cortex-M3体系结构总结!
- 【嵌入式系统】ARM Cortex-A8体系结构
- 痞子衡嵌入式:Ethos-U55,ARM首款面向Cortex-M的microNPU
- 痞子衡嵌入式:单片机AI的春天已来,ARM Cortex-M55发布了
- 【课程升级】华清远见ARM Cortex-A9 四核平台全面应用嵌入式系统教学
- Linux嵌入式 -- 内核 (arm) & 文件系统
- Arm linux 内核移植及系统初始化过程分析
- ARM内核目标系统中的代码运行时间测试
- 小梅科普:ARM Cortex-A8和Android 4.x的联动报警系统
- 【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】全面解析Linux内核的同步与互斥机制--互斥篇
- 嵌入式linux系统网络超级服务器构建指南(for arm)
- Linux系统内核定时器机制详解
- 利用内核cgroup机制轻松实现类似docker的系统资源管控
- STM32F系列ARM Cortex-M3核微控制器基础之系统时钟二
- 在VM上学习嵌入式Linux系统的构建之一--编译内核
- opencv嵌入式ARM系统中安装
- 嵌入式系统系统升级内核双备份的实现方式
- ARM内核全解析,从ARM7,ARM9到Cortex-A7,A8,A9,A12,A15到Cortex-A53,A57