STM32
直播中

刘桂兰

8年用户 1047经验值
私信 关注
[问答]

IAP升级跳转APP跳转Boot失败了怎么解决?

使用的MCU是STM32U535RC ,V6 编译器

跳转实现的功能如下


  • /**
  • *@brief  直接跳转到 Boot 程序
  • */
  • void LibJumpToBoot(UINT32 BootAddr)
  • {
  •     static UINT32 JumpBootAddr = 0, sJumpToBootAddr = 0;

  •     JumpBootAddr = BootAddr;

  •     UINT32 CheckRamAddr = *(volatile UINT32*)(JumpBootAddr);

  •     DEBUG("Check Ram Addr [0x%X], Flash Boot Addr [0x%X] rn", CheckRamAddr, JumpBootAddr);

  •     MCU_DelayUnitms(200);

  •     if ((CheckRamAddr & 0x2FF00000) == 0x20000000)
  •     {
  •         sJumpToBootAddr = *(volatile UINT32*)(JumpBootAddr + 4);

  •         __disable_irq();

  •         __HAL_RCC_APB1_FORCE_RESET();
  •         __HAL_RCC_APB1_RELEASE_RESET();


  •         for (UINT8 i = 0;i < 8;i++)//适用于中断编号是16~255
  •         {
  •             NVIC->ICER = 0xFFFFFFFF;
  •             NVIC->ICPR = 0xFFFFFFFF;
  •         }

  •         SysTick->CTRL = 0x00;

  •         SCB->VTOR = 0x08000000;

  •         __set_CONTROL(0);

  •         __set_PSP(*(volatile UINT32*)JumpBootAddr);
  •         __set_MSP(*(volatile UINT32*)JumpBootAddr);


  •         ((void (*)(void))sJumpToBootAddr)();

  •         MCU_EnableIrq();

  •         while (1);
  •     }
  •     else
  •     {
  •         DEBUG_ERR("Check Jump Boot Addr[0x%X] ! rn", CheckRamAddr);
  •     }
  • }




这段代码在项目Keil工程中能够实现跳转,但是把这段代码由keil编成的lib, 项目工程中再使用此lib ,调用lib的接口函数却卡死,
项目工程和lib工程均没有开优化(-O0)



回帖(1)

小镇故事多

2025-7-24 18:28:48

针对IAP升级跳转Boot失败的问题,以下是详细的分析和解决方案:


主要原因分析:




  1. 堆栈指针检查错误



    • 原始代码使用 (CheckRamAddr & 0x2FFE0000) == 0x20000000 检查堆栈地址,但在STM32U5中RAM地址范围为 0x2000_0000-0x3004_0000,该掩码会错误地排除高地址区域(如0x30000000)。




  2. 外设状态未重置



    • 未复位关键外设(如DMA、定时器),可能导致跳转后外设状态冲突。

    • SysTick未完全复位(缺少VAL和LOAD清零)。




  3. 缓存处理不足



    • STM32U5自带Cache,跳转前需清理数据缓存并失效指令缓存。




  4. 中断未彻底关闭



    • 仅清除了中断使能和挂起位,未重置中断优先级分组。




  5. 函数指针转换方式不安全



    • 直接类型转换可能存在对齐问题(Cortex-M33要求函数指针地址最低位为1)。






完整修复代码:


#include "stm32u5xx.h"

void LibJumpToBoot(uint32_t BootAddr) {
    // 1. 精确检查堆栈指针范围(STM32U5 RAM地址范围)
    volatile uint32_t sp = *(volatile uint32_t*)BootAddr;
    if(sp < 0x20000000 || sp >= 0x30040000) {
        DEBUG("Invalid SP: 0x%08Xrn", sp);
        return; // 避免继续跳转
    }

    // 2. 获取复位处理函数地址(必须检查奇地址对齐)
    volatile uint32_t reset_vector = *(volatile uint32_t*)(BootAddr + 4);
    if((reset_vector & 1) == 0) { // Cortex-M33要求最低位为1
        DEBUG("Invalid Reset Vector: 0x%08Xrn", reset_vector);
        return;
    }
    void (*boot_entry)(void) = (void (*)(void))reset_vector;

    // 3. 彻底关闭所有外设和中断
    __disable_irq();

    // 关闭SysTick(完整复位)
    SysTick->CTRL = 0;
    SysTick->VAL = 0;
    SysTick->LOAD = 0;

    // 清空所有中断
    for(int i = 0; i < 8; i++) {
        NVIC->ICER[i] = 0xFFFFFFFF;    // 禁止中断
        NVIC->ICPR[i] = 0xFFFFFFFF;    // 清除挂起
    }
    NVIC_DisableIRQ(SysTick_IRQn);     // 补充SysTick中断禁用

    // 4. 重置关键外设(防止状态冲突)
    __HAL_RCC_AHB3_FORCE_RESET();
    __HAL_RCC_AHB3_RELEASE_RESET();
    // 根据实际使用添加其他外设复位(如DMA、USART等)

    // 5. 缓存操作(STM32U5专属)
    SCB_CleanDCache();                 // 清理数据缓存
    SCB_InvalidateICache();            // 失效指令缓存
    __DSB();                           // 数据同步屏障
    __ISB();                           // 指令同步屏障

    // 6. 设置堆栈指针并跳转
    __set_MSP(sp);                     // 设置主堆栈
    SCB->VTOR = BootAddr;              // 强制重定位向量表
    boot_entry();                      // 跳转执行

    while(1); // 确保不会返回
}

关键修复点详解:




  1. 堆栈指针检查



    • 使用精确的地址范围 0x20000000-0x3003FFFF(STM32U5实际RAM空间)

    • 替代原来有缺陷的掩码检查




  2. 复位函数地址处理



    • 验证地址最低位为1(表示Thumb状态)

    • 更安全的函数指针转换:(void (*)(void))((uint32_t)reset_vector)




  3. 外设复位增强



    • 添加DMA/USART等外设复位(根据实际使用)

    • 示例:__HAL_RCC_AHB2_FORCE_RESET()(复位GPIO、ADC等)




  4. 中断彻底处理



    • 补充 NVIC_DisableIRQ(SysTick_IRQn)

    • 重置优先级分组:NVIC_SetPriorityGrouping(0)




  5. 缓存处理(STM32U5必需)



    • SCB_CleanDCache():保证数据一致性

    • SCB_InvalidateICache():防止执行旧指令

    • 双屏障 __DSB()/__ISB():确保操作完成




  6. 向量表重定位



    • SCB->VTOR = BootAddr:强制内核使用新向量表






BootLoader侧的配合要求:


在BootLoader的启动文件中(如startup_stm32u535xx.s),需确保:



  1. 第一行为堆栈指针地址

  2. 第二行为 Reset_Handler 地址

  3. 在main函数初始化前设置VTOR:
    // system_stm32u5xx.c中
    void SystemInit(void) {
       SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;
       // ...
    }


调试建议:



  1. 在跳转前打印关键值:
    DEBUG("SP: 0x%08X, Reset: 0x%08Xrn", sp, reset_vector);

  2. 用J-Link查看BootLoader区的汇编:

    • 检查 BootAddr 处是否为合法向量表

    • 确保 Reset_Handler 地址有效



通过以上修改,可解决STM32U5的IAP跳转Boot失败问题,关键点在于精确地址检查、缓存操作、外设重置和向量表重定向

举报

更多回帖

×
20
完善资料,
赚取积分