×
单片机 > 单片机程序设计 > 详情

STM32 堆栈的理解

发布时间:2020-06-03 发布时间:
|

1、MDK STM32的内存分配 (摘自网络)


C语言上分为栈、堆、bss、data、code段。具体每个段具体是存储什么数据的,直接百度吧。重点分析一下STM32以及在MDK里面段的划分。


MDK下Code,RO-data,RW-data,ZI-data这几个段:


Code是存储程序代码的。


RO-data是存储const常量和指令。


RW-data是存储初始化值不为0的全局变量。


ZI-data是存储未初始化的全局变量或初始化值为0的全局变量。


Flash=Code + RO Data + RW Data;


RAM= RW-data+ZI-data;


这个是MDK编译之后能够得到的每个段的大小,也就能得到占用相应的FLASH和RAM的大小,但是还有两个数据段也会占用RAM,但是是在程序运行的时候,才会占用,那就是堆和栈。在stm32的启动文件.s文件里面,就有堆栈的设置,其实这个堆栈的内存占用就是在上面RAM分配给RW-data+ZI-data之后的地址开始分配的。


堆:是编译器调用动态内存分配的内存区域。


栈:是程序运行的时候局部变量的地方,所以局部变量用数组太大了都有可能造成栈溢出。


2、M3手册相关内容


1、 工作模式

Cortex-M3 处理器支持两种工作模式,线程模式和处理模式:

1) 在复位时处理器进入线程模式, 异常返回时也会进入该模式。 特权和用户(非特权)


代码能够在线程模式下运行。


2) 出现异常时处理器进入处理模式,在处理模式中,所有代码都是特权访问的。


2、特权访问和用户访问

代码可以是特权执行或非特权执行。 非特权执行时对有些资源的访问受到限制或不允许

访问。特权执行可以访问所有资源。处理模式始终是特权访问,线程模式可以是特权或非特

权访问。

线程模式在复位之后为特权访问,但可通过 MSR 指令清零 CONTROL[0],将它配置为

用户(非特权)访问。用户访问禁止:

1) 部分指令的使用,例如设置 FAULTMASK 和 PRIMASK 的 CPS 指令。

2)对系统控制空间(SCS)的大部分寄存器的访问。


当线程模式从特权访问变为用户访问后,本身不能回到特权访问。只有处理操作能够改


变线程模式的访问特权。处理模式始终是特权访问的。


3、主堆栈和进程堆栈

结束复位后,所有代码都使用主堆栈。异常处理程序(例如 SVC)可以通过改变其在

退出时使用的 EXC_RETURN 值来改变线程模式使用的堆栈。所有异常继续使用主堆栈,堆

栈指针 r13 是分组寄存器,在 SP_main 和 SP_process 之间切换。在任何时候,进程堆栈和主

堆栈中只有一个是可见的,由 r13 指示。

除了使用从处理模式退出时的 EXC_RETURN 的值外,在线程模式中,使用 MSR 指令

对 CONTROL[1]执行写操作也可以从主堆栈切换到进程堆栈。


3、关于STM32的 主堆栈指针 和 进程堆栈指针 


1、RTOS调用sheduler之前,起作用的是MSP,PSP的值是00000

2、sheduler之后 , RTOS进入运行状态,在task的代码中时此时,起作用的是PSP栈指针 (图示为idel task)

3、进一步验证


在任务调度的代码中设置断点,任务调度过程一定不属于任何一个task。从断点看,任务调度过程使用的是MSP

继续debug,单步至调度过程结束,进入一个task代码,此时栈指针立刻切换到PSP。

4、结论


单片机启动时运行MSP栈,RTOS在执行调度时使用的是MSP


RTOS task运行时,使用的是当前task的栈,栈指针使用的是PSP


即粗略地可以认为 task代码段使用的都是PSP指针,而非task代码段使用任然是MSP指针


附:


1、查找系统栈的起始地址。


map文件中,关于栈的起始地址和大小都有描述。起始地址即栈的栈底地址,栈顶地址为栈低地址加上栈大小的地址


栈的设置如文件中描述,在arm_startup_nrf52.c中

2、在map中,查看heap的情况


startup文件中申请的heap内存管,如果没有被使用的话,会被编译器优化掉

如有错误,敬请斧正



『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
采用AT89C2051的数字可调稳压电源单片机源程序