stm32DMA+訊息佇列實現串列埠資料接收不丟包

大唐不夜城 發表於 2020-11-21

前提:有一個專案一直使用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 <USART2_MSG_MAX)
        {
        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;
}