RT-Thread论坛
直播中

李继明

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

qboot跳转app后卡在app的系统调用处,为什么?

首先是boot工程的配置:



然后是app工程的配置:



注:boot和app工程中,fal配置内部flash的地址和大小都和对应的#define ROM_START              、#define ROM_SIZE保持一致
现象:
如果boot的跳转函数如下,qboot会一直重启

  • void qbt_jump_to_app(void)
  • {
  •     typedef void (*app_func_t)(void);
  •     u32 app_addr = QBOOT_APP_ADDR;
  •     u32 stk_addr = *((__IO uint32_t *)app_addr);
  •     app_func_t app_func = (app_func_t)(*((__IO uint32_t *)(app_addr + 4)));

  •     if ((((u32)app_func & 0xff000000) != 0x08000000) || (((stk_addr & 0x2ff00000) != 0x20000000) && ((stk_addr & 0x2ff00000) != 0x24000000)))
  •     {
  •         LOG_E("No legitimate application.");
  •         return;
  •     }

  •     rt_kprintf("Jump to application running ... n");
  •     rt_thread_mdelay(200);

  •     __disable_irq();
  •     HAL_DeInit();

  •     for(int i=0; i<128; i++)
  •     {
  •         HAL_NVIC_DisableIRQ(i);
  •         HAL_NVIC_ClearPendingIRQ(i);
  •     }

  •     SysTick->CTRL = 0;
  •     SysTick->LOAD = 0;
  •     SysTick->VAL = 0;

  •     HAL_RCC_DeInit();

  •     __set_CONTROL(0);
  •     __set_MSP(stk_addr);

  •     app_func();//Jump to application running

  •     LOG_E("Qboot jump to application fail.");
  • }



当我把HAL_DeInit();注释掉,其他不变,现象如下图

这是我app中注释的代码段

  • void rt_application_init(void)
  • {
  •     rt_thread_t tid;

  • #ifdef RT_USING_HEAP
  •     tid = rt_thread_create("main", main_thread_entry, RT_NULL,
  •                            RT_MAIN_THREAD_STACK_SIZE, RT_MAIN_THREAD_PRIORITY, 20);
  •     RT_ASSERT(tid != RT_NULL);
  • #else
  •     rt_err_t result;

  •     tid = &main_thread;
  •     result = rt_thread_init(tid, "main", main_thread_entry, RT_NULL,
  •                             main_stack, sizeof(main_stack), RT_MAIN_THREAD_PRIORITY, 20);
  •     RT_ASSERT(result == RT_EOK);

  •     /* if not define RT_USING_HEAP, using to eliminate the warning */
  •     (void)result;
  • #endif

  •     rt_thread_startup(tid);
  • }

  • int rtthread_startup(void)
  • {
  •     rt_hw_interrupt_disable();

  •     /* board level initialization
  •      * NOTE: please initialize heap inside board initialization.
  •      */
  •     rt_hw_board_init();

  •     /* show RT-Thread version */
  •     rt_show_version();

  •     /* timer system initialization */
  •     rt_system_timer_init();

  •     /* scheduler system initialization */
  •     rt_system_scheduler_init();

  • #ifdef RT_USING_SIGNALS
  •     /* signal system initialization */
  •     rt_system_signal_init();
  • #endif

  •     /* create init_thread */
  •     rt_application_init();

  •     /* timer thread initialization */
  •     rt_system_timer_thread_init();

  •     /* idle thread initialization */
  •     rt_thread_idle_init();
  •     rt_kprintf("rt_thread_idle_init finshedn");
  • #ifdef RT_USING_SMP
  •     rt_hw_spin_lock(&_cpus_lock);
  • #endif /*RT_USING_SMP*/
  •     /* start scheduler */
  •     rt_system_scheduler_start();
  •     rt_kprintf("rt_system_scheduler_start finshedn");
  •     /* never reach here */
  •     return 0;
  • }




回帖(1)

乐骞添

2025-10-20 17:03:21

根据您描述的现象和配置,qBoot跳转后卡在App系统调用处或不断重启,通常由以下原因导致:


关键原因分析




  1. 中断向量表未重定位



    • 问题本质:Bootloader跳转后App未设置正确的VTOR寄存器,导致中断仍指向Bootloader区域

    • 解决方法
      // 在App的main.c开头添加(需在启用中断前执行)
      SCB->VTOR = FLASH_BASE | 0x10000; // 与QBOOT_APP_ADDR对齐




  2. 跳转前未完全复位外设



    • 关键缺失

      • 中断未完全禁用(NVIC未复位)

      • 外设寄存器残留状态



    • 改进的跳转函数


      void qbt_jump_to_app(void) {
      typedef void (*app_func_t)(void);
      uint32_t app_addr = QBOOT_APP_ADDR;
      uint32_t stk_addr = *((volatile uint32_t*)app_addr);
      app_func_t app_func = (app_func_t)(*((volatile uint32_t*)(app_addr + 4)));

      // 关键复位序列
      __disable_irq();
      SysTick->CTRL = 0;
      HAL_RCC_DeInit();
      HAL_DeInit();

      // 禁用所有中断
      for (int i = 0; i < 8; i++) {
           NVIC->ICER[i] = 0xFFFFFFFF;  // 禁用中断
           NVIC->ICPR[i] = 0xFFFFFFFF;  // 清除挂起标志
      }

      // 设置寄存器回到复位状态
      __set_CONTROL(0);
      __set_MSP(stk_addr); // 主堆栈指针重置
      __DSB();
      __ISB();

      // 直接跳转(不使用函数调用避免堆栈问题)
      asm volatile (
           "BX %0"
           :
           : "r" (app_func)
      );
      }





  3. 内存分区冲突



    • 检查要点

      • Bootloader结束地址ROM_START + ROM_SIZEQBOOT_APP_ADDR

      • App链接脚本:确保IROM1起始地址 = QBOOT_APP_ADDR

      • 中断向量偏移:App中SystemInit()需包含SCB->VTOR设置





  4. 堆栈指针验证



    • 调试建议:在跳转前检查获取的栈顶地址
      printf("[Boot] App Stack Top: 0x%08Xn", stk_addr);
      printf("[Boot] App Entry Point: 0x%08Xn", app_func);


      • 栈顶地址应在RAM范围内(如0x20000000~0x20020000)

      • 入口地址应在App的Flash区域内





  5. 时钟配置冲突



    • 现象:Boot中启用PLL,App未重新配置时钟

    • 解决方案

      • App启动时调用SystemClock_Config()重新初始化时钟

      • 或Boot跳转前降频回HSI:
        HAL_RCC_DeInit();
        __HAL_RCC_HSI_ENABLE();  // 切回内部时钟





验证流程图


graph TD
    A[Bootloader运行] --> B{检查配置}
    B --> C[ROM分区是否正确?]
    B --> D[VTOR地址对齐?]
    B --> E[外设完全复位?]
    C -->|错误| F[修正链接脚本]
    D -->|未设置| G[App中添加SCB->VTOR]
    E -->|残留状态| H[增强跳转函数]
    F --> I[重新编译]
    G --> I
    H --> I
    I --> J[烧录测试]
    J -->|成功| K[正常进入App]
    J -->|失败| L[调试内存映射]

补充建议




  1. 调试手段



    • 在App的Reset_Handler入口放置断点

    • 检查R0-R4寄存器值(应不为0)

    • 查看SCB->VTOR寄存器值






























  2. 常见错误地址示例 配置项 典型错误值 正确示例
    QBOOT_APP_ADDR 0x08000000 0x08010000
    App VTOR 未设置 0x08010000
    FLASH SIZE 与芯片实际不符 512K/1024K



  3. 启动文件检查



    • 确认App的startup_stm32xxx.s中堆栈大小足够(至少1KB)

    • 确保Reset_Handler调用SystemInit




通过以上步骤,90%以上的跳转失败问题可解决。重点排查中断向量表重定位和外设复位两个核心环节。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分