前提:有一个项目一直使用DMA+串口空闲中断接收数据,最近发现串口数据丢包。
经过检查发现串口发送机在发送数据过程中本来应该是连续发送,但是中间有某一个字节与下一个字节之间的间距大于一个字节,MCU端会认为产生了一个空闲中断,便触发,这时候如果软件直接读取数据,很有可能后面的数据就直接丢失,并且原程序设计时候在处理过程中是关闭DMA的,这就会导致串口数据堵塞后面的数据也进不了,表现为串口接不到数据。
为了解决这个问题:修改程序逻辑,将DMA的两个中断(接收完成中断,和接收一半中断使能),在超过一半时即开始接收数据,存入另一个缓冲区,然后DMA继续运行,不影响后续数据接收。
之所以设定接收一半中断是为了加快数据流转,避免占用过多资源。下面看代码。
//定义一个fifo循环里面不断查询是否有数据,并处理
经过试验即使发送端发生数据发送中断,后续数据正常发送时也能保证数据被完整的接收,不会出现丢包现象。
typedef struct
{
uint8_t f_cnt;
uint8_t r_cnt;
uint8_t msgcnt;
uint8_t pock;
uint8_t usartbuff[USART2_MSG_MAX];
}ST_UartBuffFIFO;
//数据包进入队列
uint8_t Sdk_Usart_BuffQueueInsertData(ST_UartBuffFIFO *pDataQueue , uint8_t *pDatabuff,uint32_t datasize)
{
if(pDataQueue->msgcnt
{
pDataQueue->pock = 1;
pDataQueue->msgcnt+= datasize;
memcpy(&pDataQueue->usartbuff[pDataQueue->r_cnt],pDatabuff,datasize);
if(pDataQueue->r_cnt >= (USART2_MSG_MAX -1))
{
pDataQueue->r_cnt = 0;
}
else
{
pDataQueue->r_cnt+=datasize ;
}
pDataQueue->pock = 0;
return 1;
}
return 0;
}
//数据包移除队列
uint8_t Sdk_Usart_BuffQueueDeleteData(ST_UartBuffFIFO *pDataQueue, uint8_t *pData )
{
if (pDataQueue->pock == 0)
{
if(pDataQueue->msgcnt >0)
{
pDataQueue->msgcnt--;
*pData = pDataQueue->usartbuff[pDataQueue->f_cnt];
if(pDataQueue->f_cnt >= (USART2_MSG_MAX -1))
{
pDataQueue->f_cnt = 0;
}
else
{
pDataQueue->f_cnt++;
}
return 1;
}
else
{
//pDataQueue->f_cnt = pDataQueue->r_cnt;
pDataQueue->f_cnt = 0;
pDataQueue->r_cnt = 0;
return 0;
}
return 0;
}
前提:有一个项目一直使用DMA+串口空闲中断接收数据,最近发现串口数据丢包。
经过检查发现串口发送机在发送数据过程中本来应该是连续发送,但是中间有某一个字节与下一个字节之间的间距大于一个字节,MCU端会认为产生了一个空闲中断,便触发,这时候如果软件直接读取数据,很有可能后面的数据就直接丢失,并且原程序设计时候在处理过程中是关闭DMA的,这就会导致串口数据堵塞后面的数据也进不了,表现为串口接不到数据。
为了解决这个问题:修改程序逻辑,将DMA的两个中断(接收完成中断,和接收一半中断使能),在超过一半时即开始接收数据,存入另一个缓冲区,然后DMA继续运行,不影响后续数据接收。
之所以设定接收一半中断是为了加快数据流转,避免占用过多资源。下面看代码。
//定义一个fifo循环里面不断查询是否有数据,并处理
经过试验即使发送端发生数据发送中断,后续数据正常发送时也能保证数据被完整的接收,不会出现丢包现象。
typedef struct
{
uint8_t f_cnt;
uint8_t r_cnt;
uint8_t msgcnt;
uint8_t pock;
uint8_t usartbuff[USART2_MSG_MAX];
}ST_UartBuffFIFO;
//数据包进入队列
uint8_t Sdk_Usart_BuffQueueInsertData(ST_UartBuffFIFO *pDataQueue , uint8_t *pDatabuff,uint32_t datasize)
{
if(pDataQueue->msgcnt
{
pDataQueue->pock = 1;
pDataQueue->msgcnt+= datasize;
memcpy(&pDataQueue->usartbuff[pDataQueue->r_cnt],pDatabuff,datasize);
if(pDataQueue->r_cnt >= (USART2_MSG_MAX -1))
{
pDataQueue->r_cnt = 0;
}
else
{
pDataQueue->r_cnt+=datasize ;
}
pDataQueue->pock = 0;
return 1;
}
return 0;
}
//数据包移除队列
uint8_t Sdk_Usart_BuffQueueDeleteData(ST_UartBuffFIFO *pDataQueue, uint8_t *pData )
{
if (pDataQueue->pock == 0)
{
if(pDataQueue->msgcnt >0)
{
pDataQueue->msgcnt--;
*pData = pDataQueue->usartbuff[pDataQueue->f_cnt];
if(pDataQueue->f_cnt >= (USART2_MSG_MAX -1))
{
pDataQueue->f_cnt = 0;
}
else
{
pDataQueue->f_cnt++;
}
return 1;
}
else
{
//pDataQueue->f_cnt = pDataQueue->r_cnt;
pDataQueue->f_cnt = 0;
pDataQueue->r_cnt = 0;
return 0;
}
return 0;
}
举报