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

这篇博客详细解析了STM32的启动过程,包括堆栈和堆的分配,以及中断向量表的设置。它介绍了汇编语言中的关键指令如EQU、AREA、DCD等,并阐述了中断处理函数的默认实现。此外,还提到了SystemInit函数在初始化系统时钟配置中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

起始和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

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

同理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)

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

一样的做法申请一块区域 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

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

__Vectors_Size  EQU     __Vectors_End - __Vectors

接着是 申请一块空间

 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

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\

上面的意思是定义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]      

最后初始化堆栈

                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

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();
}

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值