STM32 HAL庫硬件I2C做從機的BUG

情況簡述

最近在調試與兼容 STM32F103C8T6GD32F103C8T6 時使用了STM32 HAL庫,MCU作爲從機。

在調試到 HAL_I2C_Slave_Receive_IT() 函數,使用中斷方式接收I2C數據時,只要調用了該函數,開啓了中斷,單片機就會一直被 ADDR 寄存器的中斷觸發,循環進入中斷函數中,甚至會嵌套進入,導致我的堆棧爆炸。

排錯歷程

使用調試打印的函數,發現程序不斷執行了HAL庫I2C中斷處理函數中的 I2C_Master_ADDR() 函數,由此我判斷是 ADDR 標誌位未被HAL庫代碼清零。查看HAL庫代碼,發現處理從機收到匹配地址的內容如下:

/* ADDR set --------------------------------------------------------------*/
    if ((I2C_CHECK_FLAG(sr1itflags, I2C_FLAG_ADDR) != RESET) && (I2C_CHECK_IT_SOURCE(itsources, I2C_IT_EVT) != RESET))
    {
      /* Now time to read SR2, this will clear ADDR flag automatically */
      if (hi2c->ErrorCode != HAL_I2C_ERROR_NONE)
      {
        sr2itflags   = READ_REG(hi2c->Instance->SR2);
      }
      I2C_Slave_ADDR(hi2c, sr2itflags);
      // rt_kprintf("I2C_Slave_ADDR\n");
    }

而在I2C_Slave_ADDR()函數中,清除ADDR寄存器的代碼居然時這樣子的

 {
    /* Clear ADDR flag */
   __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_ADDR);

    /* Process Unlocked */
    __HAL_UNLOCK(hi2c);
  }

官方的程序員居然用寫寄存器的操作來清除 ADDR 標誌位,而芯片的操作手冊中明確標明瞭 ADDR 標誌位爲只讀模式, 且清除方式爲按順序讀取 SR1SR2寄存器。

在這裏插入圖片描述
在這裏插入圖片描述
於是修改添加如下代碼, 按順序讀取 SR1 SR2

  else
  {
    /* Clear ADDR flag */
    /* 此清除ADDR操作存在問題,ADDR應該爲read only,只有多SR1  SR2順序讀取的方式清除  */
//    __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_ADDR);

      /* 改寫的清除ADDR代碼 */
      __attribute__((unused)) uint32_t tmp = READ_REG(hi2c->Instance->SR1);
      tmp = READ_REG(hi2c->Instance->SR2);

    /* Process Unlocked */
    __HAL_UNLOCK(hi2c);
  }

再次測試後,I2C slave 中斷模式終於正常運行, 問題被解決。

總結

經過這一番折騰,我就實在是搞不明白ST對他們芯片的硬件I2C的態度了,莫不是官方自己覺得硬件I2C太廢了,以至於在HAL庫中這麼明顯的錯誤都會出現?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章