0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何评估TI C2000系列微控制器程序的堆栈使用情况

电子设计 来源:电子设计 作者:电子设计 2022-01-19 16:17 次阅读

Other Parts Discussed in Post:C2000WARE

作者: Sheldon He

摘要:实时控制器往往拥有十分有限的存储器资源特别是片内的随机存储器(RAM)资源。能否合理、高效的运用这些资源不仅关乎到整个嵌入式系统的实现成本与性能,更涉及到系统在运行时是否会出现致命且不易被发现的错误。本文将对C2000系列微控制器的栈 (亦习惯性的被称为堆栈,这里请注意堆与栈之间的区别)做简单的介绍,并提出四种方法来对应用程序运行所需的栈空间大小进行追踪或评估,以帮助开发者在开发过程中(尤其是使用C/C++高级语言进行开发时)优化内存资源的使用并避免嵌入式程序可能存在的风险。

在计算机中,栈作为一种数据结构可以存放一系列的成员并且通过“入栈”和“出栈”操作来从栈定加入新的数据或从栈顶拿走数据。从类别上来看堆栈通常又可以分为软件堆栈和硬件堆栈两类,前者时常经由数组和链表在程序中实现而后者则与计算机架构相关并被用于实现内存的分配及访问。

本文要讨论的是C2000系列微控制器C28x内核中的硬件堆。该栈的典型特点为有一个固定的起始地址,或者说是寄存器复位值,和一个由编译器指定的可变的栈空间大小。C28x内核的堆栈指针(stack point)寄存器SP是16位寄存器,且在使用时高16位保持为0,故可以访问64K大小的内存空间。在芯片复位时,SP的内容变为0x00000400,且在使用时栈由低地址向高地址生长。堆栈的合法使用空间通常由编译器命令--stack_size= size来设定,其中size是一个常数,指定了栈空间的大小(以16位字为单位),栈的空间不得超过实际非初始化物理内存区域.stack大小也不得超出0xFFFF范围,否则将产生溢出。

一个嵌入式系统软件常常会因为多种原因而需要使用堆栈,这些原因包括:存储数学表达式的中间计算结果、在函数递归时存储每一次调用的函数返回地址、存放函数内的局部变量、存放传递进函数的参数等。随着软件流程变得越来越庞大复杂,如何正确的评估所需的堆栈空间就显得十分重要。分配过多的堆栈空间会“浪费”内存,堆栈溢出则可能造成堆栈信息丢失或者修改到邻近内存区域的数据并最终导致系统出错。

本文总结了四种适用于TI C2000系列MCU的堆栈使用评估方法,同时建议读者在有条件的情况下使用多种方法交叉验证以弥补单一方法使用过程中的局限性。这些方法通常情况下也适用于TI的其他部分嵌入式产品,对于其他各类嵌入式系统的堆栈测试、评估也有一定的借鉴意义。

一、使用TI提供的XML文件处理脚本生成函数调用图并进行静态分析

通过函数的调用关系可以静态的分析堆栈的使用情况,TI提供了一套基于Perl的脚本工具可以用于分析工程build过程中产生的XML文件以提供程序空间使用相关的信息。这里笔者需要用到的是该工具包中的call_graph.pl脚本来生成函数调用图(Call Graph)。

首先需要在wiki页面中下载并安装该工具包,可以在搜索引擎中检索关键字“Code_Generation_Tools_XML_Processing_Scripts”

并找到对应的ti.com页面进行下载安装。对于不熟悉命令行操作的读者可以按照以下三个步骤来使用该脚本。

1. 新建一个文件夹并以英文命名,并从CCS对应的C2000编译器目录拷贝odf2000.exe到该新建的文件夹中。(ofd2000.exe在C:\ti\ccs901\ccs\tools\compiler\ti-cgt-c2000_18.12.1.LTS\bin,路径随CCS版本、CCS安装路径及编译器版本不同会有差异)同时还需要从cgxml工具路径C:\ti\cgxml\bin中拷贝call_graph.exe,从工程目录拷贝编译生成的.out文件到该文件夹中。

2. 打开命令行工具(可在windows开始菜单搜索“CMD”找到),在其中输入如下命令选取上一步中新建的文件夹为工作目录

cd C:\ti\cgxml\utils

3. 在命令行中运行如下脚本获取输出结果,用户需要自行修改.out文件的文件名使其与第一步中复制到文件夹中的.out同名。

ofd2000 -xg gpio_toggle_cpu01.out | call_graph --stack_max

此时用户可以在命令行的输出中看到最恶劣情况下的堆栈占用情况,此处,函数c_int00是函数调用图的根,其调用在最大情况下会占用48个16位字的堆栈空间。但是这样的结果有两点限制条件将在本节的末尾部分指出。

poYBAGGKTnCAYnNDAAA3E1jUL4M189.png

如果使用--stack_max参数则可以获得更多的细节信息,具体的数据解读方法请参阅安装目录下的文档《call_graph.pdf》。

该方法简单易用,但是对于非直接调用的函数以及相互嵌套的中断服务,该工具则无法直接将其在脚本输出结果中表现出来。此时需要使用者结合call_graph输出的详细信息,借助自己对于程序流程的理解,分析得到最终的堆栈评估结果。

二、使用回调函数在运行时抓取栈指针(SP)最大值

C2000较新版本的编译器支持在函数的进入和退出过程中插入回调函数。开发者可以使--entry_hook选项为每个函数的开头部分插入一段读取堆栈指针(SP)的代码并在一定周期的程序运行中对堆栈指针的最大值进行抽取与比较从而获取统计学的极限堆栈使用情况。

以TI v18.12.2LTS Coder generation tool为例做一个测试,首先右击打开工程属性,并在“Advanced Options”中找到--entry_hook设置栏目,在后方的空格处输入回调函数的函数名称(以名为“entry_hook”的函数为例)。

pYYBAGGKTnKAY-b6AAGZDsPWlL0924.png

之后可以在c文件中定义函数entry_hook,其中使用的SP_current及SP_max为事先声明的int型全局变量。

void entry_hook(){

SP_current = getStackPointer();

SP_max = (SP_current > SP_max) ? SP_current : SP_max;

}

在该函数中使用了一小段汇编函数getStackPointer();用于获取堆栈指针(SP)寄存器的值,该函数的定义为:

_getStackPointer:

.asmfunc

MOV AL, SP

SUB AL, #2

LRETR

.endasmfunc

测试前还需要在头文件中对其做如下形式的函数声明:

extern int getStackPointer(void);

在完成设置后重新build工程,并点击CCS中的“Debug”按钮进入在线调试状态,此后可以进行全速运行。运行一段时间以后打开CCS的“View”,“Expressions”并点击绿色加号“Add new expression”输入变量名SP_max对最大堆栈占用情况进行观察。

通过回调函数做堆栈指针的采样统计不一定可以抓取到最极限的堆栈使用情况,实际的堆栈消耗会比用这种方法测量到的略大,因此笔者也提出了第三种测试方法。

三、在栈空间填充标识数据以检测栈空间使用情况

方法三的思路是在堆栈空间的特定内存区域中预先写入标志性数据如(0x5A)。经由程序的执行,使用过的堆栈空间内的数据会被其他数据覆盖掉,从栈尾开始向低地址走的标志性数据则因其内存空间未被使用而得以保留不变,当然这一切的前提是堆栈不发生溢出。通过寻找被修改数组的最大地址即可以判断出这一测试过程中程序实际所使用的最大堆栈规模。

该方法可以在连接仿真器的情况下进行堆栈占用情况的观察,也可以在芯片脱离仿真器运行之后再连接入仿真器(通过设置使目标芯片在连接时不被复位)并通过“Memory Browser”进行结果观察。该方法的准确性取决于软件执行的覆盖程度。

四、使用ERAD外设模块进行堆栈监测

ERAD(embedded real-time analysis and diagnostic)模块是F28004x系列MCU新增的外设,他独立于C28x内核之外,具有8个总线比较器和4个检测计数器子功能模块。由于该模块既可以被应用程序访问也可以被仿真工具访问因此能极大的增加调试的灵活性和便利性。

关于如何使用ERAD模块进行堆栈监控可以直接参考TI C2000ware软件包自带的范例程序,其参考位置为:C:\ti\c2000\C2000Ware_2_00_00_03\driverlib\f28004x\examples\erad\stack_overflow

其基本工作方式是对地址总线进行监控并根据HWBP_CNTL寄存器的配置,将地址总线内容与HWBP_REF寄存器中的参考值以指定方式进行对比(大于、大于等于、小于、小于等于),最终在比较事件发生时触发CPU的停止动作或生产RTOSINTn中断。通过这种方式的多次运用可以把堆栈空间的实际需求锁定在一个区间内便于参考。

总结:本文结合工程开发和调试的实际经验,对常用的四种C2000 MCU程序堆栈空间评估方法进行了总结,期待读者在阅读后能够结合实际情况选择一种或者多种方式确定出应用程序的堆栈需求并在工程属性中进行合理的配置,以实现最大程度的优化。

审核编辑:金巧

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • mcu
    mcu
    +关注

    关注

    146

    文章

    16019

    浏览量

    343666
  • 控制器
    +关注

    关注

    112

    文章

    15235

    浏览量

    171212
  • 嵌入式处理
    +关注

    关注

    0

    文章

    341

    浏览量

    9883
  • XML
    XML
    +关注

    关注

    0

    文章

    183

    浏览量

    32936
收藏 人收藏

    评论

    相关推荐

    CUBEIDE运行完可以看RAM的使用情况,运行中可以实时查看RAM的使用情况吗?

    CUBEIDE运行完可以看RAM的使用情况,运行中可以实时查看RAM的使用情况吗?以及负载情况? 图片是运行完可以看RAM使用情况,是否可以运行中实时查看?是不是cubemonito
    发表于 03-12 07:56

    rtthread编译后如何查看堆栈空间使用情况

    rtthread编译后如何查看堆栈空间使用情况,现在只能在编译完成后看到总大小,有没有办法能看到详细的使用情况。 由于RAM只有128K,除去内存池32k,想看看剩余的RAM在哪用了
    发表于 03-05 07:58

    如何知道嵌入式电子控制单元 (ECU) 中的RAM使用情况

    我知道嵌入式软件构建工具会报告程序闪存使用情况。我认为他们也报告 RAM 使用率,但他们是否报告最大 RAM 使用率? 生成工具可能不知道在运行时将使用多少堆。是否有构建工具不知道的其他 RAM 使用情况? 如何准确找出运行时使
    发表于 01-22 07:02

    CYBLE-416045-02在微控制器上制作应用程序,过段时间后突然停止工作的原因?

    我正在使用 CYBLE-416045-02 在微控制器上制作应用程序。 但是,它在 10 分钟或更长时间后突然停止工作。 我怀疑运行应用程序时是否会发生内存泄漏。 因此,我想检查是否发生内存泄漏以及内存
    发表于 01-22 06:35

    有什么办法可以获取TC397中的实时内存使用情况吗?

    有什么办法可以获取 TC397 中的实时内存使用情况吗? 例如,我能否通过计算当前堆栈指针值和基本堆栈指针值之间的差异来获得使用的内存大小?
    发表于 01-22 06:18

    请问TC397如何查看RAM和pFlash的使用情况

    请问 TC397 如何查看 RAM 和 pFlash 的使用情况
    发表于 01-19 06:37

    显示Web服务器中的内存使用情况

    Web服务器上,您可以在“内存”选项卡的“诊断”网页上找到有关各个内存区域当前使用情况的信息。
    的头像 发表于 12-18 10:18 290次阅读
    显示Web服务器中的内存<b class='flag-5'>使用情况</b>

    考虑x和z在verilog条件语句中的使用情况

    首先,考虑x和z在verilog条件语句中的使用情况,然后我们再考虑在verilog中用x和z给其他reg/wire赋值的情况
    的头像 发表于 11-02 09:40 626次阅读
    考虑x和z在verilog条件语句中的<b class='flag-5'>使用情况</b>

    SoC如何查看内存使用情况

    查看系统内存: free -h 查看ION内存 NPU内存使用情况: cat /sys/kernel/debug/ion/bm_npu_heap_dump/summary | head -2VPU
    发表于 09-19 07:23

    KAN316如何确定应用程序堆栈使用情况

    大小问题可能会产生不常见的零星程序错误。 因此,了解应用程序堆栈内存要求至关重要。 为了计算(并因此优化)所需的堆栈存储大小,可以使用以
    发表于 08-28 07:27

    LPC86x上的开关矩阵使用情况

    电子发烧友网站提供《LPC86x上的开关矩阵使用情况.pdf》资料免费下载
    发表于 08-17 10:48 0次下载
    LPC86x上的开关矩阵<b class='flag-5'>使用情况</b>

    LPC86x ACMP使用情况

    电子发烧友网站提供《LPC86x ACMP使用情况.pdf》资料免费下载
    发表于 08-17 10:34 0次下载
    LPC86x ACMP<b class='flag-5'>使用情况</b>

    LPC86x ADC使用情况

    电子发烧友网站提供《LPC86x ADC使用情况.pdf》资料免费下载
    发表于 08-16 10:42 0次下载
    LPC86x ADC<b class='flag-5'>使用情况</b>

    微控制器实时操作系统实践—实时系统介绍

    实时系统有各种各样的实现方式和使用情况。本书的重点是如何使用实时操作系统(RTOS)在微控制器单元(MCU)上创建实时应用程序
    发表于 06-15 17:21 900次阅读
    <b class='flag-5'>微控制器</b>实时操作系统实践—实时系统介绍

    如何检查imx6中的GPU使用情况

    在板上运行 Qt6 应用程序,想观察该 Qt6 应用程序对 GPU 的使用情况。 如何检查应用程序的 GPU 使用情况或该应用
    发表于 05-22 07:04