STM32F413串口发送时接收数据丢失问题求助
针对你遇到的发送大数据包时忽略后续接收数据的问题,结合STM32F413的硬件特性,给出以下几个可行方案:
配置DMA双缓冲区(Ping-Pong)接收
启用UART DMA的循环接收模式,搭配两个独立的接收缓冲区。当DMA填满一个缓冲区时,立即触发中断并切换到另一个缓冲区继续接收,同时在中断回调里把已完成的缓冲区数据转存到后台队列,完全不会被发送操作阻塞。建议缓冲区大小设为4KB以上,足以容纳你的2K数据包。用后台发送队列+DMA发送完成中断驱动
不要在接收完成后直接调用阻塞式发送函数,而是把待发送数据存入线程安全的环形队列,由DMA发送完成中断触发下一轮发送。这样发送大数据包时,CPU可以继续处理接收中断,不会因为等待发送完成而丢包。参考代码示例:// 定义环形发送队列 uint8_t tx_ring_buf[64 * 1024]; volatile uint32_t tx_head = 0; volatile uint32_t tx_tail = 0; volatile uint8_t tx_busy = 0; // 接收完成后将数据入队 void uart_rx_done(uint8_t* data, uint32_t len) { for (uint32_t i = 0; i < len; i++) { tx_ring_buf[tx_head] = data[i]; tx_head = (tx_head + 1) % sizeof(tx_ring_buf); } // 若当前无发送任务,启动DMA发送 if (!tx_busy) { uint32_t send_len = (tx_head - tx_tail + sizeof(tx_ring_buf)) % sizeof(tx_ring_buf); if (send_len > 0) { HAL_UART_Transmit_DMA(&huart1, &tx_ring_buf[tx_tail], send_len); tx_tail = (tx_tail + send_len) % sizeof(tx_ring_buf); tx_busy = 1; } } } // DMA发送完成回调 void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) { tx_busy = 0; // 检查队列剩余数据,继续发送 uint32_t send_len = (tx_head - tx_tail + sizeof(tx_ring_buf)) % sizeof(tx_ring_buf); if (send_len > 0) { HAL_UART_Transmit_DMA(huart, &tx_ring_buf[tx_tail], send_len); tx_tail = (tx_tail + send_len) % sizeof(tx_ring_buf); tx_busy = 1; } }启用UART硬件FIFO并调整触发阈值
STM32F413的UART自带16字节硬件FIFO,默认可能未启用。调用HAL_UARTEx_EnableFIFO()开启FIFO,再设置合适的中断触发阈值(比如8字节或14字节),可以减少中断触发频率,同时利用FIFO的缓冲能力,避免短时间内接收数据溢出。配置代码:HAL_UARTEx_EnableFIFO(&huart1); HAL_UARTEx_SetRxFifoThreshold(&huart1, UART_RX_FIFO_THRESHOLD_8_ITEMS);引入RTOS拆分任务
如果项目未使用RTOS,建议引入FreeRTOS这类轻量级系统,将接收、发送拆分为独立任务,给接收任务设置更高优先级。接收任务仅负责把数据存入队列,发送任务从队列取数发送,彻底隔离发送和接收的执行流程,避免互相阻塞。优化DMA和UART优先级
在CubeMX中检查DMA通道优先级,将接收DMA的优先级设为高于发送DMA,确保接收数据的DMA请求不会被发送抢占,保证数据及时从UART寄存器传输到内存。
内容的提问来源于stack exchange,提问作者shlee

