完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
文章内容根据野火学习教程进行整理,仅仅是学习记录。
开发板: 野火STM32F429-挑战者V2 官方固件库版本: STM32F4xx_DSP_StdPeriph_Lib_V1.8.0 启动文件介绍 位置 启动文件(例如:startup_stm32f429_439xx.s),该文件存在于官方固件库的目录位置为:STM32F4xx_DSP_StdPeriph_Lib_V1.8.0LibrariesCMSISDeviceSTSTM32F4xxSourceTemplatesarm 具体选择哪份文件就根据所使用的芯片版本来决定。 作用 启动文件由汇编编写,是系统上电复位后第一个执行的程序。主要做了以下工作: 1、 初始化堆栈指针 SP=_initial_sp 2、 初始化 PC 指针=Reset_Handler 3、 初始化中断向量表 4、 配置系统时钟 5、 调用 C 库函数_main 初始化用户堆栈,从而最终调用 main 函数去到 C 的世界 这个说明其实在每份启动文件的最前面都有英文注释 所使用到的汇编指令说明 要查找更详细的汇编指令解释可以打开ARM Development Tools进行搜索查询。 使用搜索功能,点开标题为Assembler User Guide(汇编用户指南)的主题。 ARM Development Tools 启动文件程序讲解 ;分号是注释的意思,相当于C中的/* */ 或者 //。 栈初始化 Stack_Size EQU 0x00000400 AREA STACK, NOINIT, READWRITE, ALIGN=3 Stack_Mem SPACE Stack_Size __initial_sp 解释: 1、第一行:定义Stack_Size这个变量为0x00000400即1K。 2、第二行:定义一个名字为STACK的代码段或数据段,不初始化,可读可写,8( 2^3)字节对齐。 3、第三行:分配一个大小为Stack_Size的内存空间,单位为字节。 4、第四行:__initial_sp 紧挨着 SPACE 语句放置,表示栈的结束地址,即栈顶地址,栈是由高向低生长的。 5、栈的作用是用于局部变量,函数调用,函数形参等的开销,栈的大小不能超过内部SRAM 的大小。如果编写的程序比较大,定义的局部变量很多,那么就需要修改栈的大小。 堆初始化 Heap_Size EQU 0x00000200 AREA HEAP, NOINIT, READWRITE, ALIGN=3 __heap_base Heap_Mem SPACE Heap_Size __heap_limit PRESERVE8 THUMB 解释: 1、第一行:定义Heap_Size这个变量为0x00000200即512 字节。 2、第二行:定义一个名字为HEAP的代码段或数据段,不初始化,可读可写,8( 2^3)字节对齐。 3、第三行:堆的起始地址,用于计算。 4、第四行:分配一个大小为Heap_Size的内存空间,单位为字节。 5、第五行:堆的终止地址,用于计算。 6、第六行:指定当前文件的堆栈按照 8 字节对齐。 7、表示后面指令兼容 THUMB 指令。 THUBM 是 ARM 以前的指令集, 16bit,现在 Cortex-M 系列的都使用 THUMB-2 指令集, THUMB-2 是 32 位的,兼容 16 位和 32 位的指令,是 THUMB 的超集。 8、用__heap_limit减去__heap_base即可得到堆的总空间。堆是由低向高生长的,跟栈的生长方向相反。 9、堆主要用来动态内存的分配,像 malloc()函数申请的内存就在堆上面。这个在 STM32里面用的比较少。 向量表 ; Vector Table Mapped to Address 0 at Reset AREA RESET, DATA, READONLY EXPORT __Vectors EXPORT __Vectors_End EXPORT __Vectors_Size __Vectors DCD __initial_sp ; Top of Stack DCD Reset_Handler ; Reset Handler DCD NMI_Handler ; NMI Handler 省略。。。 DCD LTDC_ER_IRQHandler ; LTDC error DCD DMA2D_IRQHandler ; DMA2D __Vectors_End __Vectors_Size EQU __Vectors_End - __Vectors 解释: 1、第一行注释:说明向量表映射到了RESET字段的地址0的位置。即第二行要定义的数据段。 2、第二行:定义一个数据段,名字为 RESET,可读 3、第三、四、五行:声明 __Vectors、 __Vectors_End 和__Vectors_Size 这三个标号具有全局属性,可供外部的文件调用。 如果是 IAR 编译器,则使用的是 GLOBAL 这个指令。 4、第六行:分配一个堆内存,以四个字节对齐,并以ESR的入口地址(即函数指针)初始化,并放在向量表的起始地址__Vectors位置。ESR对于内核来说就是异常,对外设来说就是中断。 5、第七、八、九、十、十一行:分配堆内存,以四个字节对齐,并以ESR的入口地址(即函数指针)初始化。 6、第十一行:向量表结束地址。 7、第十二行:向量表的大小,用终止地址 - 起始地址。 复位程序 AREA |.text|, CODE, READONLY ; Reset handler ;WEAK:表示弱定义,如果外部文件优先定义了该标号则首先引用该标号,如果外部文件没有声明也不会出错。这里表示复位子程序可以由用户在其他文件重新实现,这里并不是唯一的。 ;IMPORT:表示该标号来自外部文件,跟 C 语言中的 EXTERN 关键字类似。这里表示 SystemInit 和__main 这两个函数均来自外部的文件。 Reset_Handler PROC EXPORT Reset_Handler [WEAK] IMPORT SystemInit IMPORT __main LDR R0, =SystemInit BLX R0 LDR R0, =__main BX R0 ENDP 解释: 1、第一行:定义一个名称为.text 的代码段,可读。 2、第二行:表示复位程序Reset_Handler的开始,PROC与第十行的ENDP成对出现,表示程序的开始与结束。 3、第三行:声明Reset_Handler函数为全局属性,可以被其他文件调用。后面的WEAK表示该定义是弱引用。 4、第四行:插入SystemInit这个函数,该函数在别的地方定义的,不在本汇编文件的当中。 5、第五行:插入__main这个函数,该函数在别的地方定义的,不在本汇编文件的当中。 6、第六行:把SystemInit这个函数加载到R0这个寄存器。 7、第七行:执行R0这个寄存器即SystemInit这个函数并返回。 8、第八行:把__main这个函数加载到R0这个寄存器。 9、第九行:执行R0这个寄存器即__main这个函数但是不返回。这个时候跳转到了C的世界,即C中的main函数。 10、第十行:与PROC成对出现,表示复位程序Reset_Handler结束。 11、IMPORT:表示该标号来自外部文件,跟 C 语言中的 EXTERN 关键字类似。这里表示 SystemInit 和__main 这两个函数均来自外部的文件。 12、表示弱定义,如果外部文件优先定义了该标号则首先引用该标号,如果外部文件没有声明也不会出错。这里表示复位子程序可以由用户在其他文件重新实现,这里并不是唯一的。 中断程序 拿其中一个举例,与复位程序类似 NMI_Handler PROC EXPORT NMI_Handler [WEAK] B . ENDP 省略。。。 ALIGN 解释: 1、第一行:表示中断程序NMI_Handler的开始,PROC与第四行的ENDP成对出现,表示程序的开始与结束。 2、第二行:声明NMI_Handler函数为全局属性,可以被其他文件调用。后面的WEAK表示该定义是弱引用。 3、第三行:跳转到标号(.),也就是进入了无限循环。 4、第四行:与PROC成对出现,表示中断程序NMI_Handler结束。 5、第五行:对指令或者数据存放的地址进行对齐,缺省表示 4 字节对齐(也就是ALIGN=2的意思)。 6、这里面的WEAK的意思是弱引用,详细的说就是如果别的地方有定义一个名字为NMI_Handler的函数则不会进入本汇编函数中写的NMI_Handler函数,也就不会执行到( B .)这个命令。如果外部没有定义名字为NMI_Handler的函数则进入本汇编函数后会进入无限循环。 用户堆栈初始化 IF :DEF:__MICROLIB EXPORT __initial_sp EXPORT __heap_base EXPORT __heap_limit 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 END 解释: 1、IF,ELSE,ENDIF:汇编的条件分支语句,跟 C 语言的 if ,else 类似。 2、END:文件结束。 3、如果定义了__MICROLIB则赋予标号__initial_sp(栈顶地址)、__heap_base(堆起始地址)、 __heap_limit(堆结束地址)全局属性,可供外部文件调用。 4、如果没有定义__MICROLIB则使用默认的 C 库,然后初始化用户堆栈大小,这部分有 C 库函数__main 来完成,当初始化完堆栈之后,就调用 main函数去到 C 的世界。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1627 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1550 浏览 1 评论
984 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
688 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1601 浏览 2 评论
1867浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
650浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
518浏览 3评论
536浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
506浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-24 13:17 , Processed in 0.740098 second(s), Total 78, Slave 62 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号