You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

STM32 UART发送一段时间后停止响应问题求助

问题:UART发送功能运行一段时间后停止响应

我使用搭载FreeRTOS和STM32 iCUBE LoRaWAN栈的STM32L476RG NUCLEO开发板,通过UART接口与树莓派连接,实现两者间的周期性数据收发。由于接收数据量不固定,采用带DMA和空闲线检测的环形缓冲区实现接收,相关回调函数代码如下:

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
    if (huart->Instance == USART3)
    {
            oldPos = newPos;  // Update the last position before copying new data

            /* If the data in large and it is about to exceed the buffer size, we have to route it to the start of the buffer
             * This is to maintain the circular buffer
             * The old data in the main buffer will be overlapped
             */
            if (oldPos+Size > MainBuf_SIZE)  // If the current position + new data size is greater than the main buffer
            {
                    uint16_t datatocopy = MainBuf_SIZE-oldPos;  // find out how much space is left in the main buffer
                    memcpy ((uint8_t *)MainBuf+oldPos, RxBuf, datatocopy);  // copy data in that remaining space

                    oldPos = 0;  // point to the start of the buffer
                    memcpy ((uint8_t *)MainBuf, (uint8_t *)RxBuf+datatocopy, (Size-datatocopy));  // copy the remaining data
                    newPos = ((Size)-datatocopy);  // update the position
            }

            /* if the current position + new data size is less than the main buffer
             * we will simply copy the data into the buffer and update the position
             */
            else
            {
                    memcpy (MainBuf+oldPos, RxBuf, Size);
                    newPos = Size+oldPos;
            }

    }

    print_mem_hex(RxBuf, Size);

    //HAL_UARTEx_ReceiveToIdle_DMA(&huart3, RxBuf, RxBuf_SIZE);
}

但运行一段时间后,UART发送功能会停止响应。我已尝试停止并重启HAL_UART_Receive_IT()的方法,问题仍未解决,恳请提供解决方案建议。


解决方案建议

  • 检查并处理UART/DMA错误状态:在回调函数或定时任务中,定期检查huart3->ErrorCode,排查是否存在帧错误、溢出错误或DMA传输错误。一旦检测到错误,需在HAL_UART_ErrorCallback中执行错误复位逻辑,比如停止DMA、清除错误标志后重新启动接收。
  • 恢复DMA接收的重启逻辑:当前代码中注释掉了HAL_UARTEx_ReceiveToIdle_DMA(&huart3, RxBuf, RxBuf_SIZE);,这会导致处理完一次空闲中断后,DMA接收未重新开启,后续无法触发新的接收事件,甚至可能引发发送链路的同步异常。必须在回调末尾重新启动DMA接收,同时增加错误处理:
    // 在回调函数末尾添加
    if (HAL_UARTEx_ReceiveToIdle_DMA(&huart3, RxBuf, RxBuf_SIZE) != HAL_OK) {
        HAL_DMA_Abort(&hdma_usart3_rx);
        HAL_UARTEx_ReceiveToIdle_DMA(&huart3, RxBuf, RxBuf_SIZE);
    }
    
  • 保证环形缓冲区的线程安全:由于使用FreeRTOS,全局变量oldPos和newPos的读写操作需通过互斥锁(如xSemaphoreHandle)保护,避免中断与任务同时操作导致数据混乱,进而引发后续处理异常影响发送功能。
  • 规范UART发送的调用逻辑:如果使用HAL_UART_Transmit_DMA发送数据,需确保每次发送前DMA处于空闲状态,避免重复启动DMA导致传输错误;如果使用阻塞式发送,需合理设置任务优先级,防止高优先级任务长时间占用CPU导致发送任务无法调度。
  • 排查硬件层面干扰:检查UART引脚的电平稳定性,排查是否存在电磁干扰导致通信错误;同时测试树莓派的UART发送功能是否正常,排除对方设备故障的可能性。

内容的提问来源于stack exchange,提问作者busybee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 14:44:53