zoukankan      html  css  js  c++  java
  • 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】设计模式之简单工厂模式、工厂模式、抽象工厂模式的对比

    本公众号全部原创干货已整理成一个目录,回复[ 资源 ]即可获得。

  • 相关阅读:
    linq
    存储过程动态显示top条数
    js正则表达式
    WebClient异步下载文件
    C++ socket编程基础(ZT)
    Oracle数据导入导出imp/exp命令 10g以上expdp/impdp命令(转载)
    C#获取各种格式的系统时间
    C++中对sprintf()函数的说明(转)
    史上最全前端面试题(含答案)B篇
    常用正则表达式
  • 原文地址:https://www.cnblogs.com/conscience-remain/p/15389643.html
Copyright © 2011-2022 走看看