[开发工具] STM32学习笔记(6): 启动代码(Startup Code)

[复制链接]
 楼主| 过期的塔头 发表于 2021-9-29 23:53 | 显示全部楼层
三、启动代码中的配置向导注释
启动代码中的配置向导注释详见《uVision User’s Guide》中的Utilities中的”Congiguration Wizard”。

配置向导注释被用来在汇编、C/C++或初始化文件中产生配置控制。
8175561548bcc6ad88.png
 楼主| 过期的塔头 发表于 2021-9-29 23:54 | 显示全部楼层
四、堆栈存储器

堆栈存储区是在片上存储器中的SRAM(或RAM)中由用户自行开辟的一片数据存储区域,并且堆栈区的大小可根据用户的需要任意指定(只要不超过SRAM或RAM的大小),而堆栈区的位置由编译器指定分配。
Cortex-M3/M4处理器的堆栈指针SP是“满递减,空递增”,呈现向下逆生长的特点。
堆栈区数据的存储特点是“先进后出,后进先出”。这种特点是由堆栈指针的移动方式决定的(先入栈的数据对应的指针值比较大,后入栈的数据对应的指针值比较小,而出栈时堆栈指针的值是递增的,所以指针值大的数据当然后出栈)。

堆栈的作用:局部变量的存储、函数调用时函数或子程序间数据的传递(形参的保存,其实函数调用一旦结束被调函数中定义的所有局部变量单元就会被释放)、函数调用时现场数据的保存、中断发生时现场数据的保存。
 楼主| 过期的塔头 发表于 2021-9-29 23:55 | 显示全部楼层
四、启动代码分析

1、启动代码在MDK的已安装文件中,路径如下:ARM\Pack\Keil\STM32F4xx_DFP\2.11.0\Drivers\CMSIS\Device\ST\STM32F4xx\Source\Templates\arm

2、启动代码的作用:

C程序的的执行是从主函数main()开始的。可是微控制器上电后,是如何寻找main()函数的呢?显然,我们不可能从硬件上来寻找到main()函数的入口地址。实际上,main()函数的入口地址是编译器在编译过程中分配的。并且,从微控制器上电到main()函数执行前,微控制器有个启动的过程,这个启动过程正是启动代码执行的过程,时间非常短暂。

启动代码的作用:
(1)初始化堆栈指针 SP == _initial_sp;
(2)初始PC指针 ==Reset_Handler(复位处理程序);
(3)初始化中断向量表;
(4)配置系统时钟;
(5)调用C库_main()函数初始化用户堆栈,从而最终调用main()主函数去到C世界。
 楼主| 过期的塔头 发表于 2021-9-29 23:55 | 显示全部楼层
下面是startup_stm32f429xx.s启动代码:
1692661548c6647a14.png
 楼主| 过期的塔头 发表于 2021-9-29 23:56 | 显示全部楼层
第48~52行:定义了一段大小为1KB的堆栈空间,并初始化为0。(堆栈也叫栈)
第48行:定义一个变量Stack_Size,并赋值为0x00000400;
第50行:定义一个数据段(或数据节)STACK,不零初始化,可读可写,并以8个字节对齐;
第51行:开辟一个大小为0x00000400(即1KB)的初始化为零的连续的内存空间,并命名为Stack_Mem;
第52行:_initial_sp是标号,表示堆栈的栈顶地址。

第59~64行:定义了一段大小为0.5KB的堆空间,并初始化为0。由于未用到编译器自带的内存管理(malloc , free等),不会用到堆,故可以将堆大小设置为0。
第59行:定义一个变量Heap_Size,并赋值为0x00000200;
第61行:定义一个数据段HEAP,不初始化为零,可读可写,并以8个字节对齐;
第62行:_heap_base是标号,表示堆基地址;
第63行:开辟一个大小为0x000000200(即512Bytes)的初始化为零的内存空间,并命名为Heap_Mem;
第64行:_heap_limit是标号,表示堆顶地址。

第66行:PRESERVE8表示当前文件中的堆栈区按8字节对齐;
第67行:THUMB指示汇编器将THUMB后的指令翻译成T32。

第71~190行:系统复位时,向量表被映射到零地址。
第71行:定一个代码段RESET,只可读;
第72~74行:分别定义3个全局变量 _Vectors 、_Vectors_End 及_Vectors_Size;
第76~186行:分别定义了多个连续的字存储单元,这些存储单元用于存储向量表。标号_Vectors是栈顶地址 _initial_sp,__Vectors_End表示向量表的结尾地址。

第188行:定义一个变量__Vectors_Size 用于表示向量表的大小;
第190行:定义一个代码段|.text|,只可读;

第193~202行:复位处理程序,可根据实际情况进行修改。
第193行:Reset_Handler是标号。PROC表示程序的开始。
第194行:定义一个全局变量Reset_Handler,并指定为[weak](若用户没有定义同名的Reset_Handler函数,则就去执行第195~202行的程序)。
第195~196行:告知编译器,SysemInit和_main是两个在其他文件中定义过的符号名(或函数名)。

第206~246行:空异常处理程序(函数入口)。其中,”B .”表示跳转到当前指令,所以也就是进入无限循环当中。ENDP表示程序结束。

第248~433行:空异常处理程序。系统默认的处理程序和全局符号。

第440~449行:用户栈和堆初始化程序。
第440行:IF…ELSE…ENDIF结构。如果使用(或定义)_MICROLIB,那么,定义了3个全局属性变量。否则,定义一个全局属性的标号__user_initial_stackheap,并且通知编译器本文件中应用的_use_two_region_memory在其他文件中定义了。注意:MiCROLIB缺省的情况下使用的是Keil C库。

第453~460行:分别将栈顶地址,栈底地址,堆顶地址及堆基地址存放在寄存器R1,R3,R0,R2中。
注意:堆区和栈区的名称分别代表堆区和栈区的起始地址,由于栈逆生长,所以它的名称代表栈区的栈底地址。
小叶三千 发表于 2021-9-30 08:24 | 显示全部楼层
讲解的很详细,收藏一下,之后有不会的可以翻出来看一下哈,感谢分享!
xiaoqizi 发表于 2021-10-14 15:32 | 显示全部楼层
没有需要的话不需要自己编写吧
木木guainv 发表于 2021-10-14 15:34 | 显示全部楼层
没有读过这个文件的内容
tpgf 发表于 2021-10-14 15:37 | 显示全部楼层
这个是汇编指令吗
heimaojingzhang 发表于 2021-10-14 15:41 | 显示全部楼层
语法有问题会报错吗
keaibukelian 发表于 2021-10-14 15:42 | 显示全部楼层
不同的启动方式i启动代码是不是就不一样啦
littlelida 发表于 2021-10-18 14:49 | 显示全部楼层
这是启动代码~?~
stormwind123 发表于 2021-10-18 14:57 | 显示全部楼层
这个用的是什么指令了
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 在线客服 返回列表 返回顶部
快速回复 在线客服 返回列表 返回顶部