STM32 堆栈空间分布

参考

  1. 运行时访问__initial_sp__heap_base

无RTOS时的情况

在这里插入图片描述
在以上配置的情况下,生成工程。在工程的startup.s文件中,由如下代码:

Stack_Size		EQU     0x400

                AREA    STACK, NOINIT, READWRITE, ALIGN=3
__Stack_top		; 自己添加
Stack_Mem       SPACE   Stack_Size
__initial_sp

IF      :DEF:__MICROLIB           
	EXPORT  __initial_sp
	EXPORT  __heap_base
	EXPORT  __heap_limit
	EXPORT  __Stack_top	; 自己添加
ELSE
	IMPORT  __use_two_region_memory
	EXPORT  __user_initial_stackheap
__user_initial_stackheap
	LDR     R0, =  Heap_Mem
	LDR     R1, =(Stack_Mem + Stack_Size)
	LDR     R2, = (Heap_Mem +  Heap_Size)
	LDR     R3, = Stack_Mem
	BX      LR
	ALIGN
ENDIF

通过以上代码可以看出,需要使能MicroLib才会默认导出__initial_sp,__Stack_top,__heap_base,__heap_limit这几个变量。(如果不使能MicroLib,则需要在上面代码的ELSE下面也添加EXPORT语句将这几个变量导出)。
然后在main.c中添加如下代码,查看以上这些变量的值:

  extern uint32_t __heap_base, __heap_limit;
  extern uint32_t __Stack_top, __initial_sp;
  extern uint32_t __Vectors, __Vectors_End, __Vectors_Size;
  while (1)
  {
  	// 0x200013A8 ~ 0x200015A8  size:0x200  RAM
    printf("heapS[0x%08x], heapE[0x%08x]\r\n", (uint32_t)&__heap_base, (uint32_t)&__heap_limit);
      
    // 0x200019A8 ~ 0x200015A8  size:0x400  RAM
    printf("stackS[0x%08x], stackE[0x%08x]\r\n", (uint32_t)&__initial_sp, (uint32_t)&__Stack_top); 

	// 0x08000000 ~ 0x080000EC  ROM
	printf("VectS[0x%08x], VectE[0x%08x], VectSize[0x%x]\r\n\r\n", (uint32_t)&__Vectors, (uint32_t)&__Vectors_End, (uint32_t)&__Vectors_Size);
  }

从上可以看到,__Stack_top__heap_limit是一样的,说明这里分配的堆和栈是紧邻的。而且地址刚好也和我们在cubeMx中定义的一致。堆和栈是在RAM中,而中断向量表是在Flash中。

添加FreeRTOS

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
从以上三张图中,可以发现,我们给FreeRTOS总共分配了3072(0xC00) Bytes HEAP空间。而我们定义了一个defaultTask并分配了256 * 4 = 1024 Bytes,但是在最后的FreeRTOS Heap Usage页面看到,defaultTask实际使用了1144 Bytes,剩余3072 - 1144 = 1928 Bytes。(除了defaultTask多使用的1144 - 1024 = 120 Bytes(用于任务控制块TCB)外,其余都是可以对上的。)
生成工程后,我们还是将之前的那些堆栈指针地址打印出来,看一下MCU是如何进行地址分配的。只是这里还需要添加FreeRTOS中的堆栈信息了。首先通过追踪configTOTAL_HEAP_SIZE可以发现,堆空间定义为了一个数组:

	static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
    uint8_t* osHeapPoint = ucHeap;		// 由于以上变量是 static 类型,所有这里再定义一个指针指向这个 Heap 地址,以便在外部访问它;

然后我们就可以在defaultTask任务里面添加输出以上变量地址的代码了:

  extern uint32_t __heap_base, __heap_limit;
  extern uint32_t __Stack_top, __initial_sp;
  extern uint32_t __Vectors, __Vectors_End, __Vectors_Size;
  extern uint8_t* osHeapPoint;
  extern uint32_t local_addr1, local_addr2;
  void* os_mal_buf = malloc(50);
  uint32_t tast_local_val = 1;
  
  for(;;) {
  	// 0x20002D10 ~ 0x20002F10  size:0x200  RAM
  	printf("HeapS[0x%08x], HeapE[0x%08x]\r\n", (uint32_t)&__heap_base, (uint32_t)&__heap_limit);
	
	// 0x20003310 ~ 0x20002F10  size:0x400  RAM
	printf("StackS[0x%08x], StackE[0x%08x]\r\n", (uint32_t)&__initial_sp, (uint32_t)&__Stack_top);	// 
	
	// 0x08000000 ~ 0x080000EC  ROM
	printf("VectS[0x%08x], VectE[0x%08x], VectSize[0x%x]\r\n", (uint32_t)&__Vectors, (uint32_t)&__Vectors_End, (uint32_t)&__Vectors_Size);		// 中断向量表

	// 0x20002110   size: 3072 Bytes(0xC00)
	printf("OsHeapPoint[0x%08x]\r\n", (uint32_t)osHeapPoint);	// freeRTOS中定义的HEAP数组
	
	// 0x20002D18
	printf("Os_mal_buf[0x%08x]\r\n", (uint32_t)os_mal_buf);

	// 0x20002504
	printf("&Os_mal_buf[0x%08x]\r\n", (uint32_t)&os_mal_buf);

	// 0x20002508
	printf((char*)buf, "&tast_local_val[0x%08x]\r\n\r\n", (uint32_t)&tast_local_val);	// 在freeRTOS任务中定义的局部变量
	
	// 0x20000008, 0x2000000C
	printf("&global_var1[0x%08x], &global_var2[0x%08x]\r\n", (uint32_t)&global_var1, (uint32_t)&global_var2);	// 函数外部定义的全局变量

	// 0x20003304, 0x20003308
	printf("local_addr1[0x%08x], local_addr2[0x%08x]\r\n\r\n", local_addr1, local_addr2);	// 这两个全局变量保存了在freeRTOS初始化前,在main()函数中定义的两个局部变量的地址
  }

根据以上输出总结如下:
在这里插入图片描述

  1. local_addr的地址(靠近__initial_sp)可以看出,栈空间的地址值是向下增长的,即栈顶(__initial_sp = 0x20003310)在高地址;
  2. 从全局变量的地址可以看出,全局变量是默认分配在RAM的起始地址;
  3. freeRTOS任务中定义的局部变量(&tast_local_val = 0x20002508)存储在定义freeRTOS时定义的HEAP里(0x20002110~0x20002D10);
  4. 再看一下&tast_local_val = 0x20002508这个数据,发现0x20002508大概等于0x20002110 + 256*4 = 0x20002510。这就再次说明,freeRTOS定义任务时,是从配置好的HEAP地址初始空间的开始部分给新任务分配Task stack的,而在任务中使用这个task stack时,还是符合栈的使用规范(即从高地址开始分配);
  5. s_mal_buf = 0x20002D18可以知道,即使在freeRTOS任务中动态分配,也是在任务之外的堆中分配空间。

疑问

  1. 通过以上总结,发现在freeRTOS任务中定义局部变量和在freeRTOS任务之外定义局部变量,他们分配的地址空间是不一样的。那么,如果有以下函数:
void addr_test(void)
{
	uint32_t loc_var = 1;
	printf("&loc_var = 0x%08x\r\n", (uint32_t)&loc_var);
}

我分别在freeRTOS初始化之前调用,以及在freeRTOS的任务中调用,其输出会是什么呢?
经过验证,在freeRTOS初始化之前调用,输出的地址范围在0x20002F10 - 0x20003310之间;而在freeRTOS的任务中调用,输出的地址范围在0x20002110 - 0x20002D10之间。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/123467.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MySQL代码子查询续集

dept表: emp表: -- 查询每个部门的信息(包括:部门名,编号,地址)和人员数量 -- 1.将两张表结合起来,筛选出部门名,编号,地址 tips: 表.* 表示将该表所有列都显示出来&#xff…

获取请求IP以及IP解析成省份

某些业务需要获取请求IP以及将IP解析成省份之类的,于是我写了一个工具类,可以直接COPY /*** IP工具类* author xxl* since 2023/11/9*/ Slf4j public class IPUtils {/*** 过滤本地地址*/public static final String LOCAL_ADDRESS "127.0.0.1&quo…

VUE获取当前日期的周日和周六

<template><div><div @click="handleLast()">上一周</div><div @click="handleNext()">下一周</div><el-calendarref="monChild"v-model="value":first-day-of-week="7":range=&q…

React进阶之路(二)-- 组件通信、组件进阶

文章目录 组件通信组件通信的意义父传子实现props说明子传父实现兄弟组件通信跨组件通信Context通信案例 React组件进阶children属性props校验组件生命周期 组件通信 组件通信的意义 组件是独立且封闭的单元&#xff0c;默认情况下组件只能使用自己的数据&#xff08;state&a…

2022年接口测试总结【温故知新系列】

本文主要分为两个部分&#xff1a; 第一部分&#xff1a;主要从问题出发&#xff0c;引入接口测试的相关内容并与前端测试进行简单对比&#xff0c;总结两者之前的区别与联系。但该部分只交代了怎么做和如何做&#xff1f;并没有解释为什么要做&#xff1f; 第二部分&#xff1…

Spring Gateway基础知识总结

本文主要总结Spring Gateway的基础用法&#xff0c;内容包括网关、Spring Gateway工作流程、Spring Cloud Gateway搭建、路由配置方式、负载均衡实现、断言工厂这几个部分 目录 1. 网关 1.1 网关介绍 1.2 网关对比 1.3 Spring Gateway 1.4 核心概念 1.6 总结 2. Spring …

什么GAN生成对抗网络?生成对抗网络可以干什么?

生成对抗网络(Generative Adversarial Nets,简称GAN)。神经网络分很多种,有普通的前向传播网络,有分析图片的CNN卷积神经网络,有分析系列化数据比如语言、文字的RNN循环神经网络,这些神经网络都是用来输入数据,得到想要的结果,我们看中的是这些神经网络中很好地将数据与…

SpringCloud——消息总线——Bus

1.什么是总线&#xff1f; 我们在微服务的项目中&#xff0c;通常会构建一个共同的消息主题&#xff0c;然后需要的服务可以连接上来&#xff0c;该主题中产生的消息会被监听和消费&#xff0c;这种我们称为消息总线。 SpringCloud Bus 配合SpringCloud Config使用可以实现配置…

RestTemplate配置和使用

在项目中&#xff0c;如果要调用第三方的http服务&#xff0c;就需要发起http请求&#xff0c;常用的请求方式&#xff1a;第一种&#xff0c;使用java原生发起http请求&#xff0c;这种方式不需要引入第三方库&#xff0c;但是连接不可复用&#xff0c;如果要实现连接复用&…

基础课26——业务流程分析方法论

基础课25中我们提到业务流程分析方法包括以下几种&#xff1a; 价值链分析法&#xff1a;主要是找出或设计出哪些业务能够使得客户满意&#xff0c;实现客户价值最大化的业务流程。要进行价值链分析的时候可以从企业具体的活动进行细分&#xff0c;细分的具体方面可以从生产指…

运行springboot时提示:源值 7 已过时,将在未来版本中删除,并且提示java.time not exist, LocaDateTime类找不到。

运行springboot时提示&#xff1a;源值 7 已过时&#xff0c;将在未来版本中删除&#xff0c;并且提示 java.time not exist, LocaDateTime类找不到。 解决方法&#xff1a; 方式一&#xff1a;通过IDEA修改这几个地方的JDK版本 1&#xff09;打开ProjectStructure->Proj…

多篇论文介绍-Wiou

论文地址 目录 https://arxiv.org/pdf/2301.10051.pdf 01 CIEFRNet&#xff1a;面向高速公路的抛洒物检测算法 02改进 YOLOv5 的 PDC 钻头复合片缺损识别 03 基于SimAM注意力机制的DCN-YOLOv5水下目标检测 04 基于改进YOLOv7-tiny 算法的输电线路螺栓缺销检测 05 基于改…

机器学习中的假设检验

正态性检验相关分析回归分析 所谓假设检验&#xff0c;其实就是根据原假设来构造一种已知分布的统计量来计算概率&#xff0c;根据概率值大小来判断能否拒绝原假设&#xff0c;从而得到一种结论。假设检验的过程就是&#xff0c;构造一个原假设成立条件下的事件A&#xff0c;计…

基于斑马算法的无人机航迹规划-附代码

基于斑马算法的无人机航迹规划 文章目录 基于斑马算法的无人机航迹规划1.斑马搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用斑马算法来优化无人机航迹规划。 1.斑马搜索算法 …

内网可达网段探测netspy- Mac环境

netspy是一款快速探测内网可达网段工具 当我们进入内网后想要扩大战果&#xff0c;那我们可能首先想知道当前主机能通哪些内网段。 netspy正是一款应用而生的小工具&#xff0c;体积较小&#xff0c;速度极快&#xff0c;支持跨平台&#xff0c;支持多种协议探测&#xff0c;…

软件测试/校招推荐丨鼎捷软件股份有限公司岗位开放

点此获取更多相关资料 软件测试工程师 岗位职责 负责公司产品的日常测试工作&#xff1b;依据软件需求和非功能需求&#xff0c;编写测试方案和测试用例&#xff0c;设计测试脚本&#xff1b;负责服务器系统和软件的日常维护工作&#xff0c;为上线部署和运维活动提供技术支持…

HarmonyOS应用开发

引言 本章将深入探讨 HarmonyOS 应用开发的关键方面&#xff0c;包括应用的生命周期、数据存储和网络访问。了解这些内容对于创建功能丰富、高效的 HarmonyOS 应用至关重要。 目录 HarmonyOS 应用的生命周期HarmonyOS 应用的数据存储HarmonyOS 应用的网络访问总结 1. Harmo…

python 时间加法 输出t分钟后的时间

题目&#xff1a; 现在时间是a点b分&#xff0c;请问t分钟后&#xff0c;是几点几分&#xff1f; 输入&#xff1a; 第一行包含一个整数a 第二行包含一个整数b 第三行包含一个整数t 其中&#xff0c;0≤a≤23&#xff0c;0≤b≤59&#xff0c;0≤t&#xff0c;t分钟后还…

【Linux】进程的基本概念和进程控制

TOC 目录 一.冯诺依曼体系结构 二. 操作系统(Operator System) 概念 设计OS的目的 定位 总结 系统调用和库函数概念 进程 基本概念 描述进程-PCB task_struct-PCB的一种 task_ struct内容分类 组织进程 查看进程 通过系统调用获取进程标识符 进程状态 D--深度…

Android内存回收机制、GC算法及内存问题分析解决

Android内存回收机制、GC算法及内存问题分析解决 在Android开发中&#xff0c;Java内存回收和垃圾收集&#xff08;GC&#xff09;机制是确保应用程序高效运行的关键部分。针对不同对象存活率&#xff0c;Android平台采用了引用计数算法和可达性分析法来判定对象的可回收性&am…