典型arm32位单片机启动流程(从上电到main.c)

0 启动流程

  1. 复位
  2. 通过boot引脚选择启动模式
  3. 从地址0x00000000读取 __initial_sp 初始栈顶值到MSP
  4. 从地址0x00000004读取 Reset_Handler 地址到PC
  • 32位系统, 字长4字节
  1. 指向复位向量的内容
  2. 执行SystemInit函数, 初始化系统时钟
  3. 执行__main, 软件设置SP指针, 初始化栈空间, 清除bss段, 最后跳转到mian函数
    典型arm32位单片机启动流程(从上电到main.c)

1 启动模式

BOOT0 BOOT1 启动模式
0 X 从FLASH启动0x0800 0000
1 0 从系统存储器启动(bootROM)
1 1 从RAM启动0x2000 0000
  • pc指针在硬件复位后会自动指向0x0000 0000, 而Flash实际起始地址:0x0800 0000, RAM实际起始地址: 0x2000 0000, 硬件会自动将0x0000 0000映射到对应的地址

2 启动流程

2.1 Reset_Handler 复位向量

2.1.1 Reset_Handler 源代码:

; Reset handler Reset_Handler    PROC                  EXPORT  Reset_Handler             [WEAK]         IMPORT  SystemInit         IMPORT  __main                   LDR     R0, =SystemInit                  BLX     R0                  LDR     R0, =__main                  BX      R0                  ENDP 

2.1.2 代码分析:

导入 SystemInit 和 __main 两个符号,并LDR数据到R0寄存器,跳转执行(BLX/BX)

2.2 SystemInit

2.2.1 SystemInit源代码:

2.2.1.1HAL库中的SystemInit

void SystemInit(void) {   /* FPU settings ------------------------------------------------------------*/   #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)     SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));  /* set CP10 and CP11 Full Access */   #endif  #if defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM)   SystemInit_ExtMemCtl();  #endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */    /* Configure the Vector Table location -------------------------------------*/ #if defined(USER_VECT_TAB_ADDRESS)   SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */ #endif /* USER_VECT_TAB_ADDRESS */ } 

2.2.1.2 STD库中的SystemInit

典型arm32位单片机启动流程(从上电到main.c)

2.2.2 代码分析:

  1. HAL库中的SystemInit: 根据宏配置初始化FPU, 外部SRAM, 中断向量表(根据用户设置的地址)
  2. STD库中的SystemInit: 根据宏配置初始化FPU, 外部SRAM, 初始化PLL, 设置系统时钟, 根据宏设置中断向量表地址(只能配置FLASH_BASE和SRAM_BASE)

2.3 __main

2.3.1 代码分析:

1. _初始化RW段和ZI段   - RW:程序中已经初始化的变量所占空间   - ZI:未初始化的static和全局变量以及堆栈所占的空间 2. 调用__rt_entry()函数   1. __user_initial_stackheap 是 标准C库初始化时自动调用的函数,主要用于向C库传递堆(Heap)和栈(Stack)的地址信息。它的执行时机会在复位处理函数跳转到 __main 后,在 C库初始化阶段自动触发   2. 初始化堆栈   3. 初始化库函数   4. 最后跳转到main函数 

3 进入mian函数

4 启动文件分析

4.1 __initial_sp

栈顶地址,复位时 CPU 会把这个值加载到堆栈指针 SP,告诉程序临时数据存哪里。

Stack_Size      EQU     0x800              ; 定义栈大小为 2KB (2048 bytes)  AREA    STACK, NOINIT, READWRITE, ALIGN=3  ; 定义一个名为 STACK 的内存区域 Stack_Mem       SPACE   Stack_Size         ; 分配连续 2KB 的栈内存空间 __initial_sp                               ; 声明栈顶符号 

4.2 __heap_limit

Heap_Size      EQU     0x400          ; 定义堆大小为 1KB (1024 bytes)                 AREA    HEAP, NOINIT, READWRITE, ALIGN=3  ; 定义可读写、8字节对齐的HEAP段 __heap_base                           ; 堆起始地址符号(链接器识别) Heap_Mem        SPACE   Heap_Size     ; 分配连续 1KB 堆内存空间 __heap_limit                          ; 堆结束地址符号(Heap_Mem + Heap_Size) 

4.3 处理器模式设置

PRESERVE8             ; 要求堆栈8字节对齐(兼容Cortex-M系列)                 THUMB                 ; 指定使用Thumb指令集 

4.4 中断向量表

AREA    RESET, DATA, READONLY  ; 定义只读数据段                 EXPORT  __Vectors      ; 导出向量表起始地址(用于链接脚本)                 EXPORT  __Vectors_End                 EXPORT  __Vectors_Size__Vectors                                               DCD     __initial_sp  ; 地址0: 主栈顶地址(硬件自动加载到MSP)                 DCD     Reset_Handler ; 地址4: 复位处理函数(程序入口)                  ; ▼ 内核异常向量 ▼                 DCD     NMI_Handler                ; NMI                 DCD     HardFault_Handler          ; 硬件错误                 DCD     MemManage_Handler          ; 内存管理错误                 DCD     BusFault_Handler           ; 总线错误                 DCD     UsageFault_Handler         ; 用法错误                 DCD     0                          ; 保留                 DCD     0                                           DCD     0                                           DCD     0                                           DCD     SVC_Handler                ; 系统调用                 DCD     DebugMon_Handler           ; 调试监控                 DCD     0                                           DCD     PendSV_Handler             ; 可挂起系统调用                  DCD     SysTick_Handler            ; 系统节拍定时器                   ; ▼ 外设中断向量 ▼                  DCD     WWDG_IRQHandler            ; 窗口看门狗                                                       DCD     PVD_IRQHandler             ; 电源电压检测                                                  DCD     TAMP_STAMP_IRQHandler       ; 入侵检测和时间戳                ;  ...(后续DCD均为具体外设的中断入口)  __Vectors_End                        ; 向量表结束标识  __Vectors_Size  EQU  __Vectors_End - __Vectors  ; 计算向量表大小 4.5 Reset_Handler ; Reset handler Reset_Handler    PROC                  EXPORT  Reset_Handler             [WEAK]         IMPORT  SystemInit         IMPORT  __main                   LDR     R0, =SystemInit                  BLX     R0                  LDR     R0, =__main                  BX      R0                  ENDP 

4.6 异常处理函数

NMI_Handler     PROC                 EXPORT  NMI_Handler                [WEAK]                 B       .                 ENDP HardFault_Handler                 PROC                 EXPORT  HardFault_Handler          [WEAK]                 B       .                 ENDP MemManage_Handler                 PROC                 EXPORT  MemManage_Handler          [WEAK]                 B       .                 ENDP BusFault_Handler                 PROC                 EXPORT  BusFault_Handler           [WEAK]                 B       .                 ENDP UsageFault_Handler                 PROC                 EXPORT  UsageFault_Handler         [WEAK]                 B       .                 ENDP SVC_Handler     PROC                 EXPORT  SVC_Handler                [WEAK]                 B       .                 ENDP DebugMon_Handler                 PROC                 EXPORT  DebugMon_Handler           [WEAK]                 B       .                 ENDP PendSV_Handler  PROC                 EXPORT  PendSV_Handler             [WEAK]                 B       .                 ENDP SysTick_Handler PROC                 EXPORT  SysTick_Handler            [WEAK]                 B       .                 ENDP  Default_Handler PROC                  EXPORT  WWDG_IRQHandler                   [WEAK]                                                         EXPORT  PVD_IRQHandler                    [WEAK]                                       EXPORT  TAMP_STAMP_IRQHandler             [WEAK]                          EXPORT  RTC_WKUP_IRQHandler               [WEAK]                                      EXPORT  FLASH_IRQHandler                  [WEAK]                                                          EXPORT  RCC_IRQHandler                    [WEAK]                                                             EXPORT  EXTI0_IRQHandler                  [WEAK]                                                             EXPORT  EXTI1_IRQHandler                  [WEAK]                                                              EXPORT  EXTI2_IRQHandler                  [WEAK]                                                             EXPORT  EXTI3_IRQHandler                  [WEAK]                                                            EXPORT  EXTI4_IRQHandler                  [WEAK]                                                             EXPORT  DMA1_Stream0_IRQHandler           [WEAK]                                                 EXPORT  DMA1_Stream1_IRQHandler           [WEAK]                                                    EXPORT  DMA1_Stream2_IRQHandler           [WEAK]                                                    EXPORT  DMA1_Stream3_IRQHandler           [WEAK]                                                    EXPORT  DMA1_Stream4_IRQHandler           [WEAK]                                                    EXPORT  DMA1_Stream5_IRQHandler           [WEAK]                                                    EXPORT  DMA1_Stream6_IRQHandler           [WEAK]                                                    EXPORT  ADC_IRQHandler                    [WEAK]                                                                                         EXPORT  EXTI9_5_IRQHandler                [WEAK]                                                     EXPORT  TIM1_BRK_TIM9_IRQHandler          [WEAK]                                   EXPORT  TIM1_UP_TIM10_IRQHandler          [WEAK]                                 EXPORT  TIM1_TRG_COM_TIM11_IRQHandler     [WEAK]                  EXPORT  TIM1_CC_IRQHandler                [WEAK]                                                    EXPORT  TIM2_IRQHandler                   [WEAK]                                                             EXPORT  TIM3_IRQHandler                   [WEAK]                                                             EXPORT  TIM4_IRQHandler                   [WEAK]                                                             EXPORT  I2C1_EV_IRQHandler                [WEAK]                                                              EXPORT  I2C1_ER_IRQHandler                [WEAK]                                                              EXPORT  I2C2_EV_IRQHandler                [WEAK]                                                             EXPORT  I2C2_ER_IRQHandler                [WEAK]                                                                EXPORT  SPI1_IRQHandler                   [WEAK]                                                            EXPORT  SPI2_IRQHandler                   [WEAK]                                                             EXPORT  USART1_IRQHandler                 [WEAK]                                                           EXPORT  USART2_IRQHandler                 [WEAK]                                                                                                   EXPORT  EXTI15_10_IRQHandler              [WEAK]                                                   EXPORT  RTC_Alarm_IRQHandler              [WEAK]                                   EXPORT  OTG_FS_WKUP_IRQHandler            [WEAK]                                         EXPORT  DMA1_Stream7_IRQHandler           [WEAK]                                                                                                      EXPORT  SDIO_IRQHandler                   [WEAK]                                                              EXPORT  TIM5_IRQHandler                   [WEAK]                                                              EXPORT  SPI3_IRQHandler                   [WEAK]                                                                                EXPORT  DMA2_Stream0_IRQHandler           [WEAK]                                                   EXPORT  DMA2_Stream1_IRQHandler           [WEAK]                                                    EXPORT  DMA2_Stream2_IRQHandler           [WEAK]                                                     EXPORT  DMA2_Stream3_IRQHandler           [WEAK]                                                     EXPORT  DMA2_Stream4_IRQHandler           [WEAK]                                                                                                                      EXPORT  OTG_FS_IRQHandler                 [WEAK]                                                        EXPORT  DMA2_Stream5_IRQHandler           [WEAK]                                                    EXPORT  DMA2_Stream6_IRQHandler           [WEAK]                                                    EXPORT  DMA2_Stream7_IRQHandler           [WEAK]                                                    EXPORT  USART6_IRQHandler                 [WEAK]                                                            EXPORT  I2C3_EV_IRQHandler                [WEAK]                                                               EXPORT  I2C3_ER_IRQHandler                [WEAK]                                                               EXPORT  FPU_IRQHandler                    [WEAK]                                 EXPORT  SPI4_IRQHandler                   [WEAK]                 EXPORT  SPI5_IRQHandler                   [WEAK] 

4.7 __user_initial_stackheap

                IF      :DEF:__MICROLIB  ; 当使用微库时的路径                 ; ▼ 直接导出符号供微库使用 ▼                                  EXPORT  __initial_sp     ; 导出初始栈顶地址(MICROLIB需要)                                  EXPORT  __heap_base      ; 导出堆起始地址                                  EXPORT  __heap_limit     ; 导出堆结束地址                                                  ELSE      ; 使用标准C库时的路径                                  ; ▼ 导出动态堆栈初始化函数 ▼                                  IMPORT  __use_two_region_memory  ; 声明C库内存模型                                  EXPORT  __user_initial_stackheap  ; 导出初始化函数                  __user_initial_stackheap  ; 堆栈初始化函数(由C库调用)                                  LDR     R0, =Heap_Mem    ; R0 = 堆起始地址(用于malloc)                                  LDR     R1, =(Stack_Mem + Stack_Size)  ; R1 = 栈顶地址                                  LDR     R2, = (Heap_Mem +  Heap_Size)   ; R2 = 堆结束地址                                  LDR     R3, =Stack_Mem    ; R3 = 栈底地址(监测栈溢出)                                  BX      LR                ; 返回调用者(C库)                                                   ENDIF                 END  ; 文件结束 

参考文档

[深入剖析STM32]STM32 启动流程详解
stm32的启动文件详解 Reset_Handler做了什么工作 疑问--初始化pc指针的操作在哪里 ---硬件设置SP 和 PC的值_reset handler-CSDN博客
STM32启动代码分析及其汇编学习-ARM - 蓝天上的云℡ - 博客园
STM32_从SystemInit、__main到main() 已修正 - 蓝天上的云℡ - 博客园
STM32启动过程详解-CSDN博客
关于ARM CM3的启动文件分析 - strongwong - 博客园
15. 启动文件详解 — [野火]STM32库开发实战指南——基于野火霸天虎开发板 文档

发表评论

评论已关闭。

相关文章