单片机堆栈小知识

目录

一、关于单片机堆栈的基础知识

1、STM32程序数据分类

2、STM32内存(RAM)分配

3、经典例子分析:

4、STM32堆栈位置

5、STM32栈增长方式

三、如何设置STM32的堆栈大小

1、MDK编译环境下

2、IAR 编译环境下

四、STM32单片机程序内存占用大小分析

1、MDK编译环境下

2、IAR编译环境下


一、关于单片机堆栈的基础知识

1、STM32程序数据分类

  • Code:程序代码
  • RO-data:const常量和指令
  • RW-data:初始化值不为0的全局变量
  • ZI-data:未初始化的全局变量 或 初始化值为0的全局变量

RO Size = Code + RO Data 表示程序运行时占用的FLASH大小

RW Size = RW Data + ZI Data 表示占用RAM大小

ROM Size = Code + RO Data + RW Data 表示烧写程序后占用的FLASH大小

2、STM32内存(RAM)分配

一个由C/C ++编译的程序占用的内存可分为以下几个部分:

  • 栈(stack):由编译器自动分配释放,存放函数的参数值,局部变量的值等。
  • 堆(heap):存放程序运行中被动态分配的内存,一般由程序员分配释放,若程序员不释

放,程序结束时可能由OS回收。

  • bss段:通常是指用来存放程序中未初始化的全局变量的一块内存区域,存放ZI-data数据
  • data段:通常是指用来存放程序中已初始化的全局变量的一块内存区域,存放RW-data数据

FLASH占用大致以下两个部分:

  • 文字常量区(const) :常量字符串就是放在这里的。
  • 程序代码区 (code): 存放函数体的二进制代码

3、经典例子分析:

int a = 0;              //全局初始化区
char *p1;               //全局未初始化区
main()
{
  int b;                //栈
  char s[] = "abc";     //栈
  char *p2;             //栈
  char *p3 = "123456";  //123456\0在常量区,p3在栈上。
  static int c =0;//全局(静态)初始化区
  p1 = (char *)malloc(10);
  p2 = (char *)malloc(20);   //分配得来得10和20字节的区域就在堆区。
  strcpy(p1, "123456");      //123456\0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
}

在MDK编译环境下,可在map文件的"Memory Map of the image"-->"Execution Region RW_IRAM1"内容中查看程序的RAM占用及分配情况,如下【图一】【图二】

                                                                                                              【图一】

                                                                                                                【图二】

4、STM32堆栈位置

首先看一下STM32的地址空间映射【图三】,STM32的堆栈就是存放在片上静态SRAM中的,地址分配可以见Keil的编译map文件的"Memory Map of the image"【图四】;可见堆的地址为0x20000a08,大小为0x200,栈的地址为 0x20000c08,大小为0x400,可推算栈顶地址为:0x20000c08 + 0x400 = 0x20001008。而程序在刚运行的时候,主堆栈指针MSP指向的是程序所占用内存的最高地址【图五】,也就是栈的栈顶地址。

                                                                                                     【图三】

                                                                                                    【图四】

                                                                                                          【图五】

5、STM32栈增长方式

STM32的栈增长方式是向下增长的,也就是程序运行后,SP指针从栈顶地址开始往下给函数的局部变量分配地址 。可以通过如下代码来测试STM32单片机的栈增长方式。

//保存栈增长方向 0,向下增长;1,向上增长.
static unsigned char stack_dir;

//查找栈增长方向,结果保存在stack_dir里面.
void find_stack_direction(void)
{
    static u8 *addr = NULL; //用于存放第一个dummy的地址。
    u8 dummy;               //用于获取栈地址 
    if(addr == NULL)        //第一次进入
    {                          
        addr = &dummy;     //保存dummy的地址
        find_stack_direction ();  //递归 
    }
    else                //第二次进入 
    {  
        if(&dummy > addr)stack_dir=1; //第二次dummy的地址大于第一次dummy,那么说明栈增长方向是向上的. 
        else stack_dir=0;             //第二次dummy的地址小于第一次dummy,那么说明栈增长方向是向下的.  
    }
} 

三、如何设置STM32的堆栈大小

1、MDK编译环境下

通过修改.s启动文件中的 Stack_Size 和 Heap_Size大小

2、IAR 编译环境下

通过修改Linker-->Config中的CSTACK和HEAP大小

四、STM32单片机程序内存占用大小分析

map文件:通过编译器编译之后,集程序、数据及IO空间的一种映射文件。通过map文件可以知道函数大小,入口地址等一些重要信息。

1、MDK编译环境下

编译后的map文件大致有如下几个部分:在分析内存占用时主要看d、e段就行

a、Section Cross References:模块、段(入口)交叉引用

b、Removing Unused input sections from the image:移除未调用模块

c、Image Symbol Table:映射符号表

d、Memory Map of the image:内存(映射)分布,包括存储地址和运行地址分布

e、Image component sizes:存储组成大小,列出了各个文件中各种数据占用的内存大小

2、IAR编译环境下

编译后的map文件大致有如下几个部分:

a、MAIN INIF:关于map文件的主要信息。包含:IAR版本、日期、输出文件路径等

b、RUNTIME MODEL ATTRIBUTES:运行时MODEL属性

c、PLACEMENT SUMMARY:概述位置,即各Section(段)存储的位置

大致意思为:

"A0"段位于0x08000000,类型为intvec(初始化向量);

"P1"段位于0x08000000 至 0x0807ffff区域,类型为 ro;

"P2"段位于0x20000000 至0x2000ffff区域,类型包含:rw, block CSTACK;

段与类型一般有对应关系:

     Section         Kind

"A1": 

     .intvec           ro code(ro代码)

"P1":

     .text             ro code(ro代码)

     .rodata          const (常量)

     CODE           ro code(ro代码)

     .iar.init_table     const(常量)

     Initializer bytes   ro data(ro数据)

"P2":

     .data           inited(已初始化数据)

     .bss            zero(未初始化数据 零)

d、INIT TABLE:初始化表

e、MODULE SUMMARY:概述模块,文件所占ro代码大小、rw数据大小

f、ENTRY LIST:入口列表,包含函数、变量等入口地址

h、最后就是程序所占用的code、RO-data、RW-data

发布了35 篇原创文章 · 获赞 22 · 访问量 1151

猜你喜欢

转载自blog.csdn.net/m0_37845735/article/details/103301528