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

STM32F405RGT6 Bootloader跳转后卡死问题排查求助

问题

使用STM32F405RGT6芯片,Bootloader跳转函数如下:

static void Boot_Jump_To_App(uint32_t app_addr)
{
  uint32_t app_msp = *((uint32_t *)app_addr);
  uint32_t app_reset = *((uint32_t *)(app_addr + 4U));
  BootEntry_t app_entry = (BootEntry_t)app_reset;

  /* Stop SysTick used by bootloader */
  SysTick->CTRL = 0U;
  SysTick->LOAD = 0U;
  SysTick->VAL  = 0U;
  SCB->ICSR =
    SCB_ICSR_PENDSVCLR_Msk |
    SCB_ICSR_PENDSTCLR_Msk |
    SCB_ICSR_PENDSVCLR_Msk;
  /* Disable and clear all NVIC IRQs to avoid pending bootloader interrupts */
  for (uint32_t i = 0; i < 8U; i++) {
    NVIC->ICER[i] = 0xFFFFFFFFU;
    NVIC->ICPR[i] = 0xFFFFFFFFU;
  }

  /* Optional but often helpful for clean handoff */
  HAL_RCC_DeInit();
  HAL_DeInit();

  __disable_irq();
  /* Point vector table to application */
  SCB->VTOR = app_addr;
  __DSB();
  __ISB();

  /* Load app stack and branch */
  __set_MSP(app_msp);
  __DSB();
  __ISB();
  
  /* Keep IRQs disabled here; app startup will enable when ready */
  //app_entry();
  __ASM volatile ("bx %0" : : "r"(app_entry));
    
    while(1);
}

为调试目的,将跳转目标设为Bootloader自身(app_addr = 0x08000000)。通过CMSIS-DAP调试发现app_msp、SP、app_reset、app_entry均正常。在__ASM volatile ("bx %0" : : "r"(app_entry));处设断点可正常暂停,但点击运行后无响应,停止调试后发现停在Disassembly的MemManage_Handler,Stack+local显示为HardFault_Handler。

reset_handler地址为0x0800019D,与0x8000004地址的内容一致,Bootloader的.map文件显示0x0800019c属于startup_stm32f405xx.o(.text)段。程序在卡死前未进入systeminit(),使用Keil5搭配ARM编译器,Bootloader仅使用UART外设实现printf串口输出,请问该如何调试此问题?

调试建议

  • 检查栈指针合法性:虽然app_msp读取正常,但跳转后栈可能被破坏。在__set_MSP(app_msp)后,直接查看SP寄存器值是否等于app_msp,同时确认0x08000000处的栈顶地址是否在芯片合法RAM范围内(STM32F405的RAM起始为0x20000000,大小192KB,栈顶需落在这个区间)。
  • 排查HAL初始化残留问题:HAL_RCC_DeInit()和HAL_DeInit()可能没有完全复位所有外设状态。尝试注释这两个函数,直接跳转测试,看是否还会触发HardFault。如果注释后正常,说明DeInit过程中某个外设寄存器操作导致了异常。
  • 验证VTOR设置有效性:在SCB->VTOR = app_addr后,读取SCB->VTOR寄存器确认值是否正确。另外,STM32F4的VTOR需要设置为向量表起始地址,且必须对齐到0x200的倍数(0x08000000符合要求),但要确保芯片的FLASH访问权限没有被错误配置。
  • 检查跳转指令的状态:bx指令要求目标地址的最低位为1(表示Thumb模式),app_reset是0x0800019D,最低位为1,符合Thumb模式要求,但可以在汇编窗口确认跳转时的PSR寄存器的T位是否为1,确保处于Thumb状态。
  • 启用HardFault调试机制:在Bootloader中添加HardFault异常捕获函数,保存SCB->CFSR、SCB->HFSR等寄存器的值,通过串口打印出来。这些寄存器可以明确是内存管理错误(MemManage)还是总线错误,定位具体异常原因。示例代码:
void HardFault_Handler(void)
{
    uint32_t cfsr = SCB->CFSR;
    uint32_t hfsr = SCB->HFSR;
    printf("HardFault! CFSR: 0x%08X, HFSR: 0x%08X\r\n", cfsr, hfsr);
    while(1);
}
  • 检查编译器优化和链接配置:Keil中如果开启了过高的优化等级,可能导致跳转代码被错误优化。尝试将跳转函数的优化等级设为-O0(无优化),同时检查链接脚本中向量表的配置是否正确,确保0x08000000处确实是向量表起始。
  • 模拟冷启动流程:跳转回自身时,相当于二次启动,而Bootloader的初始化代码可能没有处理二次初始化的情况。比如某些全局变量已经被初始化过,二次执行startup_stm32f405xx.s中的初始化代码时,可能出现内存覆盖问题。可以在跳转前手动重置所有全局变量到初始值,或者修改启动代码,允许重复初始化。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 11:36:08