一、启动文件简介
启动文件由汇编编写,是系统上电复位后第一个执行的程序。主要做了以下工作:
1、初始化堆栈指针 SP=_initial_sp
2、初始化 PC 指针=Reset_Handler
3、初始化中断向量表
4、配置系统时钟
5、调用 C 库函数_main 初始化用户堆栈,从而最终调用 main 函数去到 C 的世界
二、启动文件代码讲解
1.Stack—栈
1 Stack_Size EQU 0x00000400
2
3 AREA STACK, NOINIT, READWRITE, ALIGN=3
4 Stack_Mem SPACE Stack_Size
5 __initial_sp
开辟栈的大小为 0X00000400(1KB),名字为 STACK,NOINIT 即不初始化,可读可写,8(2^3)字节对齐。
栈的作用是用于局部变量,函数调用,函数形参等的开销,栈的大小不能超过内部SRAM 的大小。
EQU:宏定义的伪指令,相当于等于,类似与 C 中的 define。
AREA:告诉汇编器汇编一个新的代码段或者数据段。STACK 表示段名,这个可以任
意命名;NOINIT表示不初始化;READWRITE表示可读可写,ALIGN=3,表示按照 2^3对齐,即 8 字节对齐。
SPACE:用于分配一定大小的内存空间,单位为字节。这里指定大小等于 Stack_Size。
标号__initial_sp紧挨着 SPACE语句放置,表示栈的结束地址,即栈顶地址,栈是由高
向低生长的。
2. Heap 堆
1 Heap_Size EQU 0x00000200
2
3 AREA HEAP, NOINIT, READWRITE, ALIGN=3
4 __heap_base
5 Heap_Mem SPACE Heap_Size
6 __heap_limit
PRESERVE8
THUMB
开辟堆的大小为 0X00000200(512 字节),名字为 HEAP,NOINIT 即不初始化,可读可写,8(2^3)字节对齐。
堆主要用来动态内存的分配,像 malloc()函数申请的内存就在堆上面。这个在 STM32里面用的比较少。
PRESERVE8:指定当前文件的堆栈按照 8 字节对齐。
THUMB:表示后面指令兼容 THUMB 指令。
3. 向量表
1 AREA RESET, DATA, READONLY
2 EXPORT __Vectors
3 EXPORT __Vectors_End
4 EXPORT __Vectors_Size
定义一个数据段,名字为 RESET,可读。
当内核响应了一个发生的异常后,对应的异常服务例程(ESR)就会执行。为了决定 ESR的入口地址, 内核使用了“向量表查表机制”。
EXPORT:声明一个标号可被外部的文件使用,使标号具有全局属性。如果是 IAR 编译器,则使用的是 GLOBAL 这个指令。
4. 复位程序
1 AREA |.text|, CODE, READONLY
定义一个名称为.text 的代码段,可读。
1 Reset_Handler PROC
2 EXPORT Reset_Handler [WEAK]
3 IMPORT SystemInit
4 IMPORT __main
5
6 LDR R0, =SystemInit
7 BLX R0
8 LDR R0, =__main
9 BX R0
10 ENDP
复位子程序是系统上电后第一个执行的程序,调用 SystemInit 函数初始化系统时钟,然后调用 C 库函数_mian,最终调用 main 函数去到 C 的世界。
WEAK:表示弱定义,如果外部文件优先定义了该标号则首先引用该标号,如果外部文件没有声明也不会出错。
IMPORT:表示该标号来自外部文件,跟 C 语言中的 EXTERN 关键字类似。
SystemInit()是一个标准的库函数,在 system_stm32f10x.c这个库文件总定义。主要作用是配置系统时钟,这里调用这个函数之后,单片机的系统时钟配被配置为 72M。
__main 是一个标准的 C 库函数,主要作用是初始化用户堆栈,并在函数的最后调用main 函数去到 C 的世界。这就是为什么我们写的程序都有一个 main 函数的原因。
5. 中断服务程序
在启动文件里面已经帮我们写好所有中断的中断服务函数,跟我们平时写的中断服务函数不一样的就是这些函数都是空的,真正的中断复服务程序需要我们在外部的 C 文件里面重新实现,这里只是提前占了一个位置而已。
1 NMI_Handler PROC ;系统异常
2 EXPORT NMI_Handler [WEAK]
3 B .
4 ENDP
5
18 LTDC_IRQHandler
19 LTDC_ER_IRQHandler
20 DMA2D_IRQHandler
21 B .
B:跳转到一个标号。这里跳转到一个‘.’,即表示无线循环。
6. 用户堆栈初始化
1 ALIGN
ALIGN:对指令或者数据存放的地址进行对齐,后面会跟一个立即数。缺省表示 4 字节对齐。
1 ;用户栈和堆初始化,由 C 库函数_main 来完成
2 IF :DEF:__MICROLIB ;这个宏在 KEIL 里面开启
3
4 EXPORT __initial_sp
5 EXPORT __heap_base
6 EXPORT __heap_limit
7
首先判断是否定义了__MICROLIB ,如果定义了这个宏则赋予标号__initial_sp(栈顶地址)、__heap_base(堆起始地址)、__heap_limit(堆结束地址)全局属性,可供外部文件调用。然后堆栈的初始化就由 C 库函数_main 来完成。
一、收获
1.栈溢出
如果编写的程序比较大,定义的局部变量很多,那么就需要修改栈的大小。如果某一天,你写的程序出现了莫名奇怪的错误,并进入了硬 fault 的时候,这时你就要考虑下是不是栈不够大,溢出了。
上一篇:STM32系统时钟RCC工作流程详解+配置函数中文注释+使用HSE代码
下一篇:STM32位带操作实现GPIO输入输出
推荐阅读最新更新时间:2024-11-19 21:48
设计资源 培训 开发板 精华推荐
- 用于高清电视的 60W、19V 交流转直流单路输出电源
- 示波器(开源)
- EM35x陶瓷巴伦参考设计
- 使用 ON Semiconductor 的 NCP1529 的参考设计
- LTC2633-HZ8 双路 8 位数模转换器的典型应用
- 使用 Analog Devices 的 LT4275BIDD 的参考设计
- MIC2130/1,适用于汽车的 50W、0.7V、1.8V、3.3V、5V DC 至 DC 单路输出电源评估板
- NSI45060JDT4G 大电流 LED 灯串的典型应用
- 基于STC89C52RC的拓展板
- 使用 Infineon Technologies AG 的 OMR9608SC 的参考设计
- 看专题答题赢好礼!PI 稳定可靠的TOPSwitch-JX开关电源IC
- EEWORLD新年有奖竞猜,邀你来出题啦!
- 来英飞凌旗舰店,探寻秋日好物!
- 辛苦一个月,EEWORLD社区3月明星人物出台喽!
- WEBENCH设计狂欢盛宴,轻松设计赢好礼!
- 网友票选TI课程热榜出炉 学习推荐有礼!
- 电源情报站 MPS小程序干货推荐,下载有好礼!
- Littelfuse 碳化硅(SiC) MOSFET和肖特基二极管产品介绍及相关应用
- TI 嵌入式处理主题直播月|报名观看直播赢好礼【低功耗WiFi MCU、Sitara AM57X平台、机器学习】
- 是德科技有奖问答活动之三,极限温度测试示波器探头方案,答题闯关赢好礼!