STM32启动过程分析

一、概述

1、STM32的启动过程:硬件复位后,到执行用户main函数之前的这段时间。

MCU主要做的工作:

1.硬件设置SP和PC

2.根据BOOT引脚状态选择重映射区

3.设置系统时钟

4.转跳至__main函数执行

2、分析启动代码主要可以分为以下几个阶段

1.开辟栈空间

Stack_Size      EQU     0x00000400

                AREA    STACK, NOINIT, READWRITE, ALIGN=3
														
Stack_Mem       SPACE   Stack_Size
__initial_sp

代码解析:

第1行:宏定义一个Stack_Size表示栈空间的大小,类似C中的#define。

第2行:表示开辟一段名为STACK,可读可写的8字节对齐的数据空间。AREA表示下面将开始定义定义一个代码段或者数据段,后面跟着这个段的属性。

第3行:SPACE伪指令通知汇编器分配0x400个字节大小的连续内存空间给STACK段。

第4行:这句伪指令紧跟着开辟栈空间伪指令,表示初始化栈顶地址,也就是这个标号表示栈顶的地址。

2.开辟堆空间

Heap_Size       EQU     0x00000200

                AREA    HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem        SPACE   Heap_Size
__heap_limit

                PRESERVE8
                THUMB

代码解析:

开辟堆空间代码与开辟栈空间代码类似,主要注意的是__heap_base表示堆空间的开始地址,__heap_limit表示堆空间的结束地址。

最后两行代码表示:指定当前文件的堆栈保持8字节对齐。因为Cortex-M3使用的是THUMB指令集,所以指定当前使用THUMB指令集。

3.开辟只读数据段

AREA    RESET, DATA, READONLY
                EXPORT  __Vectors
                EXPORT  __Vectors_End
                EXPORT  __Vectors_Size

代码解析:

第1行:开辟一段名为RESET的只读数据段

后三行:声明3个可供外部文件调用的标号

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     DMA2_Channel3_IRQHandler   ; DMA2 Channel3
                DCD     DMA2_Channel4_5_IRQHandler ; DMA2 Channel4 & Channel5
__Vectors_End

__Vectors_Size  EQU  __Vectors_End - __Vectors

代码解析:

原代码太长就只贴出一点,其主要的作用就是建立中断向量表,并将所有中断服务函数的入口地址存入表中。MCU的中断系统会将这些入口地址对应赋给PC指针,然后跳转到对应的函数中执行。

5.定义中断服务函数

Reset_Handler   PROC
                EXPORT  Reset_Handler             [WEAK]
                IMPORT  __main
                IMPORT  SystemInit
                LDR     R0, =SystemInit
                BLX     R0               
                LDR     R0, =__main
                BX      R0
                ENDP
                                    ...
                                    ...
                                    ...
                                        ...
                                        ...
SetSysClock();

#ifdef VECT_TAB_SRAM
  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
#else
  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
                                        ...
                                        ...

代码解析:

源代码太长就只贴出最重要的复位中断服务函数,其作用就是调用外部文件的SystemInit函数和__main函数。通过查找下项目文件,我们可以知道SystemInit函数主要做的就是系统时钟的初始化,各种寄存器的初始化,包括系统控制块的向量表重映射起始地址的初始化(注意区分,从内部SRAM启动或者内部FLASH启动的向量表偏移寄存器起始地址是不一样的)。

__main函数的代码没找到,个人猜测是因为这个是C库封装起来的函数。其作用就是软件设置SP指针,使之指向栈顶,然后转跳至用户main函数。

还有一点小知识:WEAK表示弱定义,声明这个标号如果外部文件有用到,则使用外部的中断服务函数。

6.用户堆栈的初始化

                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

代码解析:由此可见,使用微库和不使用微库是不一样的。个人猜测,使用微库,我们不需要自行初始化堆,因为微库不需要用到。不使用微库,我们就需要自己写初始化堆栈函数供__main调用,应该是系统库需要用到堆。

小问题:那究竟是用微库好呢?还是不用微库好呢?

答:个人认为,使用微库节省了初始化堆这一步,启动过程步骤少一点。但是微库函数都是封装好的,里面的代码我  们不得而知,所以安全性不敢保证。

二、启动方式

1.STM32的三种启动方式

BOOT0引脚状态BOOT1引脚状态启动模式
0x从FLASH中启动
10从系统存储器启动
11从内嵌SRAM中启动

 

正是因为启动方式的不同,中断向量表的起始地址也会不同,所以通过存储器重映射,能够有效解决系统上电复位之后中断向量表的存放问题,这样系统上电复位后固定从地址0x00000000获取SP,再从0x00000004获取PC后开始执行代码。这就对应上了前面说的启动过程了。

 

后记

本人的底层知识比较欠缺,写得不好,有错的地方请各位大佬指出,谢谢!

 

 

 

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值