STM32内存知识
在了解STM32内存之前需要了解 MCU 的型号和MDK 中的.map 文件,很多刚学习 stm32 时都不会过多的去了解 MCU 的选型,是在太枯燥了。这里在从新了解一下,久了就熟悉了。
一、STM32命令规则
二、MDK下生成.map文件
在MDK中勾选.map文件的生成,确认后编译一下工程即可生成,map文件。
打开.map文件
三、MDK下文件基本概念
在.map文件的最后可以看到文件信息的统计,如下图所示:
当然每次编译完成后也可以看到统计信息,如下图所示:
了解MDK下的一些常用变量名:
变量 | 作用 |
---|---|
code | 代码存储区,存放函数体的二进制代码 |
Ro-data | 只读数据存储区,存放字常量数据类型(如const类型)程序结束后有系统自动释放 |
RW-data | 初始化可读写变量的大小,程序结束后由系统自动释放。 |
ZI-data | 没有初始化的可读写变量大小,程序结束后由系统自动释放。 |
heap | 堆区,一般由程序员分配释放,若程序员不释放,程序结束时可能由OS释放。 |
stack | 栈区,由编译器自动分配释放,存放函数的参数值,局部变量的值等。 |
.text | 与RO-code同义 |
.constdata | 与RO-data同义 |
.bss | 未初始化的全局和静态变量,编译器自动初始化为0 |
.data | 初始化的全局和静态变量(与RW-data同义) |
PAD | 地址空间对齐 |
RO Size | 包含Code及RO Data,表示只读数据占用Flash空间的大小。 |
RW Size | 包含RW Data及ZI Data,表示运行时占用的RAM的大小。 |
ROM Size | 包含Code,RO Data及RW Data,表示烧写程序所占用的Flash的大小。 |
注意:栈向下生长,内存地址由高至低;堆向上,内存地址由低至高
通过上面表格可知STM32在编程时所用RAM和ROM的大小:
Flash(ROM)=Code+Ro-data
Sram(RAM)=Rw-data+ZI-data
四、STM32内存
这里我找了一位大佬总结的博客“STM32内存知识你真的了解吗?”,感觉挺好的,所以我直接引用一下启动的图片,如下图所示:
- STM32程序运行的流程
程序在运行之前,需要可执行将镜像文件(一般是bin或hex文件),通过烧写工具写入STM32的Flash中。STM32上电启动(从Flash启动时)后会将RW段中的RW-data(初始化的全局变量)拷贝到RAM中,然后根据编译器给出的ZI地址和大小分配出ZI段,并将这块RAM区域清零。如下图所示:左边是每上电flash+ram的状态,右边是上电后运行时flash+ram的状态。
注意:
- 可执行映像文件烧录到 STM32 后的内存分布包含 RO 段和 RW 段两个部分,其中其中 RO 段中保存了 Code、RO-data 的数据,RW 段保存了 RW-data 的数据,由于 ZI-data 都是 0,所以未包含在映像文件中。
- STM32运行时不会拷贝RO段,因为CPU的可执行代码是直接从Flash中读取的。
STM32编程时需要注意的事项
堆栈的大小在编译器编译之后是不知道的,只有在运行时才知道,所以容易造成堆栈溢出(发生hardfault错误),那怎么知道自己的内存大小了,通过选型手册就知道了,比如我使用的是STM32F103C8T6,ROM是64k,RAM是20k,如下图所示:
程序中的常量,如果没加const也会编译到SRAM里,加了const会被编译到flash中。
栈向下生长,内存地址由高至低;堆向上,内存地址由低至高,堆栈之间没有固定的界限,堆栈冲突时会导致系统崩溃,如下图所示:
五、.map文件
不同文件中函数调用的关系
============================================================================== Section Cross References startup_stm32f10x_hd.o(RESET) refers to startup_stm32f10x_hd.o(.text) for Reset_Handler
startup_stm32f10x_hd.o(.text) refers to system_stm32f10x.o(.text) for SystemInit
startup_stm32f10x_hd.o(.text) refers to entry.o(.ARM.Collect$$$$00000000) for __main
stm32f10x_rcc.o(.text) refers to stm32f10x_rcc.o(.data) for APBAHBPrescTable
stm32f10x_gpio.o(.text) refers to stm32f10x_rcc.o(.text) for RCC_APB2PeriphResetCmd
stm32f10x_usart.o(.text) refers to stm32f10x_rcc.o(.text) for RCC_APB2PeriphResetCmd
led.o(.text) refers to stm32f10x_rcc.o(.text) for RCC_APB2PeriphClockCmd
led.o(.text) refers to stm32f10x_gpio.o(.text) for GPIO_Init
main.o(.text) refers to led.o(.text) for LED_GPIO_Config
main.o(.text) refers to stm32f10x_gpio.o(.text) for GPIO_ResetBits
entry.o(.ARM.Collect$$$$00000000) refers (Special) to entry10a.o(.ARM.Collect$$$$0000000D) for __rt_final_cpp
entry.o(.ARM.Collect$$$$00000000) refers (Special) to entry11a.o(.ARM.Collect$$$$0000000F) for __rt_final_exit
entry.o(.ARM.Collect$$$$00000000) refers (Special) to entry7b.o(.ARM.Collect$$$$00000008) for _main_clock
entry.o(.ARM.Collect$$$$00000000) refers (Special) to entry8b.o(.ARM.Collect$$$$0000000A) for _main_cpp_init
entry.o(.ARM.Collect$$$$00000000) refers (Special) to entry9a.o(.ARM.Collect$$$$0000000B) for _main_init
entry.o(.ARM.Collect$$$$00000000) refers (Special) to entry5.o(.ARM.Collect$$$$00000004) for _main_scatterload
entry.o(.ARM.Collect$$$$00000000) refers (Special) to entry2.o(.ARM.Collect$$$$00000001) for _main_stk
entry2.o(.ARM.Collect$$$$00000001) refers to entry2.o(.ARM.Collect$$$$00002712) for __lit__00000000
entry2.o(.ARM.Collect$$$$00002712) refers to startup_stm32f10x_hd.o(STACK) for __initial_sp
entry2.o(__vectab_stack_and_reset_area) refers to startup_stm32f10x_hd.o(STACK) for __initial_sp
entry2.o(__vectab_stack_and_reset_area) refers to entry.o(.ARM.Collect$$$$00000000) for __main
entry5.o(.ARM.Collect$$$$00000004) refers to init.o(.text) for __scatterload
entry9a.o(.ARM.Collect$$$$0000000B) refers to main.o(.text) for main
entry9b.o(.ARM.Collect$$$$0000000C) refers to main.o(.text) for main
init.o(.text) refers to entry5.o(.ARM.Collect$$$$00000004) for __main_after_scatterload ==============================================================================如
main.o(.text) refers to led.o(.text) for LED_GPIO_Config
,是main.c文件中调用了led.c文件中的LED_GPIO_Config函数被删除的冗余函数
============================================================================== Removing Unused input sections from the image. Removing startup_stm32f10x_hd.o(HEAP), (0 bytes).
Removing core_cm3.o(.emb_text), (32 bytes).
Removing system_stm32f10x.o(.constdata), (20 bytes).
Removing misc.o(.text), (220 bytes).
Removing stm32f10x_usart.o(.text), (880 bytes). 5 unused section(s) (total 1152 bytes) removed from the image. ==============================================================================删除冗余的函数,有效降低程序的代码量,MDK自动优化,可以通过“One ELF Section per Function”选项开启,开启后可以大大优化程序代码量,打开方式是如下图所示:
打开后再次编译,看看.map文件中删除了81个函数,优化了2762字节,如下图所以:
局部标号和全局标号
局部标号
主要是在文件中用static声明的全局变量和函数。汇编文件中的标号地址(作用域限本文件)
全局标号
非static声明的变量和函数,汇编文件中的标号地址(作用域全局工程)
注意:
- Number 不站地址空间,大小为0。
- DATA 只读数据
- 文件中的标号再次用i.声明,说明在c文件中用static声明了的,如下图所示:
映像文件
映像文件可以分为加载域和运行域
加载域反应了ARM可执行映像文件各个段存放在寄存器中的位置关系。
组件大小
映像的真实大小
六、.htm文件
文件中做大的作用就是基本统计了所有被调用函数的栈stack使用的情况(不考虑中断嵌套)
栈的最大深度,调用路劲是main ⇒ LED_GPIO_Config ⇒ GPIO_Init
递归调用函数
函数指针
全局标号
比如复位中断函数,使用的是Thumb指令,占用0字节栈空间,函数代码大小2字节
比如系统时钟初始化函数SystemInit ,使用的是Thumb指令,函数代码大小68字节,占用栈空间8字节,代码深度28字节,函数调用路径是Call Chain = SetSysClock ⇒ SetSysClockTo72
参考文献
stm32的内存分布:https://blog.csdn.net/BooleanWater/article/details/119278723
STM32单片机的内存分布详解(1):https://www.bilibili.com/read/cv13912565
STM32内存知识你真的了解吗?:https://blog.csdn.net/qq_49864684/article/details/119887704
MDK生成的map和htm文件分析:https://www.bilibili.com/video/BV1t3411C7Pu/?spm_id_from=autoNext
STM32内存知识的更多相关文章
- STM32内存结构介绍和FreeRTOS内存分配技巧
这是我第一次使用FreeRTOS构建STM32的项目,踩了好些坑,又发现了我缺乏对于操作系统的内存及其空间的分配的知识,故写下文档记录学习成果. 文章最后要解决的问题是,如何恰当地分配FreeRTOS ...
- STM32内存映射
一.概述 STM32内存映射是STM32的架构的重要组成部分,不可或缺. 二.STM32内存映射图 1.内存映射图--摘自<CM3权威指南> 2.内存映射图--摘自<STM32F10 ...
- 舵机&数据处理&stm32内存之堆栈溢出(遇到的问题)
产品名称:TOWER PRO(辉盛)大扭力舵机MG996R (MG995升级产品)6v/11Kg厂家编号:MG996R产品净重: 55g产品尺寸: 40.7*19.7*42.9mm产品拉力: 9.4k ...
- C程序员必须知道的内存知识【英】
C程序员必须知道的内存知识[英] 时间 2015-03-08 14:16:11 极客头条原文 http://marek.vavrusa.com/c/memory/2015/02/20/memory ...
- Java-100天知识进阶-Java内存-知识铺(四)
知识铺: 致力于打造轻知识点,持续更新每次的知识点较少,阅读不累.不占太多时间,不停的来唤醒你记忆深处的知识点. 1.Java内存模型是每个java程序员必须掌握理解的 2.Java内存模型的主要目标 ...
- JVM内存知识备忘
又是一篇备忘... 主要记录一些知识,进行一些资源的汇总. 先来群里liufor大大提供的两张图,清晰易懂: Dockerized Java https://www.youtube.com/watch ...
- [转帖] 学习 Linux 大页的内存知识
一.在解释什么情况下需要开启大页和为啥需要开启大页前先了解下Linux下页的相关的知识:以下的内容是基于32位的系统,4K的内存页大小做出的计算1)目录表,用来存放页表的位置,共包含1024个目录en ...
- STM32 内存管理实验
参考原文<STM32F1开发指南> 内存管理简介 内存管理,是指软件运行时对计算机内存资源的分配和使用的技术.最主要的目的是如何高效.快速的分配,并且在适当的时候释放和回收内存资源.内存管 ...
- Java-100天知识进阶-JVM内存-知识铺(三)
知识铺: 致力于打造轻知识点,持续更新每次的知识点较少,阅读不累.不占太多时间,不停的来唤醒你记忆深处的知识点. Java内存模型(JMM) JVM内存模式是JVM的内存分区 Java内存模式是一种虚 ...
随机推荐
- CSS简单样式练习(二)
运行效果: 源代码: 1 <!DOCTYPE html> 2 <html lang="zh"> 3 <head> 4 <meta char ...
- 一篇文章带你整明白HTTP缓存知识
最近看了很多关于缓存的文章, 每次看完,看似明白但是实际还是没明白,这次总算搞明白协商缓存是怎么回事了 首先,服务器缓存分强制缓存和协商缓存(也叫对比缓存) 强制缓存一般是服务端在请求头携带字段Exp ...
- scrapy爬虫简单案例(简单易懂 适合新手)
爬取所有的电影名字,类型,时间等信息 1.准备工作 爬取的网页 https://www.ddoutv.com/f/27-1.html 创建项目 win + R 打开cmd输入 scrapy start ...
- linux压缩打包、定时任务
压缩打包 gzip压缩 win中的压缩包:zip rar Linux常见的压缩包有哪些? gzip bzip2 1.gzip压缩 压缩命令:gzip [压缩文件] 解压命令:gzip -d [压缩包] ...
- python中的嵌套
嵌套:将一系列字典存储在列表中,或将列表作为值存储在字典中,这称为嵌套.既可以在列表中嵌套字典,也可以在字典中嵌套列表,甚至在字典中嵌套字典. 一.列表中嵌套字典 1)一般创建方式: student_ ...
- 2021.11.02 eleveni的水省选题的记录
2021.11.02 eleveni的水省选题的记录 因为eleveni比较菜,所以eleveni决定从绿题开始水 --实际上菜菜的eleveni连绿题都不一定能水过/忍不住哭了 [P2217 HAO ...
- 记一次jenkins发送邮件报错 一直报错 Could not send email as a part of the post-build publishers问题
写在前面 虽然Jenkins是开源.免费的,好处很多,但有些功能上的使用,我个人还是很不喜欢,感觉用起来特别麻烦.繁琐. 为什么? 就拿这个邮件配置来说吧,因重装系统,电脑需要配置很多东西,结果今天就 ...
- OpenHarmony 3.1 Beta版本关键特性解析——ArkUI容器类API介绍
(以下内容来自开发者分享,不代表 OpenHarmony 项目群工作委员会观点) 刘鑫 容器类,顾名思义就是存储的类,用于存储各种数据类型的元素,并具备一系列处理数据元素的方法.在 ArkUI 开发框 ...
- .NET LoongArch64 正式合并进入.NET
国内自主的龙芯,在做龙芯技术生态就把 .NET 作为其中一部分考虑进去,这也将对接下来国内.NET应用场景充满了期待.通过dotnet/runtime 可以知道现在龙芯版本的 .NET 已经合并到.N ...
- vmware安装或卸载时,显示无法打开注册表项
vmware卸载是出了名的臭名昭著,因为太难删干净了,删不干净又会有各种各样的问题.比如下文这个"无法打开注册表项" 这个我相信有很多人在重装vmware的时候遇到过,因此我来 ...