侧边栏壁纸
博主头像
xiaoming 博主等级

累死自己,卷死别人,为了小刘而努力!!!

  • 累计撰写 37 篇文章
  • 累计创建 7 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

STM32执行IAP升级后不能进中断

Administrator
2025-06-19 / 0 评论 / 0 点赞 / 10 阅读 / 0 字 / 正在检测是否收录...

场景

基于 STM32IAP升级测试

问题现象

Boot层跳转后,APP出现卡死,并进入到 HardFault

调试过程

  1. 调用了 HAL_Delay就会出现上述现象,不调用则不会卡死,怀疑是中断没打开,在 main前面添加了 __enable_irq(),现象一样(解释:其实不调用也会卡死,只是测试过程中只留意了 while(1)前的部分代码,并且这段代码很短,执行结束 SysTick都没有触发中断,在 while(1)前调用 HAL_Delay其实是加长了代码执行时间,从而导致卡死现象提前发生)
  2. 由于目前的 boot层使用的时基是 sysTick,而 App层使用的时基是 TIM1,理论上应该是没有关系的,但是还是把时基换成一致试试
  3. 先将 boot层和 App层的时基都设置为 TIM1,发现 App正常(解释:boot层未使用 SysTick,并未开启 SysTick中断,在 APP层,有无中断服务函数都不受影响)
  4. 先将 boot层和 App层的时基都设置为 SysTick,发现 App又出现卡死现象(解释:由于 boot层打开了 SysTick中断,并未关闭,导致在跳转到 APP层后,一旦出发 SysTick中断就会卡死)
  5. 经调试,猜测是 SysTick配置有问题
  6. 经检查,发现 App中竟然没有 SysTick的中断服务函数,回过头去找 CubeMX,果然没有勾选 Generate IRQ Handler

在这里插入图片描述

  1. 勾选后,App正常(这里没有勾选的原因是,在做 IAP之前,系统是上了 FreeRTOS的,但是再调试过程中发现 IAP功能没实现,于是就将 FreeRTOS去掉,只跑裸机,所以这里就有了一个隐患)
  2. 此前,都是基于裸机的调试
  3. 现在在 App中加入了 FreeRTOS,并使用 FreeRTOS内部实现的 SysTick中断服务函数后,又出现上述现象(解释:在启用调度器之前,boot层开启了 SysTick中断,并没有关闭)
  4. 更改 App中断向量表,单独烧录到 MCU中,App能正常运行
  5. 然后恢复到第 9步的状态,再次调试发现,AppFreeRTOSxPortSysTickHandler()->xTaskIncrementTick->xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xStateListItem ) );卡死,并且查看内存发现这里的变量的值有些奇怪,并且指针不在 RAM访问范围 0x20000000-0x20010000内:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  1. 结合 FreeRTOS的源码,发现 pxDelayedTaskList只有在启动任务调度器,进入到 prvInitialiseTaskLists()->pxDelayedTaskList = &xDelayedTaskList1;后,指向的地址才有合法性
  2. 所以,怀疑是运行 App之前,SysTick的中断是打开的,所以才会进入中断服务函数,从而导致内存非法访问,导致卡死
  3. 现在,只需在 Boot层,跳转到 App之前,调用 __disable_irq(),就可以了:
void App_Jump_To_App(uint32_t app_addr) {
  __disable_irq();	//关闭总中断
  volatile uint32_t jump_addr = *(volatile uint32_t *) (FLASH_APP_CODE_ADDR + 4);
  jumpapp = (pjumfunc) jump_addr;		//设置MSP指针
  __set_MSP(*(volatile uint32_t *) FLASH_APP_CODE_ADDR);	//设置栈指针
  jumpapp();	//跳转
}
  1. 为什么不上 RTOS,并且在 Boot层不关闭中断,App也能正常运行???因为在 App中,使用的时基是 TimebaseTIM1,所以 SysTick的中断服务函数里什么也没做,所以即使在跳转到 App之前,SysTick的中断是开启的,也不影响 App
  2. Boot层完成修改之后,调用 HAL_Delay又出现了卡死现象
  3. 这次经调试,发现 TIM1时钟没法进入中断,(HAL_Delay的时基是 TIM1),应该是 TIM1的中断没生效,联系到之前对 Boot层的改动,猜测在 Boot层调用了 __disable_irq(),对 App中的 TIM1有影响
  4. 经上网搜索 __disable_irq()都干了什么事,得知实际上是将 primask1,由此推断,在 Boot层执行关闭中断操作后,导致 AppTIM1中断不能响应:

在这里插入图片描述

  1. 但是为什么去掉 HAL_DelayApp也能运行,是因为 FreeRTOS中,在开启任务调度器的时候,会执行 prvStartFirstTask,在这个函数中会执行一个开中断,将 primask0

在这里插入图片描述

结论

  • 所以,综合上述问题,最终有两种方法比较好,我选择的方法二

    1. 方法一:在 Boot层跳转 App之前,调用 __disable_irq()关闭总中断,然后在 App层系统初始化完成后,立即调用 __enable_irq()打开总中断

       //Boot层
       void App_Jump_To_App(uint32_t app_addr) {
           __disable_irq();	//关闭总中断
           volatile uint32_t jump_addr = *(volatile uint32_t *) (FLASH_APP_CODE_ADDR + 4);
           jumpapp = (pjumfunc) jump_addr;
           __set_MSP(*(volatile uint32_t *) FLASH_APP_CODE_ADDR);
           jumpapp();
       }
      
       //App层
       int main(void)
       {
           HAL_Init();
           SystemClock_Config();
           MX_GPIO_Init();
           __enable_irq();	//开启总中断
           while (1)
           {
               printf("hello world\n");
               HAL_Delay(1000);
           }
       }
      
    2. 方法二:在 Boot层跳转 App前,只关闭 Boot层使用到的中断,不去操作其他中断

       //Boot层
       void App_Jump_To_App(uint32_t app_addr) {
           //这里只需关闭SysTick中断,并将其寄存器置清零
           SysTick->CTRL = 0;
           SysTick->VAL = 0;
           SysTick->LOAD = 0;
      
           volatile uint32_t jump_addr = *(volatile uint32_t *) (FLASH_APP_CODE_ADDR + 4);
           jumpapp = (pjumfunc) jump_addr;
           __set_MSP(*(volatile uint32_t *) FLASH_APP_CODE_ADDR);
           jumpapp();
       }
      
       //App层
       //不用管
      

附录

Cortex-M3 权威指南
项目地址

0

评论区