STM32 堆栈的理解

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

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

MDKCode,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编译之后能够得到的每个段的大小,也就能得到占用相应的FLASHRAM的大小,但是还有两个数据段也会占用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

STM32 堆栈的理解_第1张图片

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

STM32 堆栈的理解_第2张图片


3、进一步验证

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

STM32 堆栈的理解_第3张图片


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

STM32 堆栈的理解_第4张图片

4、结论

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

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

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


附:

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

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

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

STM32 堆栈的理解_第5张图片


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

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

STM32 堆栈的理解_第6张图片



如有错误,敬请斧正


你可能感兴趣的:(STM32,C,keil)