赞
踩
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之后的地址开始分配的。
堆:是编译器调用动态内存分配的内存区域。
栈:是程序运行的时候局部变量的地方,所以局部变量用数组太大了都有可能造成栈溢出。
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]执行写操作也可以从主堆栈切换到进程堆栈。
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内存管,如果没有被使用的话,会被编译器优化掉
如有错误,敬请斧正
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。