STM32 | map文件详解

发布者:BlissfulDreams最新更新时间:2021-08-10 来源: eefocus关键字:STM32  map文件  FLASH 手机看文章 扫描二维码
随时随地手机看文章

前言

前几个月针对公司自己的芯片写了个程序,这个程序有个硬性要求,就是能用的FLASH空间只有4KB,之前已经写得差不多了,最终占用空间3.6KB。


这不,最近又得加需求,还剩一点点FLASH空间可以使用,这该如何是好。需求已经加过来了,不行也得行啊。所以就得去优化之前的代码了,这就得研究比较底层的东西了。


我们的芯片与其它的MCU芯片用起来都差不多一样。我们在用ST的时候,编译完成,会生成很多文件,其中有一个.map文件,里面包含的信息就是工程 ROM/FLASH 和 RAM 的占用情况 。


之前只是关心.map文件的最后几行的 ROM/FLASH占用信息,如:

这次就得认真的学习一下这个文件了,只有清楚的知道这些信息才可以很好的进行代码优化 。下面我们来一起学习一下STM32的.map文件。(以下内容来自野火及安富莱教程文档)


map文件

要生成 map 文件,MDK 中如下选项要选上:

将工程全编译,且没有错误后,双击这里就可以看到生成的 map 文件了:

map文件的内容可分为如下几部分:


1、节区的跨文件引用(Section Cross References)

2、删除无用节区(Removing Unused input ps from the image)

3、符号映像表(Image Symbol Table (Local Symbols Global Symbols)

4、存储器映像索引(Memory Map of the image)

5、映像组件大小(Image component sizes)


1、节区的跨文件引用

这部分主要是不同文件中函数的调用关系。  在这部分中,详细列出了各个.o 文件之间的符号引用。


由于.o 文件是由 asm 或 c/c++源文件编译后生成的,各个文件及文件内的节区间互相独立,链接器根据它们之间的互相引用链接起来,链接的详细信息在这个Section Cross References一一列出。


例如,开头部分说明的是 startup_stm32f429_439xx.o 文件中的“RESET”节区分为它使用的__initial_sp符号引用了同文件“STACK”节区。


也许我们对启动文件不熟悉,不清楚这究竟是什么,那我们继续浏览,可看到 main.o文件的引用说明,如说明 main.o 文件的 i.main 节区为它使用的 LED_GPIO_Config 符号引用了 bsp_led.o 文件的 i.LED_GPIO_Config 节区。


有时在构建工程的时候,编译器会输出 “Undefined symbol xxx (referred from xxx.o)” 这样的提示,该提示的原因就是在链接过程中,某个文件无法在外部找到它引用的标号,因而产生链接错误。


2、删除无用节区

map 文件的第二部分是删除无用节区的说明,见代码清单:

这部分列出了在链接过程它发现工程中未被引用的节区,这些未被引用的节区将会被删除(指不加入到*.axf 文件,不是指在*.o 文件删除),这样可以防止这些无用数据占用程序空间。


例如,上面的信息中说明 startup_stm32f429_439xx.o 中的 HEAP(在启动文件中定义的用于动态分配的“堆”区)以及 stm32f4xx_adc.o 的各个节区都被删除了,因为在我们这个工程中没有使用动态内存分配,也没有引用任何 stm32f4xx_adc.c 中的内容。


由此也可以知道,虽然我们把 STM32 标准库的各个外设对应的 c 库文件都添加到了工程,但不必担心这会使工程变得臃肿,因为未被引用的节区内容不会被加入到最终的机器码文件中。


对于这个部分功能,用户最好将 MDK 中这个选项勾上,然后全编译工程,效果会比较好:

3、符号映像表

map 文件的第三部分是符号映像表(Image Symbol Table), 见代码清单 51-12。

这个表列出了被引用的各个符号在存储器中的具体地址、占据的空间大小等信息。

如我们可以查到LED_GPIO_Config 符号存储在 0x080002a5 地址,它属于 Thumb Code 类型,大小为 106 字节,它所在的节区为 bsp_led.o 文件的 i.LED_GPIO_Config 节区。


4、存储器映像索引

map 文件的第四部分是存储器映像索引(Memory Map of the image), 见代码清单:

映像文件可以分为加载域(Load Region)和运行域(Execution Region) 。

简单的说,加载域就是程序在 Flash 中的实际存储,而运行域是芯片上电后的运行状态,通过下面的框图可以有一个感性的认识:

通过上面的框图可以看出,RW 区也是要存储到 ROM/Flash 里面的,在执行映像之前,必须将已初始化的 RW 数据从 ROM 中复制到 RAM 中的执行地址并创建 ZI Section(初始化为 0 的变量区)。


本工程的存储器映像索引分为 ER_IROM1 及 RW_IRAM1 部分,它们分别对应 STM32内部 FLASH 及 SRAM 的空间。


相对于符号映像表,这个索引表描述的单位是节区,而且它描述的主要信息中包含了节区的类型及属性,由此可以区分 Code、 RO-data、 RW-data及 ZI-data。


例如,从上面的表中我们可以看到 i.LED_GPIO_Config 节区存储在内部 FLASH 的0x080002a4 地址,大小为 0x00000074,类型为 Code,属性为 RO。而程序的 STACK 节区(栈空间)存储在 SRAM 的 0x20000000 地址,大小为 0x00000400,类型为 Zero,属性为RW(即 RW-data) 。


5、映像组件大小

map 文件的最后一部分是包含映像组件大小的信息(Image component sizes),这也是最常查询的内容,见代码清单  :

这部分包含了各个使用到的*.o 文件的空间汇总信息、整个工程的空间汇总信息以及占用不同类型存储器的空间汇总信息,它们分类描述了具体占据的 Code、 RO-data、 RW-data及 ZI-data 的大小,并根据这些大小统计出占据的 ROM 总空间。


综合整个 map 文件的信息,可以分析出,当程序下载到 STM32 的内部 FLASH 时,需要使用的内部 FLASH 是从 0x0800 0000 地址开始的大小为 1456 字节的空间;当程序运行时,需要使用的内部 SRAM 是从 0x20000000 地址开始的大小为 1024 字节的空间。


总结

对照着这个map文件再看看我的程序,就可以知道哪里占的flash空间多了。硬件相关的部分已经用寄存器来操作,协议处理部分占用的flash空间最多。


最后,对于.map文件,我们一般只需要了解最后几行即可。如果想要深入学习,可以参照野火及安富莱的教程文档进行学习。


关键字:STM32  map文件  FLASH 引用地址:STM32 | map文件详解

上一篇:STM32 | 分享自定义协议的一些典型例子
下一篇:STM32 | 通俗易懂地串口通讯解析

推荐阅读最新更新时间:2024-11-11 10:59

贸泽率先独家备货STMicroelectronics的STM32 LoRaWAN 探索板
2017年2月24日 – 最新半导体和电子元件的全球授权分销商贸泽电子(Mouser Electronics) 即日起率先备货STMicroelectronics (ST)的STM32 LoRaWAN™ 探索板。这款新型探索套件与可从贸泽电子订购的Arduino兼容I-NUCLEO-LRWAN1 STM32 LoRa™扩展板一起作为一个平台,用于了解和评估基于LoRa和FSK/OOK 射频 (RF) 通信的解决方案。         贸泽电子独家备货的 ST STM32 LoRaWAN探索套件基于一体化开放式 Murata Type ABZ模块,支持低功率广域网(LPWAN) 和LoRaWAN 远程无线协议。Type ABZ模块包
[单片机]
STM32 74HC595驱动程序
以下为.h文件: #ifndef __74HC595_H__ #define __74HC595_H__ #include stm32f10x.h #define SHCP_GPIO_PORT GPIOA #define SHCP_GPIO_CLK RCC_APB2Periph_GPIOA #define SHCP_GPIO_PIN GPIO_Pin_1 #define STCP_GPIO_PORT GPIOA #define STCP_GPIO_CLK RCC_APB2Periph_GPIOA #define STCP_GPIO_PIN
[单片机]
<font color='red'>STM32</font> 74HC595驱动程序
STM32直接操作寄存器
本来stm32用库函数多么方便,但之前用51都喜欢直接操作寄存器,感觉库函数太方便了,方便到连stm32底层都可以无视掉了。看着手册,觉得直接操作寄存器很简单,但我却自己忽视了一些小细节,(就差一个强制转换,而且这个还是我自己在库函数中看到的)搞到我头大,而且网上没有人认真提出这个问题,这牛角尖钻了我好久。怒了!真的怒了! 正题:就老套的以基本的------点亮一盏灯为例吧。 (1)、如果使用库函数 先得建立好stm32库函数工程模板,然后在模板下这样操作: main() { GPIO_InitTypeDef GPIO_InitStructure; //结构体 初始化 RCC_APB2Peri
[单片机]
STM32 串口发送配置流程
串口字节发送流程: 编程USARTx_CR1的M位来定义字长。 编程USARTx_CR2的STOP位来定义停止位位数。 编程USARTx_BRR寄存器确定波特率。 使能USARTx_CR1的UE位来使能USARTx。 如果进行多缓冲通信,配置USARTx_CR3的DMA使能(DMAT)。 使能USARTx_CR1的TE位使能发送器。 向发送数据寄存器TDR写入要发送的数据。 向TDR寄存器写入最后一个数据后,等待状态寄存器USARTx_ISR的TC位置1,传输完成。 配置步骤1-6 : 配置字长,停止位,奇偶校验位,波特率等: HAL_StatusTypeDef HAL_USART_Init(USART_HandleTyp
[单片机]
STM32基于固件库学习笔记(1)GPIO基本使用
GPIO初始化函数: void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct); /* 第一个参数是用来指定 GPIO,取值范围为 GPIOA~GPIOG 第二个参数为初始化参数结构体指针,结构体类型为 GPIO_InitTypeDef */ GPIO_InitTypeDef结构体 typedef struct { uint16_t GPIO_Pin;//配置端口管脚 GPIOSpeed_TypeDef GPIO_Speed;// IO 口速度设置 输出速度(只有输出模式才配置速度) GPIOMode_TypeDef GPIO_Mode;// IO
[单片机]
stm32内核外设Systick与普通外设中断优先级比较的验证实验
最近又遇到了使用Systick来产生精确计时,然后又涉及到了Systick的中断优先级的问题。我们老板认为Systick属于内核外 设,中断优先级应该比普通外设高。然后我们说,在网上看到的是,Systick的中断优先级ST官方默认设置15(1111b),然 后换算为4位(M4用4位来表示优先级分组)是3(抢占优先级),3(响应优先级),其实是最低的,但老板说虽然它是最低的,但它是跟CPU紧耦合的内核外设,它依然能打断优先级比它高的普通外设,当然我们也有点不确定网上说的就是对的(还是老板说的就是错的,==)。于是就做了一个对比实验,测试到底是Systick到底能否打断中断优先级比它高的。 实验环境条件如下:MDK v5.21a,
[单片机]
编译STM32错误之一:Error: L6218E: Undefined symbol TIM_Cmd
注意要包含头文件:#include stm32f10x_tim.h 还有要把stm32f10x_tim.c加进工程。
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved