打印
[应用相关]

一个跟STM32中断优先级有关的话题

[复制链接]
1064|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
laozhongyi|  楼主 | 2016-9-26 20:40 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
“我用STM32F7 MCU开发产品,用到STemwin。在桌面有一个图标,点击图标后创建一个窗口,窗口中3个按钮,和1个listbox。点击窗口中的CANCEL按钮窗口关闭。当我多次打开关闭这个窗口时,程序就会死!经调试,程序是死在了硬件I2C的while循环中,如下代码中:
static
HAL_StatusTypeDef I2C_WaitOnFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t
Flag, FlagStatus Status, uint32_t Timeout)

{  
  uint32_t tickstart = HAL_GetTick();
    /* Wait until flag is set */
  if(Status == RESET)
  {   
    while(__HAL_I2C_GET_FLAG(hi2c, Flag) ==
RESET)
    {
      /* Check for the Timeout */
      if(Timeout != HAL_MAX_DELAY)
      {
        if((Timeout == 0)||((HAL_GetTick() -
tickstart ) > Timeout))
        {
          hi2c->State= HAL_I2C_STATE_READY;
          /* Process Unlocked */
          __HAL_UNLOCK(hi2c);
          return HAL_TIMEOUT;
        }
      }
    }
  }...........省略

或者
static
HAL_StatusTypeDef I2C_IsAcknowledgeFailed(I2C_HandleTypeDef *hi2c, uint32_t
Timeout)
{
  uint32_t tickstart = 0x00;
  tickstart = HAL_GetTick();
  
  if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) ==
SET)
  {
    /* Wait until STOP Flag is reset */
    /* AutoEnd should be initiate after AF */
    while(__HAL_I2C_GET_FLAG(hi2c,
I2C_FLAG_STOPF) == RESET)
    {
      /* Check for the Timeout */
      if(Timeout != HAL_MAX_DELAY)
      {
        if((Timeout == 0)||((HAL_GetTick() -
tickstart ) > Timeout))
        {
          hi2c->State= HAL_I2C_STATE_READY;
          /* Process Unlocked */
          __HAL_UNLOCK(hi2c);
          return HAL_TIMEOUT;
        }
      }
    }...........省略

该I2C程序是操作电阻触摸屏芯片的,由TIMER3定时器定时调用它。timer3中断优先级是[0,1。I2C程序中超时检测是用的SYSTICK,其中断优先级是[0x0f,0(第一个数字为抢占优先级,第二个数字为响应优先级)。
调试发现,程序死掉后,HAL_GetTick() 返回值始终不变,这样才进入死循环!
怀疑是systick优先级低,将其改为[0,0最高优先级后,依然会进入上面的死循环!”

很明显,上面用户代码是基于STM32cube库实现的。根据上面用户反馈的问题描述,他是说程序有时会死掉,而且总死在I2C通信代码里。这个I2C通信代码是通过TIM3的中断调用的,其中I2C通信中的TIMEOUT超时检测又是依据SYSTICK中断计时实现。【注:用户设计的合理性,这里暂且不谈】

应该说用户已经意识到问题的原因了。如果SYSTICK优先级低于TIM3中断优先级,而I2C通信又是在TIM3中断里执行,那在I2C程序运行过程中SYSTICK中断就没法响应,无法进行TICK计数的加减。如果此时I2C通信出现故障,TIMOUT超时检测条件就永远不会成立。程序当然就卡死在那里面了。

后来用户将SYSTICK的优先级从之前的【0x0f,0】调整为【0,0】后现象仍未改善。他认为【0,0】是最高了。其实,此时SYSTICK的抢占优先级与TIM3抢占优先级是一样的,只是二者响应优先级不一样。如果这样的话,在TIM3 中断服务程序里,SYSTICK仍然无法响应中断进行计数,也就无法通过TIMEOUT检测退出死循环。

如果反过来,将SYSTICK的抢占优先级设置得比TIM3的抢占优先级高,情况就不同了。比方将SYSTICK的优先级配置为【0,0】,TIM3的优先级配置为【1,0】。如果这样,TIM3中断里调用I2C通信程序,如果I2C通信出现故障,TIMEOUT超时检测就不会受阻卡死。因为此时SYSTICK的抢占优先级高于TIM3的,它可以打断TIM3中断程序进行TICK的计数计时,当I2C程序检测到TIMEOUT成立时就可以全身而退了。后来建议用户如此调整的确改善。

小结下,问题源于用户对中断优先级的理解不到位。在MCU开发应用中因为中断优先级处理不当而导致困扰其实还挺多的,而且问题往往还比较隐蔽。

顺便提醒下:对于STM32F7/F4/F3/F1/L1/L4系列芯片的中断优先级往往分为抢占优先级和响应优先级。只有抢占优先级不同时才会发生中断的打断和嵌套。如果抢占优先级一样的话,在同时发生中断事件时,响应优先级高的中断源优先得到响应。如果抢占优先级和响应优先级也一样,同时发生中断时根据其中断向量表的序号决定。
对于基于CORTEX M0/M0+的STM32F0/L0系列,它们的中断优先级只有抢占优先级,不分响应优先级。
沙发
Edisons| | 2016-9-26 20:44 | 只看该作者
STM32中断优先级有关的问题经常有出现。

使用特权

评论回复
板凳
天灵灵地灵灵| | 2016-9-26 23:26 | 只看该作者
果SYSTICK优先级低于TIM3中断优先级,而I2C通信又是在TIM3中断里执行,那在I2C程序运行过程中SYSTICK中断就没法响应,无法进行TICK计数的加减。

使用特权

评论回复
地板
zhuotuzi| | 2016-9-27 08:37 | 只看该作者
如果卡死在while里,就在while加个超时跳出的指令。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

111

主题

1388

帖子

0

粉丝