• STM32 CM3/CM4 ------ startup.s 文件分析 ------ GCC RT-Thread Studio 版本


    startup.s 功能

    * This module performs:
    * - Set the initial SP
    * - Set the initial PC == Reset_Handler,
    * - Set the vector table entries with the exceptions ISR address
    * - Branches to main in the C library (which eventually
    * calls main()).
    * After Reset the Cortex-M4 processor is in Thread mode,
    * priority is Privileged, and the Stack is set to Main.

    函数 Reset_Handler 内调用函数 entry(),entry() 函数添加一些我们要在 main() 函数之前执行的代码,entry() 函数的最后调用 main()。

    向量表

    在 startup.s 内,定义了一个向量表,由链接脚本决定向量表存储在哪里,对于STM32,就是 flash 的起始地址 0x08000000,向量指向的位置就是对应的中断服务函数

    MEMORY
    {
        ROM (rx) : ORIGIN = 0x08000000, LENGTH =  1024k /* 1024K flash */
        RAM (rw) : ORIGIN = 0x20000000, LENGTH =  128k /* 128K sram */
    }
    
    SECTIONS
    {
        .text :
        {
            . = ALIGN(4);
            _stext = .;
            KEEP(*(.isr_vector))            /* Startup code */
    
            . = ALIGN(4);
            *(.text)                        /* remaining code */
            *(.text.*)                      /* remaining code */
    
            _etext = .;
        } > ROM = 0
    
    ......
    }

    由上可知,变量 _stext 为空,不占用地址,所以首地址存的是中断向量表 isr_vector 

    向量表的起始处都必须包含以下向量:
      主堆栈指针(MSP)的初始值
      复位向量(根据CM3权威指南,复位向量是PC初始值,也就是说程序是从中断服务函数 Reset_Handler 开始运行的
      NMI
      硬 fault 服务例程
    后两者也是必需的,因为有可能在引导过程中发生这两种异常。

    所以 0x20000D84 就是主堆栈指针的初始值,0x08059545-1就是复位向量,指向中断服务函数 Reset_Handler 

     可以看 rtthread.map 得到验证

    startup.s 文件内容

     以下是 GCC RT-Thread 版本的 startup.s

        .section  .text.Reset_Handler
      .weak  Reset_Handler
      .type  Reset_Handler, %function
    Reset_Handler:  
      ldr   sp, =_estack     /* set stack pointer */
    
    /* Copy the data segment initializers from flash to SRAM */  
      movs  r1, #0
      b  LoopCopyDataInit
    
    CopyDataInit:
      ldr  r3, =_sidata
      ldr  r3, [r3, r1]
      str  r3, [r0, r1]
      adds  r1, r1, #4
        
    LoopCopyDataInit:
      ldr  r0, =_sdata
      ldr  r3, =_edata
      adds  r2, r0, r1
      cmp  r2, r3
      bcc  CopyDataInit
      ldr  r2, =_sbss
      b  LoopFillZerobss
    /* Zero fill the bss segment. */  
    FillZerobss:
      movs  r3, #0
      str  r3, [r2], #4
        
    LoopFillZerobss:
      ldr  r3, = _ebss
      cmp  r2, r3
      bcc  FillZerobss
    
    /* Call the clock system intitialization function.*/
      bl  SystemInit   
    /* Call static constructors */
        /* bl __libc_init_array */
    /* Call the application's entry point.*/
      bl  entry
      bx  lr    
    .size  Reset_Handler, .-Reset_Handler
    
    /**
     * @brief  This is the code that gets called when the processor receives an 
     *         unexpected interrupt.  This simply enters an infinite loop, preserving
     *         the system state for examination by a debugger.
     * @param  None     
     * @retval None       
    */
        .section  .text.Default_Handler,"ax",%progbits
    Default_Handler:
    Infinite_Loop:
      b  Infinite_Loop
      .size  Default_Handler, .-Default_Handler
    /******************************************************************************
    *
    * The minimal vector table for a Cortex M3. Note that the proper constructs
    * must be placed on this to ensure that it ends up at physical address
    * 0x0000.0000.
    * 
    *******************************************************************************/
       .section  .isr_vector,"a",%progbits
      .type  g_pfnVectors, %object
      .size  g_pfnVectors, .-g_pfnVectors
        
        
    g_pfnVectors:
      .word  _estack
      .word  Reset_Handler
      .word  NMI_Handler
      .word  HardFault_Handler
      .word  MemManage_Handler
      .word  BusFault_Handler
      .word  UsageFault_Handler
      .word  0
      .word  0
      .word  0
      .word  0
      .word  SVC_Handler
      .word  DebugMon_Handler
      .word  0
      .word  PendSV_Handler
      .word  SysTick_Handler
      
      /* External Interrupts */
      .word     WWDG_IRQHandler                   /* Window WatchDog              */                                        
      .word     PVD_IRQHandler                    /* PVD through EXTI Line detection */                        
      .word     TAMP_STAMP_IRQHandler             /* Tamper and TimeStamps through the EXTI line */            
      .word     RTC_WKUP_IRQHandler               /* RTC Wakeup through the EXTI line */                      
      .word     FLASH_IRQHandler                  /* FLASH                        */                                          
      .word     RCC_IRQHandler                    /* RCC                          */                                            
      .word     EXTI0_IRQHandler                  /* EXTI Line0                   */                        
      .word     EXTI1_IRQHandler                  /* EXTI Line1                   */                          
      .word     EXTI2_IRQHandler                  /* EXTI Line2                   */                          
      .word     EXTI3_IRQHandler                  /* EXTI Line3                   */                          
    ......
                             
                             
    /*******************************************************************************
    *
    * Provide weak aliases for each Exception handler to the Default_Handler. 
    * As they are weak aliases, any function with the same name will override 
    * this definition.
    * 
    *******************************************************************************/
       .weak      NMI_Handler
       .thumb_set NMI_Handler,Default_Handler
      
       .weak      HardFault_Handler
       .thumb_set HardFault_Handler,Default_Handler
      
       .weak      MemManage_Handler
       .thumb_set MemManage_Handler,Default_Handler
      
       .weak      BusFault_Handler
       .thumb_set BusFault_Handler,Default_Handler
    
       .weak      UsageFault_Handler
       .thumb_set UsageFault_Handler,Default_Handler
    
    ......

    下面两张图来自链接脚本,由 ENTRY(Reset_Handler) 可知程序从 Reset_Handler 开始运行,第一条语句就是对 SP 进行初始化,初始化值是 _estack

    不同于 IAR 版本,这个版本除了中断服务函数 Reset_Handler 外,其他中断服务函数都是调用函数 Default_Handler,Default_Handler是一个死循环。功能上和 IAR 版本一样都是死循环。

  • 相关阅读:
    (补充)移除动态添加的控件
    (非技术)遇见讨饭者的思考
    datalist或datagrid的数据源是数组的时候怎么写绑定?
    (原创)一步一步学Remoting之二:激活模式
    一步一步学Remoting系列文章
    如何向某网址Post信息,并得到CookieContainer以便以后直接通过验证(续)
    (原创)一步一步学Remoting之六:事件(2)
    (原创)一步一步学Remoting之五:异步操作
    【收藏】根据拼音首字母筛选人名
    (原创)一步一步学Remoting之四:承载方式(1)
  • 原文地址:https://www.cnblogs.com/god-of-death/p/14870876.html
Copyright © 2020-2023  润新知