目录
- 1,MAP文件浅析(了解)
- 1.1MAP文件概念和作用
- 1.2MAP文件组成
- 1.3MAP文件实操
- 2.STM32启动过程(了解)
- 2.1STM32启动模式(F1/F4/F7/H7)(也称自举模式)
- 2.1.1STM32启动模式(F1/F4)
- 2.1.2STM32启动模式(F7)
- 2.1.3STM32启动模式(H7)
- 2.2STM32启动过程(以内部FLASH启动为例)
- 2.2.1启动文件介绍
- 2.2.2Reset_Handler函数介绍
- 2.2.2堆栈简介
- 2.3STM32启动过程图解
- 3,总结(了解)
该篇文章参考资料为:
STM32 MAP文件浅析.pdf
STM32 启动文件浅析.pdf
Cortex-M3权威指南(中文).pdf
1,MAP文件浅析(了解)
MDK编译会产生一些中间文件,在之前新建MDK工程时使其输出到了【Output】文件夹,总共有11种,如下表所示:
1.1MAP文件概念和作用
MAP文件是MDK编译代码后,产生的集程序、数据及IO空间的一种映射列表文件。简单说就是包括了:各种.c文件、函数、符号等的地址、大小、引用关系等信息,用于分析各.c文件占用FLASH 和 RAM的大小,方便优化代码。
1.2MAP文件组成
组成部分 | 简介 |
---|---|
程序段交叉引用关系 | 描述各文件之间函数调用关系 |
删除映像未使用的程序段 | 描述工程中未用到而被删除的冗余程序段(函数/数据)(比如说定义了变量temp,但是后面并没有使用temp,MAP文件将变量temp删除,生成一个被删除的列表,也可以是函数,表示未被是使用。) |
映像符号表 | 描述各符号(程序段/数据)在存储器中的地址、类型、大小等 |
映像内存分布图 | 描述各个程序段(函数)在存储器中的地址及占用大小 |
映像组件大小 | 给出整个映像代码(.o)占用空间汇总信息 |
1.3MAP文件实操
学会分析:哪个.c占用flash 和ram比较大,以便针对性的优化。(以【09】STM32·HAL库-新建HAL库版本MDK工程 | 下载STM32固件库文章中创建工程为例。)
在【LIsting】选项卡中,可以配置MAP文件产生文件,如果要产生MAP文件需要勾选【Linker Listng: …\Output\f103.map】,具体内容由下方勾选框决定,默认全部勾选。
在【C/C++】选项卡中,勾选【One ELF Section per Function】,可以将冗余的程序段删除。
可以在工程中【Output】文件夹可以找到MAP文件,另一种就是在MDK中双击工程名可以打开MAP文件,此处MAP文件能打开,前提是编译工程0错误,否则可能产生的文件不完整。
“i.main”表示main
函数的入口地址,调用了stm32f1xx_hal.o中的"i.HALL_Init"入口地址,也就是HAL_Init
函数。
main.o(i.main) refers to stm32f1xx_hal.o(i.HAL_Init) for HAL_Init
main.o(i.main) refers to sys.o(i.sys_stm32_clock_init) for sys_stm32_clock_init
main.o(i.main) refers to delay.o(i.delay_init) for delay_init
main.o(i.main) refers to main.o(i.led_init) for led_init
与main
函数中代码相对应。
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
delay_init(72); /* 延时初始化 */
led_init(); /* LED初始化 */
以下部分是未使用的程序段组成的列表。
映像符号表显示的内容是局部、全局变量或函数地址、类型、大小等,改变函数为static数据类型,可以改变其在局部或全局的位置。
映像内存分布图可以查看程序段在存储器的地址及占用大小。
映像组件文件,可以查看用户程序文件的占用空间信息。Code是代码占用空间量,data是编译器数据(不用管),R0 Data是只读,RW Data是可读可写,delay.o是delay.c产生的文件,占用FLASH是Code+R0 Data+RW Data,放到SRAM上是RW Data ZI Data
2.STM32启动过程(了解)
2.1STM32启动模式(F1/F4/F7/H7)(也称自举模式)
M3/M4/M7等内核复位后,做的第一件事:
1,从地址 0x0000 0000 处取出堆栈指针 MSP 的初始值,该值就是栈顶地址:
2,从地址 0x0000 0004 (STM32为32位单片机,4个字节)处取出程序计数器指针 PC 的初始值,该值是复位向量。
芯片厂商可以会把0x0000 0000和0x0000 0004地址映射到其它的地址,根据映射地址的来源将启动分为几种模式。
2.1.1STM32启动模式(F1/F4)
在系统复位后,SYSCLK的第4个上升沿,BOOT引脚的值将被锁存。从系统存储器启动时,系统存储器中存放的是ST的Bootloader程序,Bootloader程序可以引导我们用其他方式下载程序。内置SRAM起始地址也就是块2地址。
F4系列不仅可以从内置SRAM启动,还可以从外部SRAM启动,如果要使用FSMC重映射到外部的SRAM:可以通过配置SYSCFG_MEMRMP寄存器。无法下载程序时可以尝试解决方法:BOOT0接3.3V,按复位,然后再下载。
2.1.2STM32启动模式(F7)
与F1、F4系列相同,F7系列在系统复位后,SYSCLK的第4个上升沿,BOOT引脚的值将被锁存;不同的是在F7系列中只有一个BOOT引脚,接GND为0,接3.3V为1,启动地址由“启动地址选项字节”决定,BOOT_ADD0和BOOT_ADD1位域由FLASH_OPTCR1寄存器决定,由于寄存器设置的是29:14位,该寄存器一共是32位,所以造成寄存器值和启动地址不一致,如果将寄存器值放到32位中对应的值就是启动地址。
F7系列可以从ITCM或者AXIM都访问到FLASH。允许将自举存储器地址配置为从 0x0000 0000 到 0x2004 FFFF 的任意地址(16KB的整数倍,最小操作位为14,214/1024=16kb)。无法下载程序时可以尝试解决方法:BOOT接3.3V,按复位,然后再下载。
2.1.3STM32启动模式(H7)
在系统复位后,SYSCLK的第4个上升沿,BOOT引脚的值将被锁存。
选项字节允许将自举存储器地址配置为从 0x0000 0000 到 0x3FFF 0000 的任意地址,其中低16位只能为0,无论BOOT引脚高低电平,只能设置高16位。无法下载程序解决方法:B0接3.3,按复位,然后再下载。
2.2STM32启动过程(以内部FLASH启动为例)
在地址0x0800 0000获取栈顶指针MSP的值,在地址0x0800 0004获取中断向量表中的复位向量,也就是中断复位函数名,也是该函数的首地址,该函数被定义在启动文件中,执行完以上两步后,到达main
函数,执行用户程序。
2.2.1启动文件介绍
**参考资料:**STM32 启动文件浅析.pdf
1,初始化MSP:从0X0800 0000获取,因为从FLASH开始启动;
2,初始化PC:从0X0800 0004获取;
3,设置堆栈大小:Heap_Size(堆)、Stack_Size(栈),通过着两个宏来设置堆栈大小;
4,初始化中断向量表:__Vectors定义;
5,调用初始化函数:可选的,如调用: SystemInit函数;
6,调用__main:标准C库函数,执行一系列设置,最终调用main函数。用户编写了main
函数,编译器会自动定义__main
函数。
2.2.2Reset_Handler函数介绍
复位中断函数Reset_Handler
被定义在启动文件中,启动文件后缀是“.s”,是汇编语言文件。Reset_Handler
函数源码如下:
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT __main
IMPORT SystemInit
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
EXPORT:标明全局属性,可被外部调用
IMPORT:声明来自外部文件,类extern
PROC:定义子程序
ENDP:表示子程序结束
WEAK:弱定义,允许用户在其他地方重新定义Reset_Handler
函数,那么此处的函数将失效。在HAL库版本中,SystemInit
函数在system_stm32f1xx.c中定义,而在寄存器中没有定义所以用分号“;”进行注释掉三行代码。
调用__main
,完成一系列操作后,就会执行用户的main
函数。
如果外部没有:SystemInit函数,则会报错!!
2.2.2堆栈简介
函数局部变量较多,嵌套关系复杂时,需加大栈大小(Stack_Size),超过栈的定义大小时会溢出,在启动文件startup_stm32f103xe.s中,栈大小被设置成如下所示。也就是1KB的大小,堆被设置成512B的大小。
Stack_Size EQU 0x00000400
...
Heap_Size EQU 0x00000200
中断向量表如下所示,其中__initial_sp为栈顶指针,STM32复位后第一件事是让MSP指针取中断向量表栈顶地址,依次偏移4字节,可以得到复位中断向量地址等,中断向量表中只是列出了中断处理函数的首地址,在其他处定义。
__Vectors DCD __initial_sp ; Top of Stack
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
DCD MemManage_Handler ; MPU Fault Handler
DCD BusFault_Handler ; Bus Fault Handler
DCD UsageFault_Handler ; Usage Fault Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD SVC_Handler ; SVCall Handler
DCD DebugMon_Handler ; Debug Monitor Handler
DCD 0 ; Reserved
DCD PendSV_Handler ; PendSV Handler
DCD SysTick_Handler ; SysTick Handler
; External Interrupts
DCD WWDG_IRQHandler ; Window Watchdog
DCD PVD_IRQHandler ; PVD through EXTI Line detect
DCD TAMPER_IRQHandler ; Tamper
DCD RTC_IRQHandler ; RTC
DCD FLASH_IRQHandler ; Flash
DCD RCC_IRQHandler ; RCC
DCD EXTI0_IRQHandler ; EXTI Line 0
DCD EXTI1_IRQHandler ; EXTI Line 1
DCD EXTI2_IRQHandler ; EXTI Line 2
DCD EXTI3_IRQHandler ; EXTI Line 3
DCD EXTI4_IRQHandler ; EXTI Line 4
DCD DMA1_Channel1_IRQHandler ; DMA1 Channel 1
DCD DMA1_Channel2_IRQHandler ; DMA1 Channel 2
DCD DMA1_Channel3_IRQHandler ; DMA1 Channel 3
DCD DMA1_Channel4_IRQHandler ; DMA1 Channel 4
DCD DMA1_Channel5_IRQHandler ; DMA1 Channel 5
DCD DMA1_Channel6_IRQHandler ; DMA1 Channel 6
DCD DMA1_Channel7_IRQHandler ; DMA1 Channel 7
DCD ADC1_2_IRQHandler ; ADC1 & ADC2
DCD USB_HP_CAN1_TX_IRQHandler ; USB High Priority or CAN1 TX
DCD USB_LP_CAN1_RX0_IRQHandler ; USB Low Priority or CAN1 RX0
DCD CAN1_RX1_IRQHandler ; CAN1 RX1
DCD CAN1_SCE_IRQHandler ; CAN1 SCE
DCD EXTI9_5_IRQHandler ; EXTI Line 9..5
DCD TIM1_BRK_IRQHandler ; TIM1 Break
DCD TIM1_UP_IRQHandler ; TIM1 Update
DCD TIM1_TRG_COM_IRQHandler ; TIM1 Trigger and Commutation
DCD TIM1_CC_IRQHandler ; TIM1 Capture Compare
DCD TIM2_IRQHandler ; TIM2
DCD TIM3_IRQHandler ; TIM3
DCD TIM4_IRQHandler ; TIM4
DCD I2C1_EV_IRQHandler ; I2C1 Event
DCD I2C1_ER_IRQHandler ; I2C1 Error
DCD I2C2_EV_IRQHandler ; I2C2 Event
DCD I2C2_ER_IRQHandler ; I2C2 Error
DCD SPI1_IRQHandler ; SPI1
DCD SPI2_IRQHandler ; SPI2
DCD USART1_IRQHandler ; USART1
DCD USART2_IRQHandler ; USART2
DCD USART3_IRQHandler ; USART3
DCD EXTI15_10_IRQHandler ; EXTI Line 15..10
DCD RTC_Alarm_IRQHandler ; RTC Alarm through EXTI Line
DCD USBWakeUp_IRQHandler ; USB Wakeup from suspend
DCD TIM8_BRK_IRQHandler ; TIM8 Break
DCD TIM8_UP_IRQHandler ; TIM8 Update
DCD TIM8_TRG_COM_IRQHandler ; TIM8 Trigger and Commutation
DCD TIM8_CC_IRQHandler ; TIM8 Capture Compare
DCD ADC3_IRQHandler ; ADC3
DCD FSMC_IRQHandler ; FSMC
DCD SDIO_IRQHandler ; SDIO
DCD TIM5_IRQHandler ; TIM5
DCD SPI3_IRQHandler ; SPI3
DCD UART4_IRQHandler ; UART4
DCD UART5_IRQHandler ; UART5
DCD TIM6_IRQHandler ; TIM6
DCD TIM7_IRQHandler ; TIM7
DCD DMA2_Channel1_IRQHandler ; DMA2 Channel1
DCD DMA2_Channel2_IRQHandler ; DMA2 Channel2
DCD DMA2_Channel3_IRQHandler ; DMA2 Channel3
DCD DMA2_Channel4_5_IRQHandler ; DMA2 Channel4 & Channel5
__Vectors_End
__Vectors_Size EQU __Vectors_End - __Vectors
AREA |.text|, CODE, READONLY
2.3STM32启动过程图解
以下信息是正点原子HAL库跑马灯实验仿真得到的数据图,其中堆是0x200大小,大小是0x20000388减去0x20000188,MSP指针自动对值进行加1处理,其实堆空间是到0x20000387,同理栈大小是0x400,但是是向下生长。内核从FLASH启动,首先从0x0800,0000获取MSP堆栈指针初始值(也就是栈顶地址__initial_sp),然后从0x0800,0000获取PC指针初始值(也就是复位中断服务函数首地址),这两个地址通过MAP文件得到,