• STM32启动文件


    一、复位电路

    在了解启动文件之前需要明白STM32的复位中断流程,STM32的复位分为上电复位和手动复位,复位的电路图如下所示:

    注意: 图中的复位电路是低电平复位,有的MCU是高电平复位。

    • 上电复位:顾名思义,上电复位就是STM32通电时,硬件自动复位的过程。从复位电路中可知,当芯片刚通电时电容两端没离子存在,所以处于充电过程,此时复位引脚等同于接地,这一过程成为上电复位。

    • 手动复位:手动复位是通过按键强行将复位引脚拉低,使芯片产生复位中断。

    二、启动文件分析准备

    1. STM32的启动文件后缀是".s"的文件,打开项目是可以看到项目中有一个startup_stm32f103xb.s的文件,如下图所示:

      打开文件后可以很清晰的看到STM32的启动流程,不过这里需要一些简单的汇编知识。没学过汇编的小伙伴也不用怕,我们只需要简单的分析即可,这里只分析流程不进行汇编指令的编写。

    2. 启动文件中常用的汇编指令

      指令 作用
      EQU 定义字符常量,相当于C语言的 define
      AREA 汇编一个新的代码段或数据段
      SPACE 分配内存空间
      PRESERVE8 当前文件堆栈需按照 8 字节对其
      EXPORT 声明全局属性,可被外部文件使用
      DCD 以字为单位分配内存,要求4字节对齐,并初始化这些内存
      PROC 定义子程序,与 ENOP 成对使用,表示子程序结束
      WEAK 弱定义,如果外部文件声明了一个标号,则优先使用外部文件定义的标号,如果外部文件没有定义,则使用当前位置的标号
      IMPORT 声明标号来自外部文件,跟 C 语言中的 EXTERN 关键字类似
      B 跳转到一个标号
      END 到达文件的末尾,文件结束
      IF,ELSE,ENDIF 汇编条件分支语句
      LDR 从存储器中加载字到一个寄存器中
      BL 跳转到由寄存器/标号给出的地址,并把跳转前的下条指令地址保存到 LR
      BLX 跳转到由寄存器给出的地址,并根据寄存器的LSE确定处理器的状态,还要把跳转前的下条指令地址保存到LR
      BX 跳转到由寄存器/标号给出的地址,不用返回

      注意: ALIGN是编译器对指令或者数据的存放地址进行对齐,一般需要跟一个立即数,缺省表示 4 字节对齐。需要注意的是:这个不是ARM的指令,是编译器的

    3. 启动流程
      (1) 硬件上电复位。
      (2) 初始化指针 SP=_initial_sp 和 PC == Reset_Handler。
      (3) 执行复位中断服务程序。

    三、启动文件的作用

    1. 初始化堆栈指针SP;
    2. 初始化程序计数器指针 PC;
    3. 设置堆、栈的大小;
    4. 设置异常向量表的入口;
    5. 配置外部SRAM作为数据存储器(这个由用户配置,一般的开发板没有外部SRAM)
    6. 设置C库的分支入口__main(最终调用mian函数)
    7. 使用库函数项目时,启动文件还调用了SystemInit函数配置系统时钟。

    四、启动代码详解

    1. 开辟栈(stack)空间,用于局部变量、函数调用、函数的参数等使用。栈的大小不能超过内部SRAM大小。

      Stack_Size		EQU     0x400
      
              AREA    STACK, NOINIT, READWRITE, ALIGN=3
      Stack_Mem       SPACE   Stack_Size
      __initial_sp
      
      • EQU:表示宏定义的伪指令,伪指令并不会生成二进制程序代码,也不会引起变量空间分配。0x400表示栈大小,注意这里是以字节为单位。
      • AREA:开辟一段可读写的数据空间,段名为stack,按照 8 字节对齐。AREA后面的关键字表示这个段的属性。
        (1) STACK:表示这个段的名字,可以任意命名。
        (2) NOINIT:表示此数据段不需要填入初始化数据。
        (3) READWRITE:表示此段可读写。
        (4) ALIGN=3:表示首地址按照 2 的 3次方对齐,也就是按照8字节对齐。
      • SPACE 这行指令告诉汇编器给STACK段分配0x400字节的连续内存空间。
      • __initial_sp紧挨SPACE放置,表示栈的结束机制,栈是从高往低使用,所以结束地址就是栈顶地址。
    2. 开辟堆(heap)空间,主要用于动态内存分配,也就是malloc、calloc、realloc等函数分配的变量空间是在堆上。

      Heap_Size      EQU     0x200
      
              AREA    HEAP, NOINIT, READWRITE, ALIGN=3
      __heap_base
      Heap_Mem        SPACE   Heap_Size
      __heap_limit
      
      • __heap_base:表示堆的开始地址
      • __heap_limit:表示堆的结束地址
    3. 文件属性定义

      PRESERVE8
      THUMB
      
          ; Vector Table Mapped to Address 0 at Reset
      AREA    RESET, DATA, READONLY
      EXPORT  __Vectors
      EXPORT  __Vectors_End
      EXPORT  __Vectors_Size
      
      • PRESERVE8:指定当前文件保持堆栈 8 字节对齐
      • THUMB:表示后面的指令是 THUMB 指令集,CM4 采用的是 THUMB - 2指令集
      • AREA:定义一块代码段,只读,段名是RESET。READONLY表示只读,缺省就表示代码段了
      • EXPORT:语句将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     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     PVD_IRQHandler             ; PVD through EXTI Line detect
                  DCD     TAMPER_IRQHandler          ; Tamper
                  DCD     RTC_IRQHandler             ; RTC
                  DCD     FLASH_IRQHandler           ; Flash
                  DCD     RCC_IRQHandler             ; RCC
                  DCD     EXTI0_IRQHandler           ; EXTI Line 0
                  DCD     EXTI1_IRQHandler           ; EXTI Line 1
                  DCD     EXTI2_IRQHandler           ; EXTI Line 2
                  DCD     EXTI3_IRQHandler           ; EXTI Line 3
                  DCD     EXTI4_IRQHandler           ; EXTI Line 4
                  DCD     DMA1_Channel1_IRQHandler   ; DMA1 Channel 1
                  DCD     DMA1_Channel2_IRQHandler   ; DMA1 Channel 2
                  DCD     DMA1_Channel3_IRQHandler   ; DMA1 Channel 3
                  DCD     DMA1_Channel4_IRQHandler   ; DMA1 Channel 4
                  DCD     DMA1_Channel5_IRQHandler   ; DMA1 Channel 5
                  DCD     DMA1_Channel6_IRQHandler   ; DMA1 Channel 6
                  DCD     DMA1_Channel7_IRQHandler   ; DMA1 Channel 7
                  DCD     ADC1_2_IRQHandler          ; ADC1_2
                  DCD     USB_HP_CAN1_TX_IRQHandler  ; USB High Priority or CAN1 TX
                  DCD     USB_LP_CAN1_RX0_IRQHandler ; USB Low  Priority or CAN1 RX0
                  DCD     CAN1_RX1_IRQHandler        ; CAN1 RX1
                  DCD     CAN1_SCE_IRQHandler        ; CAN1 SCE
                  DCD     EXTI9_5_IRQHandler         ; EXTI Line 9..5
                  DCD     TIM1_BRK_IRQHandler        ; TIM1 Break
                  DCD     TIM1_UP_IRQHandler         ; TIM1 Update
                  DCD     TIM1_TRG_COM_IRQHandler    ; TIM1 Trigger and Commutation
                  DCD     TIM1_CC_IRQHandler         ; TIM1 Capture Compare
                  DCD     TIM2_IRQHandler            ; TIM2
                  DCD     TIM3_IRQHandler            ; TIM3
                  DCD     TIM4_IRQHandler            ; TIM4
                  DCD     I2C1_EV_IRQHandler         ; I2C1 Event
                  DCD     I2C1_ER_IRQHandler         ; I2C1 Error
                  DCD     I2C2_EV_IRQHandler         ; I2C2 Event
                  DCD     I2C2_ER_IRQHandler         ; I2C2 Error
                  DCD     SPI1_IRQHandler            ; SPI1
                  DCD     SPI2_IRQHandler            ; SPI2
                  DCD     USART1_IRQHandler          ; USART1
                  DCD     USART2_IRQHandler          ; USART2
                  DCD     USART3_IRQHandler          ; USART3
                  DCD     EXTI15_10_IRQHandler       ; EXTI Line 15..10
                  DCD     RTC_Alarm_IRQHandler        ; RTC Alarm through EXTI Line
                  DCD     USBWakeUp_IRQHandler       ; USB Wakeup from suspend
      __Vectors_End
      __Vectors_Size  EQU  __Vectors_End - __Vectors
      
      • __Vectors:为向量表其实地址
      • __Vectors_End:为向量表结束地址
      • __Vectors_Size:为向量表的大小。
      • DCD:表示分配1个4字节的空间。每行DCD都会生成一个4字节的二进制代码。中断向量表存放的实际上是中断服务程序的入口地址,当异常(也就是中断实践)发生时,CPU的中断系统会将相应的入口地址赋值给PC程序计数器,之后就开始执行中断服务程序。
    5. 定义可读代码段

      AREA    |.text|, CODE, READONLY
      
      • AREA:定义一个名为.test的可读代码段
    6. 复位程序

      ; Reset handler
      Reset_Handler    PROC
                   EXPORT  Reset_Handler             [WEAK]
      IMPORT  __main
      IMPORT  SystemInit
                   LDR     R0, =SystemInit
                   BLX     R0
                   LDR     R0, =__main
                   BX      R0
                   ENDP
      
      • 复位子程序是系统上电后第一个执行的程序,调用SystemInit()函数初始化系统时钟,然后调用C库函数__main。
    7. 中断复位子程序

      ; 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
      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  TAMPER_IRQHandler          [WEAK]
                      EXPORT  RTC_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_Channel1_IRQHandler   [WEAK]
                      EXPORT  DMA1_Channel2_IRQHandler   [WEAK]
                      EXPORT  DMA1_Channel3_IRQHandler   [WEAK]
                      EXPORT  DMA1_Channel4_IRQHandler   [WEAK]
                      EXPORT  DMA1_Channel5_IRQHandler   [WEAK]
                      EXPORT  DMA1_Channel6_IRQHandler   [WEAK]
                      EXPORT  DMA1_Channel7_IRQHandler   [WEAK]
                      EXPORT  ADC1_2_IRQHandler          [WEAK]
                      EXPORT  USB_HP_CAN1_TX_IRQHandler  [WEAK]
                      EXPORT  USB_LP_CAN1_RX0_IRQHandler [WEAK]
                      EXPORT  CAN1_RX1_IRQHandler        [WEAK]
                      EXPORT  CAN1_SCE_IRQHandler        [WEAK]
                      EXPORT  EXTI9_5_IRQHandler         [WEAK]
                      EXPORT  TIM1_BRK_IRQHandler        [WEAK]
                      EXPORT  TIM1_UP_IRQHandler         [WEAK]
                      EXPORT  TIM1_TRG_COM_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  USART3_IRQHandler          [WEAK]
                      EXPORT  EXTI15_10_IRQHandler       [WEAK]
                      EXPORT  RTC_Alarm_IRQHandler        [WEAK]
                      EXPORT  USBWakeUp_IRQHandler       [WEAK]
      
      WWDG_IRQHandler
      PVD_IRQHandler
      TAMPER_IRQHandler
      RTC_IRQHandler
      FLASH_IRQHandler
      RCC_IRQHandler
      EXTI0_IRQHandler
      EXTI1_IRQHandler
      EXTI2_IRQHandler
      EXTI3_IRQHandler
      EXTI4_IRQHandler
      DMA1_Channel1_IRQHandler
      DMA1_Channel2_IRQHandler
      DMA1_Channel3_IRQHandler
      DMA1_Channel4_IRQHandler
      DMA1_Channel5_IRQHandler
      DMA1_Channel6_IRQHandler
      DMA1_Channel7_IRQHandler
      ADC1_2_IRQHandler
      USB_HP_CAN1_TX_IRQHandler
      USB_LP_CAN1_RX0_IRQHandler
      CAN1_RX1_IRQHandler
      CAN1_SCE_IRQHandler
      EXTI9_5_IRQHandler
      TIM1_BRK_IRQHandler
      TIM1_UP_IRQHandler
      TIM1_TRG_COM_IRQHandler
      TIM1_CC_IRQHandler
      TIM2_IRQHandler
      TIM3_IRQHandler
      TIM4_IRQHandler
      I2C1_EV_IRQHandler
      I2C1_ER_IRQHandler
      I2C2_EV_IRQHandler
      I2C2_ER_IRQHandler
      SPI1_IRQHandler
      SPI2_IRQHandler
      USART1_IRQHandler
      USART2_IRQHandler
      USART3_IRQHandler
      EXTI15_10_IRQHandler
      RTC_Alarm_IRQHandler
      USBWakeUp_IRQHandler
      
                      B       .
      
                      ENDP
      
      
      • WEAK:如果外部文件中定义了此中断函数,优先使用外部文件中的中断函数,反之使用当前中断函数。
      • ".":表示无限循环
      • 如果我们在使用某个外设的时候,开启了某个中断,但是又忘记编写配套的中断服务程序需或者函数名写错时,当相应的中断产生时,程序就会跳转到启动文件预先写好的空中断函数中,并且在这个空函数中无限循环,即程序就死在这里。
    8. 用户堆栈初始化

                     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
      
      • ALIGN:对指令或者数据存放的地址进行对齐,后面会跟一个立即数。缺省表示4字节对齐。
      • __user_initial_stackheap:初始化栈和堆(使用默认C库时,由__main函数进行调用)
      • 如果使用微库时,调用__MICROLIB部分的程序,反之使用默认的C库,然后初始化用户堆栈大小。微库的使用如下图所示:

    参考文献

    STM32启动文件————startup_stm32f10x_hd.s:https://wenku.baidu.com/view/3275eee00ba1284ac850ad02de80d4d8d15a0198.html

  • 相关阅读:
    AI云服务平台大全:GPU租用 | App托管 | MLOps平台
    学习Django
    如何用一部手机输出视频内容
    C# 一周入门之《C#-类和对象》Day Six
    论文笔记 - PRISM: A Rich Class of Parameterized Submodular Information Measures for Guided Subset Selection
    TCP/IP协议—DNS
    SpringBoot请求参数与响应返回值,ResponseEntity<T>自定义响应
    VMP3.6的反调试和反虚拟机
    消息中间件篇之RabbitMQ-消息不丢失
    LLM 05-大模型法律
  • 原文地址:https://www.cnblogs.com/jzcn/p/16326493.html