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

STM32G474调用内部函数跳转Bootloader失败问题排查

STM32G474跳转Bootloader失败问题排查与解决

问题描述

我在STM32G431芯片上实现了一段跳转至Bootloader的函数,可成功完成跳转。系统仅启用SPI1用于进入Bootloader模式后的通信,且确保此代码不在中断中执行(通过主函数检查标志位后执行)。将这段代码移植到STM32G474后却无法生效,设备直接回到程序内存,且未到达最后的while(1)循环。请问STM32G474是否存在与STM32G431不同的特殊寄存器设置?

原测试代码

/**
 * @brief Function to reset STM32 into bootloader mode
 * @note This function will not return as it triggers a system reset
 * @note Flash start address for STM32G431: 0x08000000
 */
void jump_to_bootloader(void)
{
    #define conBootloadAddress 0x1FFF0000

    void (*SysMemBootJump)(void);


    /* 1. Disable all interrupts */
    __disable_irq();
    
    /* 2. Disable all peripheral clocks */
    HAL_SPI_DeInit(&hspi1);
    MX_GPIO_DeInit();
    
    /* 3. Disable PLL and reset to default clock */
    HAL_RCC_DeInit();  // This handles PLL disable

    
    /* 4. Clear ALL pending interrupts */
    HAL_NVIC_DisableIRQ(SPI1_IRQn);
    HAL_NVIC_ClearPendingIRQ(SPI1_IRQn);
    
    for (int i = 0; i < sizeof(NVIC->ICER) / sizeof(NVIC->ICER[0]); i++)
    {
        NVIC->ICER[i] = 0xFFFFFFFF;
        NVIC->ICPR[i] = 0xFFFFFFFF;
    }
    
    /* 5. Disable SysTick */
    SysTick->CTRL = 0;
    SysTick->LOAD = 0;
    SysTick->VAL = 0;

    /* 6. Re-enable interrupts (needed for bootloader) */
    __enable_irq();

    /* 7. Force system reset for clean bootloader entry */
    HAL_FLASH_OB_Launch();  // This triggers a system reset

    /* 8. Jump to bootloader */
    SysMemBootJump = (void (*)(void)) (*((uint32_t*) (conBootloadAddress + 4)));
    __set_MSP(*(uint32_t*) conBootloadAddress);
    SysMemBootJump();

    while (1);
}

问题分析与解决

1. 核心错误:HAL_FLASH_OB_Launch()的误用

HAL_FLASH_OB_Launch()的作用是触发选项字节加载并立即执行系统复位。如果未预先修改选项字节的启动模式为系统Bootloader,复位后芯片会默认从用户Flash启动,直接回到你的应用程序——这就是代码无法执行到后续跳转逻辑和while(1)的原因。你在STM32G431上的成功大概率是误操作导致的特殊情况,并非标准跳转流程。

2. STM32G474与G431的Bootloader差异

两者的系统Bootloader基地址均为0x1FFF0000,寄存器逻辑无本质差异,无需针对G474修改特殊寄存器配置。G474仅在Bootloader支持的通信接口数量上更多,SPI1的适配逻辑通用。

3. 修正后的跳转代码

移除HAL_FLASH_OB_Launch()调用,直接执行内存跳转逻辑,同时保留资源清理步骤:

/**
 * @brief Function to jump to STM32 system bootloader
 * @note This function will not return
 * @note Flash start address for STM32G4x: 0x08000000
 * @note System Bootloader address for STM32G474: 0x1FFF0000
 */
void jump_to_bootloader(void)
{
    #define conBootloadAddress 0x1FFF0000

    void (*SysMemBootJump)(void);

    /* 1. Disable all interrupts */
    __disable_irq();
    
    /* 2. Disable and deinitialize used peripherals */
    HAL_SPI_DeInit(&hspi1);
    MX_GPIO_DeInit();
    
    /* 3. Reset RCC to default state (disable PLL, use HSI) */
    HAL_RCC_DeInit();
    
    /* 4. Clear ALL NVIC pending and enabled interrupts */
    for (uint32_t i = 0; i < sizeof(NVIC->ICER) / sizeof(NVIC->ICER[0]); i++)
    {
        NVIC->ICER[i] = 0xFFFFFFFF;
        NVIC->ICPR[i] = 0xFFFFFFFF;
    }
    
    /* 5. Disable SysTick timer */
    SysTick->CTRL = 0;
    SysTick->LOAD = 0;
    SysTick->VAL = 0;

    /* 6. Set MSP to Bootloader's initial stack pointer */
    __set_MSP(*(uint32_t*) conBootloadAddress);
    
    /* 7. Jump to Bootloader reset handler */
    SysMemBootJump = (void (*)(void)) (*((uint32_t*) (conBootloadAddress + 4)));
    SysMemBootJump();

    /* Never reach here */
    while (1);
}

4. 额外注意事项

  • 确保代码执行在主循环上下文:通过标志位触发时,要确保无中断嵌套或挂起的中断请求。
  • 若需永久设置Bootloader启动,可修改选项字节的启动模式,但这不是临时跳转的常规方案。

内容的提问来源于stack exchange,提问作者Raynhardt Van Zyl

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 20:47:12