You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

STM32L151无法将数据段从Flash复制到SRAM,陷入启动循环求助

STM32固件启动循环排查求助

我们在某一特定版本固件中遇到异常:设备启动时SRAM未按预期填充数据(该操作应在Reset_Handler入口函数中执行),随后每3.2ms触发一次复位,陷入启动循环。

  • 通过编译生成的.map文件确认,SRAM起始地址应存在指定变量,但实际未检测到对应数据;旧版可正常运行的固件则能正常加载该数据。
  • 诡异的是,使用STM32CubeIDE加载调试时设备运行正常,但通过ST-Link Utility或串口烧录后,设备自主启动就会出现相同故障,无法获取有效调试信息。
  • 使用STM32CubeProgrammer观察发现,程序计数器停留在地址0x20000000,无法单步调试。

链接脚本片段

/* Entry Point */
ENTRY(Reset_Handler)

...

MEMORY
{
  BOT_FLASH (rx)       : ORIGIN = 0x08000000, LENGTH = 0x6000   /* 24 kB */
  PSB_FLASH (rx)       : ORIGIN = 0x08006000, LENGTH = 0x8000   /* 32 kB */
  FLASH (rx)           : ORIGIN = 0x0800E000, LENGTH = 0x72000  /* 456 kB */
  
  SHARED_DATA (r)      : ORIGIN = 0x08080000, LENGTH = 0x200     /* 2 x 256 bytes in EEPROM */
  SHARED_DATA_END (r)  : ORIGIN = 0x08080200, LENGTH = 0x1       /* end marker */
  RAM (xrw)            : ORIGIN = 0x20000000, LENGTH = 0x13ED0
  RAM_SHARED (rw)      : ORIGIN = 0x20013ED0, LENGTH = 0x20
  PERSISTENT_RAM(xrw)  : ORIGIN = 0x20013EF0, LENGTH = 0x110
  MEMORY_B1 (rx)       : ORIGIN = 0x60000000, LENGTH = 0K
}

...

SECTIONS {

 .aBunchOfSectionsInFlash: {
    ...
 } >FLASH

   ...

   _sidata = .;

  /* Initialized data sections goes into RAM, load LMA copy after code */
  .data : 
  {
    . = ALIGN(4);
    _sdata = .;        /* create a global symbol at data start */
    *(.data)           /* .data sections */
    *(.data*)          /* .data* sections */
    *(.RamFunc)        /* .RamFunc sections */

    . = ALIGN(4);
    _edata = .;        /* define a global symbol at data end */
  } >RAM AT>FLASH

...

}

.map文件片段

Memory Configuration

Name             Origin             Length             Attributes
BOT_FLASH        0x08000000         0x00006000         xr
PSB_FLASH        0x08006000         0x00008000         xr
FLASH            0x0800e000         0x00072000         xr
SHARED_DATA      0x08080000         0x00000200         r
SHARED_DATA_END  0x08080200         0x00000001         r
RAM              0x20000000         0x00013ed0         xrw
RAM_SHARED       0x20013ed0         0x00000020         rw
PERSISTENT_RAM   0x20013ef0         0x00000110         xrw
MEMORY_B1        0x60000000         0x00000000         xr
*default*        0x00000000         0xffffffff

...
                0x080762e4                _sidata = .


.data           0x20000000     0x1380 load address 0x080762e4
                0x20000000                . = ALIGN (0x4)
                0x20000000                _sdata = .

...

                0x20001380                _edata = .

Reset_Handler代码

/**
 * @brief  This is the code that gets called when the processor first
 *          starts execution following a reset event. Only the absolutely
 *          necessary set is performed, after which the application
 *          supplied main() routine is called.
 * @param  None
 * @retval : None
*/
    .section  .text.Reset_Handler
  .weak  Reset_Handler
  .type  Reset_Handler, %function
Reset_Handler:

    /* Setup C - environment, initialise data */
    bl SetupCSys

    /* Low level HW initialization */
    bl  SystemInit

    /* Call */
    bl  main
    bx  lr
.size  Reset_Handler, .-Reset_Handler

/* Provide weak alias for SetupCSys.
 * This will only be called if another definition is not supplied.
*/
.weak      SetupCSys
.thumb_set SetupCSys,Default_SetupCSys

    .section  .text.Default_SetupCSys,"ax",%progbits
  .type Default_SetupCSys, %function
Default_SetupCSys:
    /* 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

FillZerobss:    /* Zero fill the bss segment. */
    movs  r3, #0
    str  r3, [r2], #4

LoopFillZerobss:
    ldr  r3, = _ebss
    cmp  r2, r3
    bcc  FillZerobss

排查建议

  1. 检查烧录完整性:用STM32CubeProgrammer对比烧录后的FLASH内容与编译生成的.bin/.hex文件,确认_sidata对应的0x080762e4地址开始的.data段数据是否完全一致,排除烧录过程中数据丢失或校验错误。
  2. 验证时钟配置差异:CubeIDE调试时会自动配置时钟,而自主启动依赖SystemInit的时钟设置。对比旧版与新版固件的SystemInit代码,重点检查AHB/APB总线时钟、FLASH等待周期(LATENCY)配置,若FLASH访问时钟超过芯片规格,会导致读取_sidata时出错,进而.data段复制失败。
  3. 检查Reset_Handler执行流程:在Default_SetupCSys开头添加GPIO翻转操作(用硬件引脚观测),确认自主启动时该函数是否被执行。若未执行,检查向量表是否正确映射——自主启动时向量表默认在FLASH起始地址,若新版固件修改了向量表偏移(如SCB->VTOR)但未在复位后及时设置,会导致Reset_Handler未正确执行。
  4. 排查RAM访问冲突:检查新版固件中是否有初始化代码在SetupCSys之前操作RAM(比如某些外设DMA提前启动),覆盖了刚复制的.data段数据;或者PERSISTENT_RAM等区域的配置是否影响了RAM起始地址的访问权限。
  5. 编译选项对比:对比新旧版固件的编译器优化等级、链接选项,重点检查是否开启了-fdata-sections/-ffunction-sections等可能影响段分配的选项,确认链接脚本中_sidata、_sdata等符号的定义未被意外修改。
  6. 硬件复位原因分析:3.2ms的固定复位周期,可能是看门狗触发。检查新版固件中独立看门狗(IWDG)或窗口看门狗(WWDG)的初始化时机,若在.data段未完成复制就开启看门狗,会因变量未初始化导致看门狗喂狗不及时触发复位;同时检查复位状态寄存器(RCC->CSR),确认复位来源是看门狗、硬件复位还是其他原因。

内容的提问来源于stack exchange,提问作者kruml

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 18:33:25