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

文章讲述了在STM32上进行IAP升级测试时,Boot层与App层通信时遇到的问题,涉及到中断管理、时基切换、中断服务函数缺失以及FreeRTOS的影响。作者通过调试发现,关闭Boot层的总中断或只关闭与App相关中断可以解决App卡死问题。
摘要由CSDN通过智能技术生成

场景

基于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();	//跳转
    
    }
    
  4. **为什么不上RTOS,并且在Boot层不关闭中断,App也能正常运行???**因为在App中,使用的时基是TimebaseTIM1,所以SysTick的中断服务函数里什么也没做,所以即使在跳转到App之前,SysTick的中断是开启的,也不影响App

  5. Boot层完成修改之后,调用HAL_Delay又出现了卡死现象

  6. 这次经调试,发现TIM1时钟没法进入中断,(HAL_Delay的时基是TIM1),应该是TIM1的中断没生效,联系到之前对Boot层的改动,猜测在Boot层调用了__disable_irq(),对App中的TIM1有影响

  7. 经上网搜索__disable_irq()都干了什么事,得知实际上是将primask1,由此推断,在Boot层执行关闭中断操作后,导致AppTIM1中断不能响应:

    在这里插入图片描述

  8. 但是为什么去掉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权威指南
项目地址

  • 32
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值