写点什么

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】设计模式之简单工厂模式、工厂模式、抽象工厂模式的对比


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

发布于: 刚刚阅读数: 2
用户头像

良知犹存

关注

还未添加个人签名 2020.05.29 加入

还未添加个人简介

评论

发布
暂无评论
stm32-HAL使用usart发送中断判断发送标志库问题