我正在尝试在STM32F405RGT6中开发一个串口转发项目,其中数据通过串口2接收(波特率:460800,DMA循环接收,数据存储在RINGBUF中),然后通过串口3(波特率:460800,DMA循环接收,数据存储在RINGBUF中)发送数据:460800,DMA发送,从RINGBUF读取数据)。然而,我遇到了一个令人困惑的问题。当我在PC上打开两个串口工具进行发送和接收时,接收数据的大小与发送数据的大小不匹配。接收到的数据小于发送的数据。
这是接收代码:
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 buffer传输到Ringbuffer,并保存到用于串口转发的buffer中。
这是交易代码:
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 传输。
我尝试了UART2(波特率119200,接收)和UART3(波特率460800,转发),上面提供的代码成功运行,没有任何丢包。
我尝试了UART2(波特率460800,接收)和UART3(波特率460800,转发),但是在运行代码时,遇到了数据丢失的问题。代码中接收和发送的统计变量rcv_T3和crx[1].stream_cnt是正确的,与发送的数据大小434724相匹配。但PC上收到的转发数据只有358834。
如果之前的传输没有完成,即 dmaOK == 0,但是收到了数据,在 User_UartTxTask() 中,您从环形缓冲区中提取这些数据,您甚至可以将它们计数到 rcv_T3,但是由于
if (dma_OK == 1 && huart3.gState == HAL_UART_STATE_READY)
你只需扔掉这些数据即可。
JW