ST意法半导体
直播中

云达贞

8年用户 957经验值
私信 关注
[问答]

stm32f105串口数据丢失的原因?

hal库通过dma空闲中断接收数据,收到的数据直接通过串口打印出去,每隔一段时间出现接收到数据丢失是为啥呢

回帖(3)

王官君

2025-3-15 17:43:00
如何理解你空闲中断接收数据呢?顶多说明你开启了空闲中断,数据接收到底是中断方式还是查询方式甚至DMA方式呢?


可能的话,尽量使用中断或DMA方式接收,系统里中断多的话,注意合理安排各个中断优先级。这样保障每次过来的数据都


能接收到而不发生溢出  丢失。调试状态下可以适当查看下相关状态寄存器的标志。


另外,现在是基于空闲事件作为数据接收的结束,接收缓冲可以适当放大点。
举报

吴纯英

2025-3-15 17:43:05
可以通过定时,定量,发送固定数据测试一下。


如果OK的话,那么考虑逻辑问题。

如果还会丢失的话,那么有固定逻辑可以方便调试找问题。

注意,前提信号质量和双方波特率要合格。
举报

硕达科讯

2025-3-21 17:55:45

在STM32F105中使用HAL库通过DMA空闲中断接收数据时出现数据丢失,可能由以下原因导致。以下是具体分析和解决方案:




1. DMA缓冲区溢出



  • 原因:DMA接收缓冲区过小,或数据处理速度慢于数据接收速度,导致新数据覆盖未处理的数据。

  • 解决方案

    • 增大DMA缓冲区,确保能容纳两次数据处理间隔内的最大数据量。

    • 使用循环模式(Circular Mode)配置DMA,避免单次传输后停止接收。

    • 在空闲中断中立即提取数据并重启DMA接收(调用HAL_UART_Receive_DMA())。





2. 中断处理延迟



  • 原因:空闲中断优先级低或被其他高优先级中断阻塞,导致未能及时处理数据。

  • 解决方案

    • 提高空闲中断(UART IDLE)的优先级,确保快速响应。

    • 中断处理函数保持简短,仅标记标志位,在主循环中处理数据(避免在中断中调用耗时函数如printf)。





3. 阻塞式发送导致DMA重启延迟



  • 原因:在空闲中断中直接使用HAL_UART_Transmit()等阻塞函数发送数据,导致DMA未及时重启。

  • 解决方案

    • 改用非阻塞发送(如DMA或中断模式发送),例如HAL_UART_Transmit_DMA()

    • 在发送完成回调函数中重启接收DMA,确保发送期间不丢失数据。





4. DMA配置错误



  • 原因

    • DMA未配置为循环模式,接收一次后停止。

    • 未正确处理DMA传输完成中断与空闲中断的冲突。


  • 解决方案

    • 在初始化时配置DMA为循环模式:
      hdma_usart_rx.Init.Mode = DMA_CIRCULAR; // 循环模式

    • 确保在空闲中断中不依赖DMA传输完成中断,直接通过__HAL_DMA_GET_COUNTER()计算接收数据长度。





5. 数据长度计算错误



  • 原因:错误计算DMA已接收的数据量,导致数据截断或残留。

  • 解决方案

    • 使用以下方法计算接收长度:
      uint16_t len = BUFFER_SIZE - __HAL_DMA_GET_COUNTER(huart->hdmarx);

    • 在重启DMA接收前,确保缓冲区索引或指针已重置。





6. 串口错误标志未清除



  • 原因:溢出错误(Overrun Error)或噪声错误导致后续数据丢失。

  • 解决方案

    • 在中断处理函数中检查并清除错误标志:
      if (__HAL_UART_GET_FLAG(huart, UART_FLAG_ORE)) {
      __HAL_UART_CLEAR_OREFLAG(huart);
      }

    • 启用串口错误中断(如HAL_UART_ERROR_CALLBACK())进行错误处理。





7. 硬件配置问题



  • 原因:波特率不匹配、时钟配置错误或硬件连接不稳定。

  • 解决方案

    • 使用示波器检查波特率实际值是否与配置一致。

    • 确认STM32的USART时钟源(如PCLK)配置正确,避免分频误差。





代码示例(关键步骤)


// 1. 初始化DMA为循环模式
hdma_usart_rx.Init.Mode = DMA_CIRCULAR;
HAL_DMA_Init(&hdma_usart_rx);

// 2. 启动DMA接收
HAL_UART_Receive_DMA(&huart1, rx_buf, RX_BUF_SIZE);

// 3. 空闲中断处理
void USART1_IRQHandler(void) {
    if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE)) {
        __HAL_UART_CLEAR_IDLEFLAG(&huart1);

        // 计算接收长度
        uint16_t len = RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart1.hdmarx);

        // 立即处理数据(如存入队列)
        process_data(rx_buf, len);

        // 重启DMA接收(非循环模式需手动重启)
        // HAL_UART_Receive_DMA(&huart1, rx_buf, RX_BUF_SIZE);
    }
}

// 4. 使用DMA非阻塞发送
HAL_UART_Transmit_DMA(&huart2, tx_buf, tx_len);



总结


通过优化DMA配置、确保中断高效处理、避免阻塞操作,并正确计算数据长度,可有效解决数据丢失问题。建议结合逻辑分析仪或调试器监控中断触发频率和DMA状态,进一步定位瓶颈。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分