STM3芯片三种启动方式及FLASH启动的IAP流程

一,一般启动流程

嵌入式开发与前端开发不一样,嵌入式开发者不仅要关注用户层代码编写逻辑,还要关注硬件层对代码执行流程。嵌入式设备在上电复位后,最先执行的不是我们编写的应用层代码接口main,他必须先对硬件层接口寄存器做一系列初始化动作,否则应用层脱离了硬件层将全部瘫痪。同样在写boot loader或者IAP启动的时候,我们同样要知道系统运行流程,以便于修改栈顶寄存器内容和中断向量表寄存器内容,来达到控制系统运行哪段程序。直白来讲就是在FLASH片上存放多个APP代码,且指定一个最先运行的APP,最先运行的APP就是IAP程序了,在IAP程序中,根据某些条件(是否检索到升级文件)来指定接下来运行的APP。

1,通过单步调试来观察系统运行流程

我们以前在Keil上做单步调试时候发现,一点击Debug程序立马进入main函数里面,以为main就是整个系统的入口,实际上不是的。因为我们在设置选项卡里面设置调试跳转选项。如下,将跳转至main选项给关闭掉才能跟踪到系统最开始运行流程。

在这里插入图片描述

2,开始调试

点击调试后发现,程序跳转到startup_stm32f407xx.s文件内,内容如下:

Stack_Size  EQU 0x00000400

AREASTACK, NOINIT, READWRITE, ALIGN=3

Stack_Mem   SPACE   Stack_Size

__initial_sp

本段内容开辟了一块栈空间,大小为0x400,且不做初始化,可读可写,8字节内存对其方式存储和寻址,且定义了栈顶地址为:__initial_sp

在这里插入图片描述

Heap_Size   EQU 0x00000200

AREAHEAP, NOINIT, READWRITE, ALIGN=3

__heap_base

Heap_MemSPACE   Heap_Size

__heap_limit

本段内容开辟了一块堆空间,大小为0x200,且不做初始化,可读可写,8字节内存对其方式存储和寻址,且定义了堆底地址为:顶地址为:__heap_base;堆顶地址为:__heap_limit

注意了,我们说的顶地址实际上就是堆栈区域最大地址,也就是它的深度,在堆栈地址通多顶地址然后自减来实现寻址。

在这里插入图片描述

            PRESERVE8   ;8字节对其

            THUMB        ;THUMB指令集

; Vector Table Mapped to Address 0 at Reset

AREARESET, DATA, READONLY

EXPORT  __Vectors

EXPORT  __Vectors_End

EXPORT  __Vectors_Size

本段定义了一块数据区只读内容,且底部指针地址为:__Vectors ;顶部指针地址为:__Vectors_End;大小为:__Vectors_Size

这段内容是干什么的呢,下面会对它内容填充。

在这里插入图片描述

__Vectors   DCD __initial_sp   ; Top of Stack

            DCD     Reset_Handler              ; Reset Handler

            DCD     NMI_Handler                ; NMI Handler

            DCD     HardFault_Handler          ; Hard Fault Handler

            ......

            DCD FPU_IRQHandler; FPU

__Vectors_End

__Vectors_Size  EQU  __Vectors_End - __Vectors

在上上一段代码定义了一块**__Vectors_Size大小的区域,本段则是具体将这段区域进行填充,首地址存放:__initial_sp** 栈顶指针,其次是:Reset_Handler 接下来就是其他必要的中断程序。这个区域很明显就是我们程序中至关重要的向量中断表。

在这里插入图片描述
在这里插入图片描述

__initial_sp 就是系统在识别BOOT0和BOOT1后由0X00000000跳往过来的地方,也可以看作是整个程序的起点。

Reset_Handler 则是复位中断程序的地址,和上一个起点保持4字节的位移,这是因为所有中断向量地址占用空间只是4字节(4*8=32),本芯片也是32位处理器。

AREA|.text|, CODE, READONLY


; Reset handler

Reset_HandlerPROC

 EXPORT  Reset_Handler [WEAK]

IMPORT  SystemInit

IMPORT  __main

定义reset的复位中断程序,也就是程序在执行到复位后,

EXPORT Reset_Handler 表示这个函数可以供外部C调用

IMPORT SystemInit 表示外部定义的C函数可以传递到汇编内部调用,为下面调用做好铺垫

IMPORT __main 表示外部定义的C函数可以传递到汇编内部调用,为下面调用做好铺垫

在这里插入图片描述

;memcpy the statck point to MSP

;LDR   R0,=__initial_sp

;MSR   MSP, R0

这个实际上是整个程序的第一步,也就是如上debug调试最开始进入的地方,上面介绍那么多全都是初始化。

1,把 __initial_sp 指针地址拷贝给 R0 ,也就是把上面定义向量表顶部指针地址取出来。

2,将这个地址赋值给栈顶指针MSP寄存器,也就是程序最开始执行地方(主栈指针),说白了就是寄存器映射吧。

在这里插入图片描述

;check the boost space correspands to application 

;LDR R0, = 0X0000004  

;LDR R1,  [R0] 

;LSRS R1, R1, #24

;LDR R2,=0XIF

;CMP R1,R2

在这里插入图片描述

3,向下位移4字节(就到了set_handle复位中断函数)

将R0赋值给R1

将R1向右位移24字节得出最高位的80或者1f

比较这个R1和R2(0x1f)是否相等,意思是判断系统从flash启动还是0x1f处的ISP启动

4,执行复位中断函数,上面已经定义了,主要是申明下将systeminit和_main定义为IMPORT

;BEN  application   

5,如果不是从0x1f处的ISP启动,则跳转到Aplication位置

;Application ROM

 LDR R0, =SystemInit

 BLX R0

 LDR R0, =__main

 BX  R0

 ENDP

在这里插入图片描述

6,开始执行systeminit(完成芯片正常运行所需的必备功能项的配置),这个配置内容同样非常重要,但不是本节介绍重点。

7,开始执行MDK内部封装的_main接口,主要是对:完成全局/静态变量的初始化工作(从flash到SRAM的加载)/初始化堆栈/库函数的初始化/程序的跳转,进入main()函数

; Dummy Exception Handlers (infinite loops which can be modified)


NMI_Handler PROC

EXPORT  NMI_Handler[WEAK]

B   .

ENDP

HardFault_Handler\

PROC

EXPORT  HardFault_Handler  [WEAK]

B   .

ENDP

Default_Handler PROC



            EXPORT  WWDG_IRQHandler                   [WEAK]                                        

            EXPORT  PVD_IRQHandler                    [WEAK]                      

            ......

            EXPORT  FPU_IRQHandler                    [WEAK]                



WWDG_IRQHandler   

PVD_IRQHandler  

......

FPU_IRQHandler                                                 

            B       .

            ENDP

            ALIGN

;*******************************************************************************

; User Stack and Heap initialization

;*******************************************************************************

 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

在这里插入图片描述

上面的 __user_initial_stackheap 是在系统的 _main 中自动执行,初始化栈空间和位移

;******************* © COPYRIGHT 2011 STMicroelectronics END OF FILE

二,启动模式简介

上面再讲启动流程,实是在默认flash启动用户APP程序是从0x08000000开始)基础上描述的,实际上STM32支持多种启动模式,这里进行简单介绍:

1,BOOT0和BOOT1

系统有几种启动方式,但是系统在上电前就必须需要知道从哪儿启动,实际上STM32的启动模式由芯片的启动引脚BOOT0和BOOT1决定。MCU在上电时会读取BOOT0和BOOT1引脚的电平状态并锁存,系统根据电平状态来从选择启动方式(注意:这里说的启动是指正常的上电,当我们采用jlink/jtag进行程序烧写或调试时,MCU会会忽略引脚状态)。下面是官方使用指南的说明:

在这里插入图片描述

三种启动模式对应的物理存储介质均是芯片内置的,它们是:

a.主闪存存储器 = 芯片内置的Flash。0X80

b.系统存储器 = 芯片内部一块特定的区域,芯片出厂时在这个区域预置了一段Bootloader,就是通常说的ISP程序。这个区域的内容在芯片出厂后用户无法进行读写操作。0X1F

c.SRAM = 芯片内置的RAM区,具有掉电丢失性。0X20

原文链接:https://blog.csdn.net/ye1223/article/details/79812958

本节重点讨论FLASH启动模式,在设计工程,如不是极其特殊需求,是不会用到其他两种的,讨论FLASH启动下,IAP与APP各自start文件如何编写。关于IAP程序大家不用字节写了,直接Fork在GitHub上star最多的即可。

2,FLASH启动模式下的IAP程序的start文件启动流程设计

3,FLSHA启动模式下的APP程序start文件启动流程设计

我先去取个快递吃个饭,有时间回来再更新下,尽量今晚写完吧。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值