打印
[通用 MCU]

MCU平台下确定栈空间大小的方法

[复制链接]
410|14
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2023-12-21 08:43 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
通常使用IDE开发MCU程序在生成Image文件时,Image文件被划分为代码区,数据区,BSS区,堆区,栈区。其中,代码区,数据区,BSS区空间大小由编译器最终决定,对于MCU,堆区一般设置为0,唯一不好确定的就是栈区空间的大小了。栈空间大小由非常关键,弄不好会导致栈溢出,后果非常严重。本文基于实测的方式,确定栈区空间的大小。

1.基本概念

栈空间分为静态栈空间和动态栈空间。

1)静态栈空间

静态栈空间大小一般可由编译器分析函数调用关系及调用深度来确定,顾名思义,它只能分析固定的函数调用关系,而我们的MCU程序运行过程中可能会有中断,造成函数的调用关系及深度是无法预料的,如果仅按静态栈大小来设置栈空间大小,很有可能是不够的。查看静态栈空间大小有助于我们确定最小的栈空间大小。

如Keil中可以在Link中增加“--callgraph”来生成静态调用图,其中也包括栈的使用,也可以用“--info=stack”或“--info=summarystack”列出所有全局符号的栈的使用情况。

2)动态栈空间

动态栈空间大小就是我们的程序在运行过程中(包含中断)的栈空间大小。实际使用的栈空间大小是动态变化的(随中断及函数调用而变化),确定栈空间的大小就是要确定动态栈空间最大能有多大,再预留一定的裕量,就是我们在编写程序时需要设置的栈空间大小。也是本文后续要介绍的。

2.方法&步骤

1)预先分配一个足够大的栈空间大小,这个空间在确定栈空间大小后会修改。这个在Keil中通过“startup.s”文件进行设置,在gcc编译器中可通过“.ld”文件确定。同时我们也知道栈顶的位置(通常在RAM空间的最后)。

2)编写一小段程序初始化这段栈空间大小为一个确定的数字,如“0xDEADDEAD”。代码如下:

InitStack(0x20003ffb, 0x400);

void InitStack(uint32_t Address, uint32_t nLength)
{
        while ((int32_t)nLength > 0)
        {
                *(volatile uint32_t *)Address = 0xDEADDEAD;
                Address -= 4;
        nLength -= 4;
        }
}
3)运行我们的程序,我们可以进行一系列的测试,包括外部中断及各种输入以确保程序执行中函数调用关系处于最深的情况。

4)当程序执行完毕后,我们检查2)中特定数值被修改的位置,这个位置和栈顶的偏移就是我们实际需要的栈空间大小。如我们使用JLink-Commander的“Mem32”指令可在程序运行过程中读取指定地址及长度的数据。指令如下(连接过程略):

Mem32 20003ffb  0x100
5)获得栈空间大小后,为了以防万一(步骤3)测试不充分),可以再保留一定的裕量(如50%),将此值作为最终的栈空间大小的设定值。
————————————————
版权声明:本文为CSDN博主「propor」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/propor/article/details/135064902

使用特权

评论回复
沙发
MessageRing| | 2023-12-26 10:22 | 只看该作者
栈空间可以自己调吗

使用特权

评论回复
板凳
jcky001| | 2023-12-26 11:26 | 只看该作者
首先,需要对应用程序的代码进行详细分析,了解函数调用的深度和每个函数使用的局部变量的大小。

使用特权

评论回复
地板
yangjiaxu| | 2023-12-27 21:50 | 只看该作者
MessageRing 发表于 2023-12-26 10:22
栈空间可以自己调吗

可以的,可以自己按需求进行修改,一般都是在启动文件里进行修改的

使用特权

评论回复
5
g0d5xs| | 2023-12-28 13:46 | 只看该作者
有些时候,只有在使用操作系统的时候会考虑修改堆栈这种

使用特权

评论回复
6
cen9ce| | 2023-12-28 14:50 | 只看该作者
我之前知道堆栈的时候,还是跑coremark的时候呢

使用特权

评论回复
7
q1ngt12| | 2023-12-28 16:02 | 只看该作者
其实修改这个只是为了让MCU可以稳定可靠的运行

使用特权

评论回复
8
su1yirg| | 2023-12-28 17:23 | 只看该作者
确定程序的最大递归深度:递归函数是一种函数调用自身的方式。确定程序中最深的递归调用深度可以帮助确定栈空间的最小大小

使用特权

评论回复
9
w2nme1ai7| | 2023-12-28 18:32 | 只看该作者
函数调用链是指函数之间的嵌套调用关系。确定程序中最深的函数调用链深度可以帮助确定栈空间的最小大小

使用特权

评论回复
10
suw12q| | 2023-12-28 19:40 | 只看该作者
局部变量和函数参数在函数调用时会被存储在栈空间中。确定每个函数中使用的局部变量和参数的大小,并将它们累加起来,可以得到栈空间的最小大小

使用特权

评论回复
11
q1d0mnx| | 2023-12-29 08:06 | 只看该作者
如果程序中使用了中断处理,需要考虑中断处理函数的栈空间需求。中断处理函数通常需要额外的栈空间来保存寄存器状态和临时变量

使用特权

评论回复
12
l1uyn9b| | 2023-12-29 09:17 | 只看该作者
需要考虑其他可能影响栈空间大小的因素,如编译器的优化选项、编译器生成的代码大小等

使用特权

评论回复
13
p0gon9y| | 2023-12-29 10:08 | 只看该作者
修改这个一般都是看推荐修改大小么

使用特权

评论回复
14
lix1yr| | 2023-12-29 12:36 | 只看该作者
其实仿真的时候可以看到使用的堆栈数据,可以自己再根据数据进行修改的

使用特权

评论回复
15
forgot| | 2023-12-29 19:44 | 只看该作者
需要对应用程序的代码进行详细分析,了解函数调用的深度和每个函数使用的局部变量的大小。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1536

主题

14520

帖子

9

粉丝