提问人:Wiston 提问时间:10/13/2023 更新时间:10/20/2023 访问量:50
STM32F4 Uart 数据转发使用 DMA 并发生丢包
STM32F4 Uart data forwarding uses DMA and packet loss occurs
问:
我正在尝试在STM32F405RGT6开发一个串口转发项目,其中数据由串口2接收(波特率:460800,DMA循环接收,数据存储在RINGBUF中),然后通过串口3传输数据(波特率:460800,DMA发送,从RINGBUF读取数据)。但是,我遇到了一个令人困惑的问题。当我在PC上打开两个串口工具进行收发时,接收到的数据大小与发送的数据大小不匹配。接收到的数据小于发送的数据。
这是rx代码:
uint8_t _rx_process(User_UARTRX_T *c)
{
uint16_t len = 0;
c->pos = c->rx_size - __HAL_DMA_GET_COUNTER(c->huart->hdmarx);
c->len = 0;
if (c->pos != c->oldpos)
{
if (c->pos > c->oldpos)
{
/* Processing is done in "linear" mode. */
c->len = c->pos - c->oldpos;
ringbuffer_put_force(c->ring, &(c->dmabuf[c->oldpos]), c->len);
}
else
{
/* Processing is done in "overflow" mode. */
len = c->rx_size - c->oldpos;
ringbuffer_put_force(c->ring, &(c->dmabuf[c->oldpos]), len);
c->len = len;
if (c->pos > 0)
{
ringbuffer_put_force(c->ring, &(c->dmabuf[0]), c->pos);
c->len = c->pos + len;
}
}
c->oldpos = c->pos;
}
return (c->len == 0 ? 0 : 1);
}
static void User_UartRx_Callback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART2)
{
osThreadFlagsSet(User_UartRxHandle, _SIG_UR2);
}
}
void User_UartRxTask(void *argument)
{
/* USER CODE BEGIN User_UartRxTask */
uint8_t ch;
uint16_t i = 0, len = 0;
uint32_t signal;
/* Infinite loop */
for (;;)
{
signal = osThreadFlagsWait(_SIG_RXALL, osFlagsWaitAny, osWaitForever);
if (signal & _SIG_UR2)
{
if (_rx_process(&crx[1]))
{
crx[1].stream_cnt += crx[1].len;
len = ringbuffer_data_len(&uartRxBuf[1]);
for (i = 0; i < len; ++i)
{
ringbuffer_getchar(&uartRxBuf[1], &ch);
ringbuffer_putchar(&uartTxBuf[1], ch);
User_SDbuf_WR(0, &ch, 1);
}
}
}
}
/* USER CODE END User_UartRxTask */
}
void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart)
{
User_UartRx_Callback(huart);
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
User_UartRx_Callback(huart);
}
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
UNUSED(Size);
User_UartRx_Callback(huart);
}
DMA发送完成、半发送、空闲中断触发的功能,将接收到的数据从DMA缓冲区传输到Ringbuffer,并保存到用于串口转发的缓冲区中。
这是 tx 代码:
uint8_t dma_OK = 1;
uint32_t rcv_T3 = 0, rcv_dma = 0;
void User_UartTxTask(void *argument)
{
/* USER CODE BEGIN User_UartRxTask */
uint16_t len = 0, maxlen = 0;
/* Infinite loop */
for (;;)
{
len = ringbuffer_data_len(&uartTxBuf[1]);
if (len > maxlen)
{
maxlen = len;
}
if (len > 0)
{
len = ringbuffer_get(&uartTxBuf[1], dmaTxBuf, _DMA_RXBUFSIZE);
rcv_T3 += len;
if (dma_OK == 1 && huart3.gState == HAL_UART_STATE_READY)
{
dma_OK = 0;
HAL_UART_Transmit_DMA(&huart3, dmaTxBuf, len);
}
}
/* USER CODE END User_UartRxTask */
osDelay(1);
}
}
static void User_UartTx_Callback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART3)
{
dma_OK = 1;
}
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
User_UartTx_Callback(huart);
}
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
;
}
创建一个新线程来等待数据。如果检测到txRingbuf的长度大于0,则启动DMA传输。在传输完成中断中为 DMA 设置标志,以防止在 DMA 传输不成功时重新启动 DMA 传输。
我尝试了 UART2(波特率 119200,接收)和 UART3(波特率 460800,转发),上面提供的代码成功运行,没有任何数据包丢失。
我尝试了 UART2(波特率 460800,接收)和 UART3(波特率 460800,转发),但在运行代码时,我遇到了数据丢失的问题。代码中用于接收和传输的统计变量 rcv_T3 和 crx[1].stream_cnt 是正确的,并且与发送的数据大小 434724 匹配。但是,在PC上接收的转发数据仅358834。在此处输入图像描述
答:
如果之前的传输没有完成,即 ,但有数据接收到,在你从环形缓冲区中提取这些数据时,你甚至将它们计算到 rcv_T3,但由于dmaOK == 0
User_UartTxTask()
if (dma_OK == 1 && huart3.gState == HAL_UART_STATE_READY)
你只需把这些数据扔掉。
换句话说,在从 ringbuffer 中提取数据之前,您需要执行上述检查 Tx 是否完成。
评论