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

startup.s 功能

startup.s 文件定义了向量表,包含栈初始值和各个中断服务函数指针。

芯片一上电,自动设置SP,PC,然后执行复位中断:

  设置栈顶寄存器的值 --- 多余,芯片一上电自动设置了

  data段的数据从 flash 拷贝到 SRAM

  bss段位于SRAM,初始化为0

  执行 SystemInit,初始化时钟,设置SCB->VTOR的值为向量表起始地址

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

 

 

向量表

在 startup.s 内,定义了一个向量表,由链接脚本决定向量表存储在 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)的初始值
  复位中断函数
  NMI中断函数
  硬 fault 服务函数
  ......
后两者(NMI 和硬 fault )也是必需的,因为有可能在引导过程中发生这两种异常。

链接脚本把向量表放在内存首地址处,所以 0x20000D84 就是主堆栈指针的初始值,0x08059545-1就是复位向量(最低为1,表示接下来使用的是Thumb指令),指向中断服务函数 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 */
// STM32的data段需要从flash搬移到对应的sram,bss段对应的sram需要初始化为0
// data段的数据在flash中存有一份,由链接文件可知代码中使用位于data段的变量的地址都是sram地址,所以只要把数据搬移到对应的sram就可以了
// 代码中使用bss段的变量的地址都是sram地址,所以只需要把对应的sram初始化为0即可

// 由此可看出,对于BIN类型可执行文件,data段占其空间,bss段不占其空间
/* 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 ......

对于STM32,上电后固定从地址 0x0000 0004 取值赋值到 PC,该值是复位向量,所以上电从复位向量开始运行

下面两张图来自链接脚本,由 ENTRY(Reset_Handler) 可知程序从 Reset_Handler 开始运行,这个只是起到注释的作用,因为可执行文件用的是BIN文件,不是ELF。

Reset_Handler 第一条语句就是对 SP 进行初始化,初始化值是 _estack,这个也不需要,因为芯片上电自动设置了

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

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 RCC clock configuration to the default reset state ------------*/
  /* Set HSION bit */
  RCC->CR |= (uint32_t)0x00000001;

  /* Reset CFGR register */
  RCC->CFGR = 0x00000000;

  /* Reset HSEON, CSSON and PLLON bits */
  RCC->CR &= (uint32_t)0xFEF6FFFF;

  /* Reset PLLCFGR register */
  RCC->PLLCFGR = 0x24003010;

  /* Reset HSEBYP bit */
  RCC->CR &= (uint32_t)0xFFFBFFFF;

  /* Disable all interrupts */
  RCC->CIR = 0x00000000;

#if defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM)
  SystemInit_ExtMemCtl(); 
#endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */

  /* Configure the Vector Table location add offset address ------------------*/
#ifdef VECT_TAB_SRAM
  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
#else
  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
#endif
}

  

 

posted @ 2021-06-10 14:20  流水灯  阅读(1430)  评论(0编辑  收藏  举报