历史上的今天
返回首页

历史上的今天

今天是:2024年12月14日(星期六)

2021年12月14日 | STM32启动文件执行步骤分析

2021-12-14 来源:eefocus

一、启动文件简介

启动文件由汇编编写,是系统上电复位后第一个执行的程序。主要做了以下工作:

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 的时候,这时你就要考虑下是不是栈不够大,溢出了。

推荐阅读

史海拾趣

Dantona Industries公司的发展小趣事

随着公司实力的增强,Dantona Industries开始寻求市场扩张的机会。他们首先将目光投向了海外市场,通过参加国际展会、建立海外销售网络等方式,逐步打开了国际市场的大门。然而,市场扩张也带来了新的挑战。不同国家和地区的市场需求、文化差异、法律法规等因素都需要公司去适应和应对。在这个过程中,Dantona Industries展现了出色的市场洞察力和应变能力,成功克服了各种困难,实现了市场的稳步扩张。

冠图电子(GTL-POWER)公司的发展小趣事

随着公司实力的增强,Dantona Industries开始寻求市场扩张的机会。他们首先将目光投向了海外市场,通过参加国际展会、建立海外销售网络等方式,逐步打开了国际市场的大门。然而,市场扩张也带来了新的挑战。不同国家和地区的市场需求、文化差异、法律法规等因素都需要公司去适应和应对。在这个过程中,Dantona Industries展现了出色的市场洞察力和应变能力,成功克服了各种困难,实现了市场的稳步扩张。

华宇创公司的发展小趣事

随着市场的不断发展,华宇创意识到单一产品无法满足日益增长的市场需求。于是,公司加大了对研发的投入,积极引进高端人才,与国内外知名科研机构建立合作关系。经过不懈努力,华宇创成功研发出一系列智能电子设备,包括智能手表、智能眼镜、智能家居控制器等。这些新产品的推出不仅丰富了公司的产品线,也进一步提升了华宇创的市场竞争力。

HP(Keysight)公司的发展小趣事

在21世纪初,电子科技正处于蓬勃发展的时期。李华,一位在电子行业摸爬滚打多年的工程师,决定创立自己的公司——华宇创,专注于智能电子设备的研发和生产。创业初期,华宇创面临着资金短缺、技术瓶颈等诸多挑战。然而,李华凭借对技术的热情和坚定的信念,带领团队日夜兼程地研发新产品,最终成功推出了首款具有竞争力的智能手环,获得了市场的初步认可。

Analogic Corporation公司的发展小趣事

随着市场的不断发展,华宇创意识到单一产品无法满足日益增长的市场需求。于是,公司加大了对研发的投入,积极引进高端人才,与国内外知名科研机构建立合作关系。经过不懈努力,华宇创成功研发出一系列智能电子设备,包括智能手表、智能眼镜、智能家居控制器等。这些新产品的推出不仅丰富了公司的产品线,也进一步提升了华宇创的市场竞争力。

GE (General Electric)公司的发展小趣事
如急停按钮SB1,用于在紧急情况下迅速切断电源,保障操作安全。

问答坊 | AI 解惑

推荐--开关电源研发范例

内部研发教材,吐血推荐!…

查看全部问答>

求一个简单放大器的输出

如图示 其中Uout2为+2.5V电压      Uin 范围为0~5V 求解放大器输出信号的波形和幅度…

查看全部问答>

电路板发热,电源芯片LT1085发热

我的电路板用一个1085-5V芯片转换成5V,用一个1085-3.3V转换成3.3V,5V给AD等外围芯片供电,3.3主要给核心板供电,我的程序运行一会,核心板,电源芯片就会很烫,电源芯片带的底板也很烫。功率也满足要求。请问各位高手该如何解决发热问题?…

查看全部问答>

求助一道很简单的题目

将内存单元1000-1030H中的内容复制到3000-3030H单元中去,原地址清0 我的代码在下面,下载地址1000H,自修改代码,他说改下载地址,自己内存放点东西,他要看到结果,不放东西全部是0,复制过去也没效果。老师很BT,要求十分严格。EMBESTIDE环境 ...…

查看全部问答>

求助ucgui时间获取函数!

本人的工作是将ucgui移植到nucleus系统上,nucleus系统时间的获取是通过将时钟节拍转化而来的,但本人对时钟节拍不怎么熟悉,按照自己的思路问题主要是出在到时钟节拍超出时钟节拍临界值时(其实本人也不清楚时钟节拍复位为0是怎么处理的),时 ...…

查看全部问答>

socket的建立

在vxworks下想实现socket的通讯,建立了一个虚拟机,里面跑的是vxworks,是服务端 在windows下,用VC实现的客户端。 问题是发现服务端的socket无法建立,不知是不是写错了,代码如下: netInit() {         struct sockad ...…

查看全部问答>

嵌入式技术交流群 24992320 欢迎加入啊

嵌入式技术交流群 24992320 欢迎加入啊 …

查看全部问答>

TIM4的4路输出能从PB6..PB9,但是不能从PD12...PD15输出

                                 端口的配置完全一样,且增加的函数GPIO_PinRemapConfig(GPIO_Remap_TIM4, ENABLE);…

查看全部问答>

请问ST32复位时IO口处于什么状态?

                                 如题。我说的是复位过程中,而不是复位后。谢谢!!!…

查看全部问答>

求购一套STM8L101的开发板,和配套的ST-Link

请版主帮指个路。 各位代理有的话,欢迎报价。 我手头的STM8L101都连不上SWIM,用ST-Link也不行,郁闷。 STM8L152可以。 已经有客户求购EP868用于STM8L了。。。。。…

查看全部问答>