電子產(chǎn)業(yè)一站式賦能平臺

PCB聯(lián)盟網(wǎng)

搜索
查看: 324|回復(fù): 0
收起左側(cè)

USART接收的數(shù)據(jù)怎么錯位啦?

[復(fù)制鏈接]

491

主題

491

帖子

3107

積分

四級會員

Rank: 4

積分
3107
跳轉(zhuǎn)到指定樓層
樓主
發(fā)表于 2024-8-21 11:38:00 | 只看該作者 |只看大圖 回帖獎勵 |正序瀏覽 |閱讀模式
有人使用STM32G4系列的USART,并開啟DMA方式的定長接收,DMA工作在Normal模式,但是偶爾會出現(xiàn)接收出錯問題。令人頭疼的是一旦出錯了后面的接收總是錯的,出錯的位置往往體現(xiàn)在一幀的第一個數(shù)據(jù)。除非重啟系統(tǒng)才能消除接收連續(xù)出錯問題。下面兩幅圖是UART接收出錯的情形!緸榱吮阌诮涣,后面的定長接收都是指8個字符的接收!



使用場景大致是這樣的。某工程師使用STM32G474開發(fā)產(chǎn)品,用到某USART的DMA收發(fā)。MCU通過USART跟外部傳感器進(jìn)行通信,USART的收發(fā)都使用DMA方式,Normal模式。兩端的收發(fā)都是定長方式,即收發(fā)都是基于確定長度的傳輸。
實際調(diào)試過程中,他發(fā)現(xiàn)STM32G4芯片的USART的DMA發(fā)送倒沒啥問題,就是接收偶爾會出錯。一旦出錯,后面就一直錯。通信兩端明明使用的定長數(shù)據(jù)的收發(fā),數(shù)據(jù)怎么會錯亂?即使偶爾出差了要怎樣才能及時恢復(fù)正常呢?
后來經(jīng)反復(fù)檢查確認(rèn),他說的定長收發(fā)只是理論上的或者說預(yù)期的。實際上,在通信過程中偶爾會有額外的噪聲竄出來,即傳感器端實際發(fā)送過來的數(shù)據(jù)可能多于指定長度。多發(fā)的數(shù)據(jù)雖然沒有被當(dāng)次接收,但留在USART接收FIFO了。下次基于DMA接收時,F(xiàn)IFO數(shù)據(jù)若沒被清掉就會當(dāng)作下一次的接收數(shù)據(jù)了。
因為接收這邊是DMA定長接收,發(fā)送端也是定長發(fā)送,但由于FIFO里噪聲數(shù)據(jù)的存在,接收端沒法全部接收新的數(shù)據(jù),使得FIFO里始終有殘留數(shù)據(jù),進(jìn)而導(dǎo)致后續(xù)的接收發(fā)生錯位。
下面截圖是STMG4的USART的功能框圖,看看有助于理解。

既然這樣,我們可以在每次的USART的定長接收完成之后、開啟下一次DMA接收前,將USART的FIFO清理干凈。當(dāng)然這個過程中,要注意溢出問題,發(fā)生溢出后會妨礙DMA請求的產(chǎn)生,我們需及時處理溢出標(biāo)志。
下面簡單演示解決上面問題的做法。使用STM32G474的USART2的DMA收發(fā)功能,STM32G474的USART每次從PC的串口終端做8個字符的定長接收,多余的將被丟棄并不可以影響下次接收,同時,STM32G474將每次收到的8個字符回顯到PC串口終端。開啟USART DMA接收的完成中斷,每次收到8字符時設(shè)置相應(yīng)的標(biāo)志【Flag_Rxcpt】,并稍作延時,保證一次性發(fā)送過來的字符發(fā)送完畢。注意,是保障對方的發(fā)送完畢,接收的話每次只接收8個字符。
下面的測試使用STM32G474的USART2的配置如下:




USART收發(fā)的FIFO可開可關(guān),下面做法都適用。另外,這里沒有使能USART2的中斷響應(yīng),使用庫函數(shù)組織代碼的話最好使能它,可以省些事。
解決上面問題的第一種做法就是每次在開啟下次DMA接收前將USART重新初始化一下,這個肯定是有效的。沒理由重新初始化USART了,其FIFO數(shù)據(jù)還不失效吧。見下圖紅框中的代碼。


下面是USART DMA接收完成中斷的回調(diào)處理函數(shù)。接收到8個字符后設(shè)置接收標(biāo)志,并設(shè)置延時參數(shù),讓對方或線路上可能多發(fā)或多產(chǎn)生的數(shù)據(jù)發(fā)送完畢。

不過這個操作動作有點大,有時可能不太合適。我們可以換個做法,像下面這樣,通過查詢RXNE標(biāo)志來讀取接收數(shù)據(jù)寄存器。其實就是將FIFO里的殘留清掉,同時預(yù)防性地對溢出標(biāo)志清零。


如果前面使能了USART的中斷響應(yīng),基于庫函數(shù)組織代碼時,此處對溢出標(biāo)志清零就不必要了,可以到中斷服務(wù)程序里處理。顯然第二種做法更有針對性,動作不波及其它。
當(dāng)然,還有另外一種做法,通過操作特定寄存器清空USART接收FIFO。具體就是對USART_RQR寄存器的RXFRQ位寫1,發(fā)起對接收FIFO清空的請求。操作代碼如下:

下面是基于上面幾種做法的驗證結(jié)果。USART接收時DMA每次只搬8個數(shù)據(jù),多發(fā)過來的數(shù)據(jù)不予理睬,也不影響后續(xù)的再次接收。

不管哪種做法,最終目的都一樣,即在開啟下次的USART接收前先清空接收FIFO。OK,今天的分享就到這里,下次再聊~!
猜你喜歡:
WiFi6+藍(lán)牙+星閃,三合一開發(fā)板,真香!
Github上熱門 C 語言項目匯總!
嵌入式,可測試性軟件設(shè)計!
一些低功耗軟件設(shè)計的要點!
嵌入式 C 保護(hù)結(jié)構(gòu)體的方式
實用 | 10分鐘教你通過網(wǎng)頁點燈
談?wù)勄度胧杰浖募嫒菪裕?/strong>
回復(fù)

使用道具 舉報

發(fā)表回復(fù)

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

關(guān)閉

站長推薦上一條 /1 下一條


聯(lián)系客服 關(guān)注微信 下載APP 返回頂部 返回列表