stm32-HAL使用usart發送中斷判斷發送標志庫問題


前言:

stm32是嵌入式MCU開發中最多應用的芯片,很早之前我們開發ST芯一般都是標准庫開發,標准庫簡潔好讀,現在要配合CubeMX生成代碼,所以官方主推HAL庫和LL庫,但是HAL代碼冗雜很繞,因為出來也不久,有些代碼使用之后不是那么好用。

這次我就來分享兩個實際使用過程中遇到的兩個問題,一個是使用uart的發送中斷進行數據發送產生的數組訪問越界的問題。一個是stop模式下,dma相關的外設休眠喚醒需要注意重新初始化。

這篇是uart使用的介紹:

作者:良知猶存

轉載授權以及圍觀:歡迎關注微信公眾號:羽林君

或者添加作者個人微信:become_me


情節介紹:

串口是我們經常是用的一個外設,一般我們為了發送速度變快,會使用DMA或者中斷發送接收。而CubeMX配置下,HAL調用了自己的一套函數 HAL_UART_IRQHandler 層層調用。

在官方提供的 stm32f4xx_hal_uart.c 文件中你可以看到如下函數:

void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)

{

.....

  /* UART in mode Transmitter ------------------------------------------------*/
  if (((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))
  {
    UART_Transmit_IT(huart);
    return;
  }

......

}

其中在UART_Transmit_IT 函數中 有一段 函數為

if (--huart->TxXferCount == 0U)
{
    /* Disable the UART Transmit Complete Interrupt */
    __HAL_UART_DISABLE_IT(huart, UART_IT_TXE);

    /* Enable the UART Transmit Complete Interrupt */
    __HAL_UART_ENABLE_IT(huart, UART_IT_TC);
}

這里會把發送的 TxXferCount 的計數值自減,並判斷是否為零。正常工作都沒有問題,可是我們的設備實際使用過程中,上層的部分斷電之后,會給底層通訊串口帶了一個中斷,這個時候繼續減下去就會出現出現一個很大值,這個是因為 TxXferCount 是一個無符號的16位數據。

  __IO uint16_t                 TxXferCount;      /*!< UART Tx Transfer Counter */

debug看到如下數據,原因上文提到。就是我遇到我們Linux核心板掉電之后會產生一個中斷,導致這里判斷時候自動減一,TxXferCount從 0 變成 -1 因為是無符號數據,所以數據表現為65535。

在全局搜索TxXferCount調用,我們可以看到TxXferSize 是發送buf的長度數據

HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
  /* Check that a Tx process is not already ongoing */
  if (huart->gState == HAL_UART_STATE_READY)
  {
    if ((pData == NULL) || (Size == 0U))
    {
      return HAL_ERROR;
    }

    /* Process Locked */
    __HAL_LOCK(huart);

    huart->pTxBuffPtr = pData;
    huart->TxXferSize = Size;
    huart->TxXferCount = Size;

    huart->ErrorCode = HAL_UART_ERROR_NONE;
    huart->gState = HAL_UART_STATE_BUSY_TX;

    /* Process Unlocked */
    __HAL_UNLOCK(huart);

    /* Enable the UART Transmit data register empty Interrupt */
    __HAL_UART_ENABLE_IT(huart, UART_IT_TXE);

    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}

此外我們還會發現一處 huart->TxXferCount 計數 自減 使用。

此處的函數如下, 伴隨着一個很大的 TxXferCount開始自減, pdata16bits開始自加。剛開始越界的時候由於該內存被初始化過,所以沒有問題,該循環執行一會之后,程序就會進入hardfault

HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
......

    huart->TxXferSize = Size;
    huart->TxXferCount = Size;

    while (huart->TxXferCount > 0U)
    {
      if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TXE, RESET, tickstart, Timeout) != HAL_OK)
      {
        return HAL_TIMEOUT;
      }
      if (pdata8bits == NULL)
      {
        huart->Instance->DR = (uint16_t)(*pdata16bits & 0x01FFU);
        pdata16bits++;
      }
      else
      {
        huart->Instance->DR = (uint8_t)(*pdata8bits & 0xFFU);
        pdata8bits++;
      }
      huart->TxXferCount--;
    }
......
}

修改建議:

和硬件溝通過,他們的掉電機制,就是如此無法修改。所以我們進行軟件的一些修改,因為會產生一個中斷導致計數值自減,所以我們初步確認進行自減處進行限制,先增加一個零值判斷。

huart->TxXferCount == 0U 

又考慮到我們單包數據單次不會超過150byte,所以又加上150字節的控制。(此處的數據流控制大家可以按照自己實際使用的情況進行酌情使用)

huart->TxXferCount   > 150U

原函數:

static HAL_StatusTypeDef UART_Transmit_IT(UART_HandleTypeDef *huart)
{
......
    if (--huart->TxXferCount == 0U)
    {
      /* Disable the UART Transmit Complete Interrupt */
      __HAL_UART_DISABLE_IT(huart, UART_IT_TXE);
    
      /* Enable the UART Transmit Complete Interrupt */
      __HAL_UART_ENABLE_IT(huart, UART_IT_TC);
    }
 ......
}

改為:

static HAL_StatusTypeDef UART_Transmit_IT(UART_HandleTypeDef *huart)
{
......
    if (huart->TxXferCount == 0U || --huart->TxXferCount == 0U || huart->TxXferCount   > 150U )
    {
      /* Disable the UART Transmit Complete Interrupt */
      __HAL_UART_DISABLE_IT(huart, UART_IT_TXE);
    
      /* Enable the UART Transmit Complete Interrupt */
      __HAL_UART_ENABLE_IT(huart, UART_IT_TC);
    }
 ......
}

最后代碼可以正常的使用。

結語

這就是我分享的項目中遇到一個st官方庫使用的問題,如果大家有更好的想法和需求,也歡迎大家加我好友交流分享哈。


作者:良知猶存,白天努力工作,晚上原創公號號主。公眾號內容除了技術還有些人生感悟,一個認真輸出內容的職場老司機,也是一個技術之外豐富生活的人,攝影、音樂 and 籃球。關注我,與我一起同行。

                              ‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧  END  ‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧

推薦閱讀

【1】C++的智能指針你了解嗎?

【2】嵌入式底層開發的軟件框架簡述

【3】CPU中的程序是怎么運行起來的 必讀

【4】cartographer環境建立以及建圖測試

【5】設計模式之簡單工廠模式、工廠模式、抽象工廠模式的對比

本公眾號全部原創干貨已整理成一個目錄,回復[ 資源 ]即可獲得。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM