• 兆易创新 GD32 系列(一) 启动过程分析


    起始和STM32的启动过程是一样的

    EQU:给数字常量取一个符号名,相当于C语言中的define
    AREA:指示汇编程序汇编新的代码或数据段。
    SPACE:分配内存空间
    PRESERVE8:当前文件堆栈需按照8字节对齐
    EXPORT:声明一个标号具有全局属性,可被外部的文件使用
    DCD:以字为单位分配内存,要求4字节对齐,并要求初始化这些内存
    PROC:定义子程序,与ENDP成对使用,表示子程序结束
    MSR:Move to Special register from Register. 恢复到特殊寄存器
    WEAK:弱定义,如果外部文件声明了一个标号,则优先使用外部文件定义的标号,如果外部文件没有定义也不出错。要注意的是:这个不是ARM的指令,是编译器的,这里放在一起只是为了方便。
    IMPORT:声明标号来自外部文件,跟C语言中的EXTERN关键字类似
    B:跳转到一个标号ALIGN编译器对指令或者数据的存放地址进行对齐,一般需要跟一个立即数,缺省表示4字节对齐。要注意的是:这个不是ARM的指令,是编译器的,这里放在一起只是为了方便。
    END:到达文件的末尾,文件结束
    IF,ELSE,ENDIF:汇编条件分支语句,跟C语言的if else类似

    Stack_Size      EQU     0x00000400
    
                    AREA    STACK, NOINIT, READWRITE, ALIGN=3
    Stack_Mem       SPACE   Stack_Size
    __initial_sp
    
    • 1
    • 2
    • 3
    • 4
    • 5

    EQU 类似C语言的define
    Stack_Size EQU 0x800,表示Stack_Size 为0x00000400

    AREA STACK, NOINIT, READWRITE, ALIGN=3

    用AREA指令定义一个段,代码节或数据节。说明所定义段的相关属性。(说明段的名字,段的属性)
    NOINIT 不初始化
    READWRITE 可读写
    ALIGN=3 按照8*2^3 =64字节对齐

    Stack_Mem SPACE Stack_Size

    Stack_Mem 分配内存空间大小为 0x00000400
    __initial_sp 表示Stack_Mem 空间的结束地址。栈顶地址,栈是由高向低生长的

    Heap_Size       EQU     0x00000400
    
                    AREA    HEAP, NOINIT, READWRITE, ALIGN=3
    __heap_base
    Heap_Mem        SPACE   Heap_Size
    __heap_limit
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    同理heap空间的申请也是一样的,__heap_base表示起始地址,__heap_limit表示结束地址
    在编译后mmp文件中有记录内存地址

        HEAP                                     0x20012e10   Section     1024  startup_gd32f450_470.o(HEAP)
        Heap_Mem                                 0x20012e10   Data        1024  startup_gd32f450_470.o(HEAP)
        STACK                                    0x20013210   Section     1024  startup_gd32f450_470.o(STACK)
        Stack_Mem                                0x20013210   Data        1024  startup_gd32f450_470.o(STACK)
        __initial_sp                             0x20013610   Data           0  startup_gd32f450_470.o(STACK)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    0x20013210 - 0x20012e10 = 0x400
    0x20013610 - 0x20013210 = 0x400

      /* reset Vector Mapped to at Address 0 */
                    AREA    RESET, DATA, READONLY
                    EXPORT  __Vectors
                    EXPORT  __Vectors_End
                    EXPORT  __Vectors_Size
    
    • 1
    • 2
    • 3
    • 4
    • 5

    一样的做法申请一块区域 RESET 数据段,只读。内存是可读可写的,所以只读指的是FLASH上的空间,原本指的是ROM。

    EXPORT:声明一个标号具有全局属性,可被外部的文件使用
    三个声明部分不占用空间
    下面接着是 RESET 空间向量,按照顺序排列

    DCD:以字为单位分配内存,要求4字节对齐,并要求初始化这些内存

       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 handler */
                    DCD     WWDGT_IRQHandler                  ; 16:Window Watchdog Timer
                    DCD     LVD_IRQHandler                    ; 17:LVD through EXTI Line detect
                    DCD     TAMPER_STAMP_IRQHandler           ; 18:Tamper and TimeStamp through EXTI Line detect
                    DCD     RTC_WKUP_IRQHandler               ; 19:RTC Wakeup through EXTI Line
                    DCD     FMC_IRQHandler                    ; 20:FMC
                    DCD     RCU_CTC_IRQHandler                ; 21:RCU and CTC
                    DCD     EXTI0_IRQHandler                  ; 22:EXTI Line 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    DCD __initial_sp ; Top of Stack 排在第一位
    DCD Reset_Handler ; Reset Handler 排在第二位
    一次排列成一张表
    __initial_sp ,Reset_Handler 这些标号都是地址。
    __Vectors 开头 以__Vectors_End 结尾

    __Vectors_Size  EQU     __Vectors_End - __Vectors
    
    • 1

    接着是 申请一块空间

     AREA    |.text|, CODE, READONLY
    
    ;/* reset Handler */
    Reset_Handler   PROC
                    EXPORT  Reset_Handler                     [WEAK]
                    IMPORT  SystemInit
                    IMPORT  __main
                    LDR     R0, =SystemInit
                    BLX     R0
                    LDR     R0, =__main
                    BX      R0
                    ENDP
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    PROC:定义子程序,与ENDP成对使用,表示子程序结束
    同样是定义了只读FLASH空间,标号为Reset_Handler ,并且可以被外部引用
    IMPORT:声明标号来自外部文件,跟C语言中的EXTERN关键字类似
    然后依次执行 外部函数 SystemInit,__main(由MDK环境自动生成)
    SystemInit 一般做时钟配置
    __main 一般是配置C语言运行环境,堆栈的初始化

    ;/* dummy Exception Handlers */
    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\
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    上面的意思是定义Vectors对应处理函数地址。[WEAK]表示如果外部有定义则优先链接外部的函数。
    B .是循环的意思,如果没有定义就会无限循环。
    可以看到在Default_Handler PROC 之前都是会无限循环的,也就是说如果没写对应的函数就会卡在循环中。

    ;/* reset Handler */
    Reset_Handler   PROC
                    EXPORT  Reset_Handler                     [WEAK]
                    IMPORT  SystemInit
                    IMPORT  __main
                    LDR     R0, =SystemInit
                    BLX     R0
                    LDR     R0, =__main
                    BX      R0
                    ENDP
    
    ;/* dummy Exception Handlers */
    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
    ;               /* external interrupts handler */
                    EXPORT  WWDGT_IRQHandler                  [WEAK]
                    EXPORT  LVD_IRQHandler                    [WEAK]                  
                    EXPORT  TAMPER_STAMP_IRQHandler           [WEAK]           
                    EXPORT  RTC_WKUP_IRQHandler               [WEAK]               
                    EXPORT  FMC_IRQHandler                    [WEAK]                
                    EXPORT  RCU_CTC_IRQHandler                [WEAK]                 
                    EXPORT  EXTI0_IRQHandler                  [WEAK]                  
                    EXPORT  EXTI1_IRQHandler                  [WEAK]                 
                    EXPORT  EXTI2_IRQHandler                  [WEAK]               
                    EXPORT  EXTI3_IRQHandler                  [WEAK]                
                    EXPORT  EXTI4_IRQHandler                  [WEAK]                 
                    EXPORT  DMA0_Channel0_IRQHandler          [WEAK]         
                    EXPORT  DMA0_Channel1_IRQHandler          [WEAK]          
                    EXPORT  DMA0_Channel2_IRQHandler          [WEAK]        
                    EXPORT  DMA0_Channel3_IRQHandler          [WEAK]         
                    EXPORT  DMA0_Channel4_IRQHandler          [WEAK]          
                    EXPORT  DMA0_Channel5_IRQHandler          [WEAK]          
                    EXPORT  DMA0_Channel6_IRQHandler          [WEAK]          
                    EXPORT  ADC_IRQHandler                    [WEAK]         
                    EXPORT  CAN0_TX_IRQHandler                [WEAK]          
                    EXPORT  CAN0_RX0_IRQHandler               [WEAK]          
                    EXPORT  CAN0_RX1_IRQHandler               [WEAK]           
                    EXPORT  CAN0_EWMC_IRQHandler              [WEAK]           
                    EXPORT  EXTI5_9_IRQHandler                [WEAK]           
                    EXPORT  TIMER0_BRK_TIMER8_IRQHandler      [WEAK]  
                    EXPORT  TIMER0_UP_TIMER9_IRQHandler       [WEAK]  
                    EXPORT  TIMER0_TRG_CMT_TIMER10_IRQHandler [WEAK]
                    EXPORT  TIMER0_Channel_IRQHandler         [WEAK]        
                    EXPORT  TIMER1_IRQHandler                 [WEAK]       
                    EXPORT  TIMER2_IRQHandler                 [WEAK]           
                    EXPORT  TIMER3_IRQHandler                 [WEAK]           
                    EXPORT  I2C0_EV_IRQHandler                [WEAK]          
                    EXPORT  I2C0_ER_IRQHandler                [WEAK]         
                    EXPORT  I2C1_EV_IRQHandler                [WEAK]         
                    EXPORT  I2C1_ER_IRQHandler                [WEAK]         
                    EXPORT  SPI0_IRQHandler                   [WEAK]        
                    EXPORT  SPI1_IRQHandler                   [WEAK]          
                    EXPORT  USART0_IRQHandler                 [WEAK]         
                    EXPORT  USART1_IRQHandler                 [WEAK]         
                    EXPORT  USART2_IRQHandler                 [WEAK]        
                    EXPORT  EXTI10_15_IRQHandler              [WEAK]        
                    EXPORT  RTC_Alarm_IRQHandler              [WEAK]        
                    EXPORT  USBFS_WKUP_IRQHandler             [WEAK]        
                    EXPORT  TIMER7_BRK_TIMER11_IRQHandler     [WEAK] 
                    EXPORT  TIMER7_UP_TIMER12_IRQHandler      [WEAK] 
                    EXPORT  TIMER7_TRG_CMT_TIMER13_IRQHandler [WEAK]
                    EXPORT  TIMER7_Channel_IRQHandler         [WEAK]        
                    EXPORT  DMA0_Channel7_IRQHandler          [WEAK]       
                    EXPORT  EXMC_IRQHandler                   [WEAK]         
                    EXPORT  SDIO_IRQHandler                   [WEAK]           
                    EXPORT  TIMER4_IRQHandler                 [WEAK]           
                    EXPORT  SPI2_IRQHandler                   [WEAK]          
                    EXPORT  UART3_IRQHandler                  [WEAK]          
                    EXPORT  UART4_IRQHandler                  [WEAK]          
                    EXPORT  TIMER5_DAC_IRQHandler             [WEAK]         
                    EXPORT  TIMER6_IRQHandler                 [WEAK]        
                    EXPORT  DMA1_Channel0_IRQHandler          [WEAK]          
                    EXPORT  DMA1_Channel1_IRQHandler          [WEAK]          
                    EXPORT  DMA1_Channel2_IRQHandler          [WEAK]         
                    EXPORT  DMA1_Channel3_IRQHandler          [WEAK]         
                    EXPORT  DMA1_Channel4_IRQHandler          [WEAK]          
                    EXPORT  ENET_IRQHandler                   [WEAK]         
                    EXPORT  ENET_WKUP_IRQHandler              [WEAK]         
                    EXPORT  CAN1_TX_IRQHandler                [WEAK]          
                    EXPORT  CAN1_RX0_IRQHandler               [WEAK]         
                    EXPORT  CAN1_RX1_IRQHandler               [WEAK]          
                    EXPORT  CAN1_EWMC_IRQHandler              [WEAK]          
                    EXPORT  USBFS_IRQHandler                  [WEAK]          
                    EXPORT  DMA1_Channel5_IRQHandler          [WEAK]          
                    EXPORT  DMA1_Channel6_IRQHandler          [WEAK]          
                    EXPORT  DMA1_Channel7_IRQHandler          [WEAK]          
                    EXPORT  USART5_IRQHandler                 [WEAK]          
                    EXPORT  I2C2_EV_IRQHandler                [WEAK]         
                    EXPORT  I2C2_ER_IRQHandler                [WEAK]          
                    EXPORT  USBHS_EP1_Out_IRQHandler          [WEAK]    
                    EXPORT  USBHS_EP1_In_IRQHandler           [WEAK]    
                    EXPORT  USBHS_WKUP_IRQHandler             [WEAK]             
                    EXPORT  USBHS_IRQHandler                  [WEAK]            
                    EXPORT  DCI_IRQHandler                    [WEAK]                      
                    EXPORT  TRNG_IRQHandler                   [WEAK]          
                    EXPORT  FPU_IRQHandler                    [WEAK]          
                    EXPORT  UART6_IRQHandler                  [WEAK]          
                    EXPORT  UART7_IRQHandler                  [WEAK]          
                    EXPORT  SPI3_IRQHandler                   [WEAK]          
                    EXPORT  SPI4_IRQHandler                   [WEAK]          
                    EXPORT  SPI5_IRQHandler                   [WEAK]                 
                    EXPORT  TLI_IRQHandler                    [WEAK]         
                    EXPORT  TLI_ER_IRQHandler                 [WEAK]         
                    EXPORT  IPA_IRQHandler                    [WEAK]      
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147

    最后初始化堆栈

                    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 PROC
                    LDR     R0, =  Heap_Mem
                    LDR     R1, =(Stack_Mem + Stack_Size)
                    LDR     R2, = (Heap_Mem +  Heap_Size)
                    LDR     R3, = Stack_Mem
                    BX      LR
                    ENDP
    
                    ALIGN
    
                    ENDIF
    
                    END
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    GD32F4xx_Firmware_Library\CMSIS\GD\GD32F4xx\Source\system_gd32f4xx.c
    一下是GD32标准库中包含的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
        /* Reset the RCU clock configuration to the default reset state */
        /* Set IRC16MEN bit */
        RCU_CTL |= RCU_CTL_IRC16MEN;
        while(0U == (RCU_CTL & RCU_CTL_IRC16MSTB)){
        }
        RCU_MODIFY(0x50);
        
        RCU_CFG0 &= ~RCU_CFG0_SCS;
        
        /* Reset HXTALEN, CKMEN and PLLEN bits */
        RCU_CTL &= ~(RCU_CTL_PLLEN | RCU_CTL_CKMEN | RCU_CTL_HXTALEN);
    
        /* Reset HSEBYP bit */
        RCU_CTL &= ~(RCU_CTL_HXTALBPS);
        
        /* Reset CFG0 register */
        RCU_CFG0 = 0x00000000U;
    
        /* wait until IRC16M is selected as system clock */
        while(0 != (RCU_CFG0 & RCU_SCSS_IRC16M)){
        }
    
        /* Reset PLLCFGR register */
        RCU_PLL = 0x24003010U;
    
        /* Disable all interrupts */
        RCU_INT = 0x00000000U;
             
        /* Configure the System clock source, PLL Multiplier and Divider factors, 
            AHB/APBx prescalers and Flash settings */
        system_clock_config();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    执行外SystemInit 后跳转到__main(),然后跳转到用户执行的主函数中。

  • 相关阅读:
    Vuecli项目结构,及组件的使用
    虚拟机中centos扩展根目录空间
    PreScan快速入门到精通第二十三讲2D车辆动力学模型
    java BufferedReader类、BufferedWriter类
    【java】【SpringBoot】【一】基础篇 SpringBoot工程创建和实现ssm/ssmp整合
    思科、华为、华三、锐捷网络设备巡检命令
    一文读懂在Postgresql数据库中进行窗口函数的操作
    软件测试如何进行缺陷数据分析及发现更多缺陷的方法
    Python | Leetcode Python题解之第203题移除链表元素
    企业邮箱选择指南:最适合跨境贸易的解决方案推荐
  • 原文地址:https://blog.csdn.net/denghuajing/article/details/128045438