单片机
返回首页

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

2025-09-12 来源:cnblogs

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

}


进入单片机查看更多内容>>
相关视频
  • 【TI MSPM0 应用实战】智能小车+工业角度编码器+血氧仪+烟雾探测器!硬核参考设计详解!

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

  • 直播回放: Microchip Timberwolf™ 音频处理器在线研讨会

  • 基于灵动MM32W0系列MCU的指夹血氧仪控制及OTA升级应用方案分享

精选电路图
  • 1瓦线性调频增强器

  • 12V 转 28V DC-DC 变换器(基于 LM2585)

  • 红外遥控音量控制

  • LM317过压保护

  • 12V转110V/220V 500W逆变器

  • DS1669数字电位器

    相关电子头条文章