STM32HAL库的启动流程分析

STM32HAL库的启动流程分析

 次点击
30 分钟阅读

首先介绍一下STM32的三种启动模式

当STM32芯片上电或复位时,代码始终都是从0x00000000开始的,也就是说三种启动模式其实都是将三块存储分区映射到0x00000000处。

  • 主闪存存储器(Main Flash memory)启动
    STM32从内置的Flash启动(0x0800 0000-0x0807 FFFF),在使用JTAG或者SWD模式下载程序时,就是下载到这个里面,重启后也直接从这启动程序。

  • 系统存储器(System memory)启动
    STM32从系统存储器启动(0x1FFFF000 - 0x1FFF F7FF),这种模式启动的程序功能是由厂家设置的。一般来说,我们选用这种启动模式时,是为了通过串口烧录程序。

  • 片上SRAM(Embedded SRAM)启动
    从内置SRAM启动(0x2000 0000-0x3FFFFFFF),既然是SRAM,自然也就没有程序存储的能力了,这个模式一般用于程序调试。SRAM 只能从0x20000000进行操作,与上述两者不同。从SRAM 启动时,需要在应用程序初始化代码中重新设置向量表的位置。

分析STM32上电后第一个执行的程序代码startup文件

下面以STM32F407的启动文件为例

1.栈的设置

Stack_Size		EQU     0x400

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

这段主要进行了Stack栈的设置。栈是编译器自动分配和释放的一块连续内存,NOINIT (不初始化),READWRITE(可读可写),ALIGN=3(8 字节对齐)。

SPACE表示申请Stack_Size大小(0x400 1kb)的内存。
__initial_sp表示栈顶地址。特别声明一点,栈的顺序是由高到低的。

2.堆的设置

Heap_Size      EQU     0x200

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

                PRESERVE8
                THUMB

和栈相反,堆是程序主动申请释放的一块内存,一般不连续,NOINIT (不初始化),READWRITE(可读可写),ALIGN=3(8 字节对齐)。

SPACE Heap_Size申请了一块Heap_Size大小(0x200 512b)的内存。

__heap_limit表示堆的结束地址。

PRESERVE8表示当前文件的堆栈以8字节对齐。

THUMB表示支持THUMB指令集,当前Cortex-M系列支持THUMB-2指令集,THUMB-2是THUMB的超集同时支持16位和32位指令。

指令集就是CPU能直接读懂的代码,直观来讲就是像1110 00 0 0100 0001 0000 000000000001 这样由01组成的指令。

3.向量表

; Vector Table Mapped to Address 0 at Reset
                AREA    RESET, DATA, READONLY
                EXPORT  __Vectors
                EXPORT  __Vectors_End
                EXPORT  __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     MemManage_Handler          ; MPU Fault Handler
                DCD     BusFault_Handler           ; Bus Fault Handler
                DCD     UsageFault_Handler         ; Usage Fault Handler
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     SVC_Handler                ; SVCall Handler
                DCD     DebugMon_Handler           ; Debug Monitor Handler
                DCD     0                          ; Reserved
                DCD     PendSV_Handler             ; PendSV Handler
                DCD     SysTick_Handler            ; SysTick Handler

                ; External Interrupts
                DCD     WWDG_IRQHandler                   ; Window WatchDog                                        
                .
                .         
                .
                DCD     DMA1_Stream7_IRQHandler           ; DMA1 Stream7                                           
                DCD     FMC_IRQHandler                    ; FMC                                             
                DCD     SDIO_IRQHandler                   ; SDIO                                            
                DCD     TIM5_IRQHandler                   ; TIM5                                            
                DCD     SPI3_IRQHandler                   ; SPI3                                            
                DCD     UART4_IRQHandler                  ; UART4                                           
                DCD     UART5_IRQHandler                  ; UART5                                           
                DCD     TIM6_DAC_IRQHandler               ; TIM6 and DAC1&2 underrun errors                   
                DCD     TIM7_IRQHandler                   ; TIM7                   
                DCD     DMA2_Stream0_IRQHandler           ; DMA2 Stream 0                                   
                DCD     DMA2_Stream1_IRQHandler           ; DMA2 Stream 1                                   
                DCD     DMA2_Stream2_IRQHandler           ; DMA2 Stream 2                                   
                DCD     DMA2_Stream3_IRQHandler           ; DMA2 Stream 3                                   
                DCD     DMA2_Stream4_IRQHandler           ; DMA2 Stream 4                                   
                DCD     ETH_IRQHandler                    ; Ethernet                                        
                DCD     ETH_WKUP_IRQHandler               ; Ethernet Wakeup through EXTI line                      
                DCD     CAN2_TX_IRQHandler                ; CAN2 TX                                                
                DCD     CAN2_RX0_IRQHandler               ; CAN2 RX0                                               
                DCD     CAN2_RX1_IRQHandler               ; CAN2 RX1                                               
                DCD     CAN2_SCE_IRQHandler               ; CAN2 SCE                                               
                DCD     OTG_FS_IRQHandler                 ; USB OTG FS                                      
                DCD     DMA2_Stream5_IRQHandler           ; DMA2 Stream 5                                   
                DCD     DMA2_Stream6_IRQHandler           ; DMA2 Stream 6                                   
                DCD     DMA2_Stream7_IRQHandler           ; DMA2 Stream 7                                   
                DCD     USART6_IRQHandler                 ; USART6                                           
                DCD     I2C3_EV_IRQHandler                ; I2C3 event                                             
                DCD     I2C3_ER_IRQHandler                ; I2C3 error                                             
                DCD     OTG_HS_EP1_OUT_IRQHandler         ; USB OTG HS End Point 1 Out                      
                DCD     OTG_HS_EP1_IN_IRQHandler          ; USB OTG HS End Point 1 In                       
                DCD     OTG_HS_WKUP_IRQHandler            ; USB OTG HS Wakeup through EXTI                         
                DCD     OTG_HS_IRQHandler                 ; USB OTG HS                                      
                DCD     DCMI_IRQHandler                   ; DCMI  
                DCD     0                                 ; Reserved				                              
                DCD     HASH_RNG_IRQHandler               ; Hash and Rng
                DCD     FPU_IRQHandler                    ; FPU                   
__Vectors_End

__Vectors_Size  EQU  __Vectors_End - __Vectors

                AREA    |.text|, CODE, READONLY

向量表是一个WORD(32bit)数组,数组的每个位置都对应一种异常(中断也属于异常的一种)程序,对应的值则是其ESR(Exception Syndrome Register异常综合寄存器 在Cortex-M中并不存在 对应应该是状态寄存器(xxx_SR))的入口地址,这一整张的向量表的地址是可以更改的,在NVIC中由重定位寄存器来指出向量表的地址,在复位后,寄存器的值置0,所有向量表的地址位置应该是0。

DCD后面的0是复位后MSP(Main Stack Pointer主堆栈指针寄存器)的值。这篇说的各种寄存器会在下一篇文章中进行统一总结和归纳,觉得烧脑的同学可以详细看看下一篇文章。

AREA RESET, DATA, READONLY 表示申请一块READONLY (只读)的代码段。

EXPORT 表示__Vectors __Vectors_End __Vectors_Size 均可被外部引用并有全局属性。

__Vectors 表示向量表的起始地址。

__Vectors_End 表示向量表的结束地址。

__Vectors_Size 表示向量表的大小。

DCD 表示分配4字节的空间,每执行一次DCD就会生成一个特定的4字节的二进制代码。

4.复位程序

复位程序就是板子在复位后执行的第一个程序,它也属于中断程序的一种。

; Reset handler
Reset_Handler    PROC
                 EXPORT  Reset_Handler             [WEAK]
        IMPORT  SystemInit
        IMPORT  __main

                 LDR     R0, =SystemInit
                 BLX     R0
                 LDR     R0, =__main
                 BX      R0
                 ENDP

Reset_Handler表示声明一个程序,PROC 表示程序的开始。

EXPORT表示程序可以被外部引用,[WEAK] 表示弱定义。

IMPORT 引入了两段函数SystemInit __mainSystemInit 在system_stm32f4xx中进行了定义,__main 则是对初始化用户堆栈程序,最终会调用用户的main函数。

LDR R0, =SystemInit 表示将SystemInit 载入寄存器R0地址中。

BLX R0 表示跳转到寄存器R0,根据寄存器的LSE确定状态,并将跳转前的下条指令地址保存到LR。

LDR R0, =__main 同理,不再过多赘述

BX R0 只跳转不返回。

ENDP 表示程序的结束。

5.中断服务程序

这部分就没什么好说的了,内容较为统一,都是允许被外部引用,B . 表示无限循环。

ALIGN表示对指令或者数据存放的地址进行对齐,缺省表示4字节对齐。

6.堆栈的初始化

                 IF      :DEF:__MICROLIB
                
                 EXPORT  __initial_sp
                 EXPORT  __heap_base
                 EXPORT  __heap_limit
                
                 ELSE
                
                 IMPORT  __use_two_region_memory
                 EXPORT  __user_initial_stackheap

显而易见,影响堆栈初始化的唯一判断条件就是MICROLIB的开启与否。

结尾

至此,你已经对STM32启动流程有一定认识了,下一篇文章我们会详细介绍STM32当中的寄存器。

© 本文著作权归作者所有,未经许可不得转载使用。