ETAS StackM配置及使用-stack监控

前言

嵌入式C语言执行的软件中,stack溢出会导致程序执行异常,严重可能导致直接进硬件异常中断(hardfault)。软件执行过程中的stack监控是非常有必要的,ETAS的StackM模块实现了运行过程中的stack监控,对于多核系统,对每个核的stack进行监控。本文介绍StackM配置及使用。

Stack基本介绍

栈是用来存储函数调用时的局部变量函数参数以及返回地址等信息的数据结构。栈的生长方向一般是向下生长的,栈顶为高地址

当一个函数被调用时,它的局部变量和函数调用的参数都会被压入栈中,这会导致栈指针(通常称为栈顶指针或SP)向下移动,即向更低的内存地址移动。当函数执行完毕并返回时,栈中的这些数据会被弹出,栈指针则会向上移动回到之前的值。

示例如下:
在这里插入图片描述
栈的原则:栈中的数据元素遵守 后进先出(LIFO)的原则

栈的两个经典操作:

压栈:栈的插入操作叫做 进栈 / 压栈 / 入栈 (入数据在栈顶)

出栈:栈的删除操作叫做出栈。(出数据也在栈顶)

StackM配置

以下配置都基于stack向下生长,即STACKM_GROWDOWN = TRUE

StackMTarget

配置将在运行时监控的堆栈属性,例如内核所属、起始地址和结束地址

StackMStackID:配置stack id,实际没啥用

StackMStackLimit1:Stack监控限制阈值1,固定为12.5%。

StackMStackLimit2:Stack监控限制阈值2,固定为25%。

StackMStackLimit3:Stack监控限制阈值3,固定为50%。

StackMStackCoreID:关联的核id
StackMStackName:关联的stack内存名
在这里插入图片描述
StackName在linker模块中配置,包括stack的大小

对应代码配置为:

#define Stack0_StackId     (0)
#if (STACKM_GROWDOWN == TRUE)
    #define Stack0_Start       ((uint32*)((uint32)&STACK_START_SYSCORE_STACK - 0x00000001))
    #define Stack0_End         ((uint32*)((uint32)&STACK_END_SYSCORE_STACK  + 0x00000000))
    #define Stack0_Limit0      ((uint32*)((uint32)&STACK_START_SYSCORE_STACK - (STACK_LEN_SYSCORE_STACK>>5)))  /* convert to uint32,limit boundary at 12.5% */
    #define Stack0_Limit1      ((uint32*)((uint32)&STACK_START_SYSCORE_STACK - (STACK_LEN_SYSCORE_STACK>>4)))  /* convert to uint32,limit boundary at 25% */
    #define Stack0_Limit2      ((uint32*)((uint32)&STACK_START_SYSCORE_STACK - (STACK_LEN_SYSCORE_STACK>>3)))  /* convert to uint32,limit boundary at 50% */

    /* Check whether the Address to check is out of address space of current stack */
    LOCAL_INLINE boolean STACKM_CBK_Stack0( const uint32* currAddr) {return (((currAddr > Stack0_Start) || (currAddr == 0))? TRUE:FALSE);}
#else
    #error "Stack growing direction not supported in current StackM version !"
#endif

上面的limit是转化为uint32之后的计算,不是基于byte的,所以多除了4

StackMGeneral

StackMDevErrorDetect:使能错误检测

StackMEnable:使能StackM

StackMTraceEnable:使能trace跟踪功能

StackMPatternEnable:使能stack填充功能

StackMPattern:stack默认填充值

StackMLimitHigh:limit处填充的64字节的高32字节

StackMLimitHigh:limit处填充的64字节的低32字节

对应代码配置为:

#define STACKM_DEV_ERROR_DETECT STD_ON

/* Set to STD_ON if this feature has to be enabled, otherwise set STD_OFF */
#define STACKM_CFG_ENABLE STD_ON    /* Enable StackM component. */
#define STACKM_CFG_ENABLETRACE STD_ON    /* Enable Stack utilization tracing feature. */
#define STACKM_CFG_PATTERNINIT STD_ON    /* Enable Stack filling for tracing feature. */


#define STACKM_CFG_DEFAULTFILLUPVALUE ((uint32)0x4C4C4946)  /* "FILL" */
#define STACKM_CFG_LIMITHIGH ((uint32)0x3179656B)  /* "key1" */
#define STACKM_CFG_LIMITLOW ((uint32)0x3279656B)  /* "key2" */

Linker配置

配置对应stack的ld段,及stacksize
在这里插入图片描述
对应代码配置为:

#define STACK_LEN_SYSCORE_STACK        12288
#if (LINKER_STACK_GROWDOWN == TRUE)
    #define STACK_START_SYSCORE_STACK  __Stack_start_c0
    #define STACK_END_SYSCORE_STACK    __Stack_end_c0
#else
    #define STACK_START_SYSCORE_STACK  __SYSCORE_STACK_START
    #define STACK_END_SYSCORE_STACK    __SYSCORE_STACK_END
#endif

#define STACK_LEN_COMCORE_STACK        12288
#if (LINKER_STACK_GROWDOWN == TRUE)
    #define STACK_START_COMCORE_STACK  __Stack_start_c1
    #define STACK_END_COMCORE_STACK    __Stack_end_c1
#else
    #define STACK_START_COMCORE_STACK  __COMCORE_STACK_START
    #define STACK_END_COMCORE_STACK    __COMCORE_STACK_END
#endif

此处__Stack_start_c0为ld文件中定义的宏,表示的stack的高地址

    __Stack_start_c0         = ADDR(int_sram_stack_c0) + SIZEOF(int_sram_stack_c0);

EcuM配置

配置各个核的Stack初始化函数
在这里插入图片描述
主要就是对stack区域赋一个指定值

RTE配置

将对应的StackM的主函数映射到1ms任务上,或者在idle task中调用也是可以的
在这里插入图片描述

集成与测试

需要确认ld文件中的stack定义与StackM中的一致。

通过调用StackM_GetStackInfo函数获取stack监控的结果,对应结果参数定义结构体为StackM_StackMeasureType

typedef struct {
   uint32  FreeSpace;
   float32 FreePercent;
   uint8   CheckWordReached;
} StackM_StackMeasureType;

FreeSpace为当前剩余stack字节数FreePercent为当前剩余stack百分比,CheckWordReached为1时说明Stack使用量达到过12.5%,为3时说明使用量达到过25%,为7时说明使用量达到过50%.

调试结果如下:
在这里插入图片描述
在这里插入图片描述

总结

在栈使用量超过一定值时可以做出一些报警动作,在调试阶段对stack监控后合理分配stack空间,也是非常有意义的。

相关推荐

  1. 【docker】Docker Stack 详细使用注意事项

    2024-07-21 20:54:05       47 阅读
  2. spring retry 配置使用

    2024-07-21 20:54:05       46 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-21 20:54:05       52 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-21 20:54:05       54 阅读
  3. 在Django里面运行非项目文件

    2024-07-21 20:54:05       45 阅读
  4. Python语言-面向对象

    2024-07-21 20:54:05       55 阅读

热门阅读

  1. ArduPilot开源代码之AP_DAL研读系列

    2024-07-21 20:54:05       11 阅读
  2. Dockerfile相关命令

    2024-07-21 20:54:05       12 阅读
  3. Lucene 索引文件详解:结构与工作原理

    2024-07-21 20:54:05       15 阅读
  4. go语言的命名规则

    2024-07-21 20:54:05       18 阅读
  5. 基于python的时空地理加权回归(GTWR)模型

    2024-07-21 20:54:05       19 阅读
  6. c++端的类,作为组件在qml端使用

    2024-07-21 20:54:05       14 阅读
  7. Python笔记(3)

    2024-07-21 20:54:05       14 阅读
  8. 生成表的DDL语句没有字段描述和表名描述

    2024-07-21 20:54:05       16 阅读
  9. bitset和set总结

    2024-07-21 20:54:05       13 阅读