当前位置: 首页 > news >正文

STM32 堆栈空间分布

参考

  1. 运行时访问__initial_sp__heap_base

无RTOS时的情况

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

Stack_Size		EQU     0x400AREA    STACK, NOINIT, READWRITE, ALIGN=3
__Stack_top		; 自己添加
Stack_Mem       SPACE   Stack_Size
__initial_spIF      :DEF:__MICROLIB           EXPORT  __initial_spEXPORT  __heap_baseEXPORT  __heap_limitEXPORT  __Stack_top	; 自己添加
ELSEIMPORT  __use_two_region_memoryEXPORT  __user_initial_stackheap
__user_initial_stackheapLDR     R0, =  Heap_MemLDR     R1, =(Stack_Mem + Stack_Size)LDR     R2, = (Heap_Mem +  Heap_Size)LDR     R3, = Stack_MemBX      LRALIGN
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  RAMprintf("heapS[0x%08x], heapE[0x%08x]\r\n", (uint32_t)&__heap_base, (uint32_t)&__heap_limit);// 0x200019A8 ~ 0x200015A8  size:0x400  RAMprintf("stackS[0x%08x], stackE[0x%08x]\r\n", (uint32_t)&__initial_sp, (uint32_t)&__Stack_top); // 0x08000000 ~ 0x080000EC  ROMprintf("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  RAMprintf("HeapS[0x%08x], HeapE[0x%08x]\r\n", (uint32_t)&__heap_base, (uint32_t)&__heap_limit);// 0x20003310 ~ 0x20002F10  size:0x400  RAMprintf("StackS[0x%08x], StackE[0x%08x]\r\n", (uint32_t)&__initial_sp, (uint32_t)&__Stack_top);	// // 0x08000000 ~ 0x080000EC  ROMprintf("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数组// 0x20002D18printf("Os_mal_buf[0x%08x]\r\n", (uint32_t)os_mal_buf);// 0x20002504printf("&Os_mal_buf[0x%08x]\r\n", (uint32_t)&os_mal_buf);// 0x20002508printf((char*)buf, "&tast_local_val[0x%08x]\r\n\r\n", (uint32_t)&tast_local_val);	// 在freeRTOS任务中定义的局部变量// 0x20000008, 0x2000000Cprintf("&global_var1[0x%08x], &global_var2[0x%08x]\r\n", (uint32_t)&global_var1, (uint32_t)&global_var2);	// 函数外部定义的全局变量// 0x20003304, 0x20003308printf("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之间。

相关文章:

STM32 堆栈空间分布

参考 运行时访问__initial_sp和__heap_base 无RTOS时的情况 在以上配置的情况下,生成工程。在工程的startup.s文件中,由如下代码: Stack_Size EQU 0x400AREA STACK, NOINIT, READWRITE, ALIGN3 __Stack_top ; 自己添加 Stack_Mem…...

小程序制作(超详解!!!)第十五节 自动随机变化的三色旗

1.例题描述 设计一个小程序&#xff0c;开始时界面上显示一个三色旗和一个按钮&#xff0c;当点击按钮时&#xff0c;三色旗的颜色会发生随机变化&#xff0c;即使不点击按钮&#xff0c;三色旗的颜色也会每隔一定时间自动发生变化。 2.index.wxml <view class"box&…...

MySQL_主从复制_环境搭建

MySQL主从复制配置 CentOS 7 配置 阿里云 yum 源 sudo mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup sudo wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo sudo yum clean all sudo yum makeca…...

Linux 设置静态IP(Ubuntu 20.04/18.04)

以Ubuntu20.04示例 第一步&#xff1a;查看当前网络信息 ifconfig 本机网卡名为&#xff1a;ens32&#xff0c;IP地址为&#xff1a;192.168.15.133&#xff0c;子网掩码为&#xff1a;255.255.255.0 第二步&#xff1a;查看当前网关信息 route -n 网关地址为&#xff1a;1…...

计网----累积应答,TCP的流量控制--滑动窗口,粘包问题,心跳机制,Nagle算法,拥塞控制,TCP协议总结,UDP和TCP对比,中介者模式

计网----累积应答&#xff0c;TCP的流量控制–滑动窗口&#xff0c;粘包问题&#xff0c;心跳机制&#xff0c;Nagle算法&#xff0c;拥塞控制&#xff0c;TCP协议总结&#xff0c;UDP和TCP对比&#xff0c;中介者模式 一.累积应答 1.什么是累计应答 每次发一些包&#xff0…...

OpenCV 直方图和归一化

直方图可以反映图片的整体统计信息, 使用函数 CalcHist() 实现. 但CalcHist() 统计出的数量信息和图像大小相关, 如果要剔除图像大小因素, 需要做归一化处理, 归一化处理后的信息, 反映出各个颜色值得占比情况, 这样更方便不同size图像做对比, 归一化的函数为 Normalize(). ///…...

Flink架构

1、Apache Flink集群的核心架构&#xff1a; 1、client&#xff08;作业客户端&#xff09;&#xff1a;提交任务的地方叫做客户端 2、JobManager&#xff08;作业管理器&#xff09;&#xff1a;作用是用于管理集群中任务 3、TaskManager&#xff08;任务管理器&#xff09;&a…...

Packet Tracer路由器连接终端设备怎么配置?

在Packet Tracer中配置一台路由器和三台终端设备可以帮助你建立一个简单的局域网&#xff0c;以下是配置的基本步骤&#xff1a; 打开Packet Tracer&#xff0c;从左侧设备栏中拖拽一个路由器和三个终端设备到工作区。 连接设备&#xff1a;使用网线将路由器的端口与每台终端设…...

评估APP网页小程序代码UI开发H5估价师怎么评估开发精确研发价格?

作为一名应用程序开发评估师&#xff0c;可能涉及到的主要任务是为特定的应用程序提供估算开发成本和所需时间预测。为了为一个应用程序更准确地评估价格&#xff0c;须遵循以下几个步骤&#xff1a; 问: 如何让一个App更好、更精确地评估出价格&#xff1f; 答: 以下是一个可…...

16 Linux 内核定时器

一、Linux 时间管理和内核定时器简介 1. 内核时间管理简介 Linux 内核中有大量的函数需要时间管理&#xff0c;比如周期性的调度程序、延时程序、定时器等。 硬件定时器提供时钟源&#xff0c;时钟源的频率可以设置&#xff0c;设置好以后就周期性的产生定时中断&#xff0c;系…...

C++11 shared_ptr类型智能指针学习

智能指针和普通指针的用法类似,但是智能指针可以在适当时机自动释放分配的内存。 C++11有三种类型的智能指针,shared_ptr、unique_ptr 以及 weak_ptr; 先学习shared_ptr类型; shared_ptr<T> 的定义位于<memory>头文件,并位于 std 命名空间中; T 表示指针指…...

网络流量分类概述

1. 什么是网络流量&#xff1f; 一条网络流量是指在一段特定的时间间隔之内&#xff0c;通过网络中某一个观测点的所有具有相同五元组(源IP地址、目的IP地址、传输层协议、源端口和目的端口)的分组的集合。 比如(10.134.113.77&#xff0c;47.98.43.47&#xff0c;TLSv1.2&…...

JavaWeb篇_02——服务器简介及Tomcat服务器简介

服务器简介 硬件服务器的构成与一般的PC比较相似&#xff0c;但是服务器在稳定性、安全性、性能等方面都要求更高&#xff0c;因为CPU、芯片组、内存、磁盘系统、网络等硬件和普通PC有所不同。软件服务器&#xff08;英文名称Server&#xff09;&#xff0c;也称伺服器。指一个…...

2311d游戏引擎适配ios

原文 通过遵循arsd:simpledisplay(v11.0.0之前)上的一些旧代码,Apple的文档和Jacob的这一惊人贡献桥, 我已从金属绑定中删除了所有extern(Objective-C)代码,现在,所有Objective-C桥接代码都是使用D的反射生成的. 因此,给定此例代码: import core.attribute : selector; extern…...

网络唤醒(Wake-on-LAN, WOL)

远程唤醒最简单的方法&#xff1a;DDNSTOOpenwrt网络唤醒&#xff0c;完美实现。 原帖-远程唤醒_超详细windows设置远程唤醒wol远程连接&#xff08;远程开机&#xff09; WOL Web# 访问 Wake on Lan Over The Interweb by Depicus 可以无需借助软件很方便的从网页前端唤醒远…...

接口测试框架实战(一) | Requests 与接口请求构造

Requests 是一个优雅而简单的 Python HTTP 库&#xff0c;其实 Python 内置了用于访问网络的资源模块&#xff0c;比如urllib&#xff0c;但是它远不如 Requests 简单优雅&#xff0c;而且缺少了许多实用功能。所以&#xff0c;更推荐掌握 Requests 接口测试实战技能&#xff0…...

【C++】详解 void*

文章目录 1. void *是什么&#xff1f;2. void*详解3. 和void的区别4. 应用场景4.1 函数传参时不确定类型&#xff0c;或者要支持多类型的传参&#xff1b;4.2 当函数的返回值不考虑类型指关心大小的时候 5. 总结 今天看到一段代码&#xff0c;觉得非常有意思。 void* say_hell…...

Linux家目录变成了-bash-4.2$

Linux家目录变成了-bash-4.2$ Mark a workarround: 使用root用户&#xff0c;执行cp -a /etc/skel/. /home/zookeeper/&#xff08;不是root用户也可以&#xff09; 其中/home/zookeeper/目录是对应自己的家目录地址~ 若有帮到你&#xff0c;记得点赞&#xff0c;收藏呀…...

Python和SQLite游标处理多行数据

如果您需要处理多行数据&#xff0c;使用游标或其他适当的方法是更好的选择。以下是一些处理多行数据的方法&#xff1a; 使用游标&#xff1a;游标可以逐行处理查询结果&#xff0c;这对于大量数据或需要逐行处理的场景非常有用。以下是一个使用Python和SQLite的游标示例&…...

安全测试之PHP 漏洞全解

PHP 漏洞全解(一)-PHP的攻击方式 针对 PHP 的网站主要存在下面几种攻击方式: 1、命令注入(Command Injection) 2、eval 注入(Eval Injection) 3、客户端脚本攻击(Script Insertion) 4、跨网站脚本攻击(Cross Site Scripting, XSS) 5、SQL 注入攻击(SQL injection) 6、跨网站…...

云计算——弹性云计算器(ECS)

弹性云服务器&#xff1a;ECS 概述 云计算重构了ICT系统&#xff0c;云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台&#xff0c;包含如下主要概念。 ECS&#xff08;Elastic Cloud Server&#xff09;&#xff1a;即弹性云服务器&#xff0c;是云计算…...

Python:操作 Excel 折叠

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习

禁止商业或二改转载&#xff0c;仅供自学使用&#xff0c;侵权必究&#xff0c;如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

用机器学习破解新能源领域的“弃风”难题

音乐发烧友深有体会&#xff0c;玩音乐的本质就是玩电网。火电声音偏暖&#xff0c;水电偏冷&#xff0c;风电偏空旷。至于太阳能发的电&#xff0c;则略显朦胧和单薄。 不知你是否有感觉&#xff0c;近两年家里的音响声音越来越冷&#xff0c;听起来越来越单薄&#xff1f; —…...

【Go语言基础【13】】函数、闭包、方法

文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数&#xff08;函数作为参数、返回值&#xff09; 三、匿名函数与闭包1. 匿名函数&#xff08;Lambda函…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

【Post-process】【VBA】ETABS VBA FrameObj.GetNameList and write to EXCEL

ETABS API实战:导出框架元素数据到Excel 在结构工程师的日常工作中,经常需要从ETABS模型中提取框架元素信息进行后续分析。手动复制粘贴不仅耗时,还容易出错。今天我们来用简单的VBA代码实现自动化导出。 🎯 我们要实现什么? 一键点击,就能将ETABS中所有框架元素的基…...

Axure 下拉框联动

实现选省、选完省之后选对应省份下的市区...

算术操作符与类型转换:从基础到精通

目录 前言&#xff1a;从基础到实践——探索运算符与类型转换的奥秘 算术操作符超级详解 算术操作符&#xff1a;、-、*、/、% 赋值操作符&#xff1a;和复合赋值 单⽬操作符&#xff1a;、--、、- 前言&#xff1a;从基础到实践——探索运算符与类型转换的奥秘 在先前的文…...

向量几何的二元性:叉乘模长与内积投影的深层联系

在数学与物理的空间世界中&#xff0c;向量运算构成了理解几何结构的基石。叉乘&#xff08;外积&#xff09;与点积&#xff08;内积&#xff09;作为向量代数的两大支柱&#xff0c;表面上呈现出截然不同的几何意义与代数形式&#xff0c;却在深层次上揭示了向量间相互作用的…...