|
有人使用STM32G4系列的USART,并開啟DMA方式的定長接收,DMA工作在Normal模式,但是偶爾會(huì)出現(xiàn)接收出錯(cuò)問題。令人頭疼的是一旦出錯(cuò)了后面的接收總是錯(cuò)的,出錯(cuò)的位置往往體現(xiàn)在一幀的第一個(gè)數(shù)據(jù)。除非重啟系統(tǒng)才能消除接收連續(xù)出錯(cuò)問題。下面兩幅圖是UART接收出錯(cuò)的情形!緸榱吮阌诮涣,后面的定長接收都是指8個(gè)字符的接收!
anwvvbetrot6405507120.png (91.54 KB, 下載次數(shù): 1)
下載附件
保存到相冊
anwvvbetrot6405507120.png
2024-8-21 13:20 上傳
11dayj3dn036405507220.png (83.16 KB, 下載次數(shù): 0)
下載附件
保存到相冊
11dayj3dn036405507220.png
2024-8-21 13:20 上傳
使用場景大致是這樣的。某工程師使用STM32G474開發(fā)產(chǎn)品,用到某USART的DMA收發(fā)。MCU通過USART跟外部傳感器進(jìn)行通信,USART的收發(fā)都使用DMA方式,Normal模式。兩端的收發(fā)都是定長方式,即收發(fā)都是基于確定長度的傳輸。
實(shí)際調(diào)試過程中,他發(fā)現(xiàn)STM32G4芯片的USART的DMA發(fā)送倒沒啥問題,就是接收偶爾會(huì)出錯(cuò)。一旦出錯(cuò),后面就一直錯(cuò)。通信兩端明明使用的定長數(shù)據(jù)的收發(fā),數(shù)據(jù)怎么會(huì)錯(cuò)亂?即使偶爾出差了要怎樣才能及時(shí)恢復(fù)正常呢?
后來經(jīng)反復(fù)檢查確認(rèn),他說的定長收發(fā)只是理論上的或者說預(yù)期的。實(shí)際上,在通信過程中偶爾會(huì)有額外的噪聲竄出來,即傳感器端實(shí)際發(fā)送過來的數(shù)據(jù)可能多于指定長度。多發(fā)的數(shù)據(jù)雖然沒有被當(dāng)次接收,但留在USART接收FIFO了。下次基于DMA接收時(shí),F(xiàn)IFO數(shù)據(jù)若沒被清掉就會(huì)當(dāng)作下一次的接收數(shù)據(jù)了。
因?yàn)榻邮者@邊是DMA定長接收,發(fā)送端也是定長發(fā)送,但由于FIFO里噪聲數(shù)據(jù)的存在,接收端沒法全部接收新的數(shù)據(jù),使得FIFO里始終有殘留數(shù)據(jù),進(jìn)而導(dǎo)致后續(xù)的接收發(fā)生錯(cuò)位。
下面截圖是STMG4的USART的功能框圖,看看有助于理解。
h3ejrvmjbpb6405507320.png (90.65 KB, 下載次數(shù): 1)
下載附件
保存到相冊
h3ejrvmjbpb6405507320.png
2024-8-21 13:20 上傳
既然這樣,我們可以在每次的USART的定長接收完成之后、開啟下一次DMA接收前,將USART的FIFO清理干凈。當(dāng)然這個(gè)過程中,要注意溢出問題,發(fā)生溢出后會(huì)妨礙DMA請求的產(chǎn)生,我們需及時(shí)處理溢出標(biāo)志。
下面簡單演示解決上面問題的做法。使用STM32G474的USART2的DMA收發(fā)功能,STM32G474的USART每次從PC的串口終端做8個(gè)字符的定長接收,多余的將被丟棄并不可以影響下次接收,同時(shí),STM32G474將每次收到的8個(gè)字符回顯到PC串口終端。開啟USART DMA接收的完成中斷,每次收到8字符時(shí)設(shè)置相應(yīng)的標(biāo)志【Flag_Rxcpt】,并稍作延時(shí),保證一次性發(fā)送過來的字符發(fā)送完畢。注意,是保障對方的發(fā)送完畢,接收的話每次只接收8個(gè)字符。
下面的測試使用STM32G474的USART2的配置如下:
jnjkjova5se6405507421.png (124.1 KB, 下載次數(shù): 2)
下載附件
保存到相冊
jnjkjova5se6405507421.png
2024-8-21 13:20 上傳
zt3pus2tjkw6405507521.png (134.38 KB, 下載次數(shù): 2)
下載附件
保存到相冊
zt3pus2tjkw6405507521.png
2024-8-21 13:20 上傳
USART收發(fā)的FIFO可開可關(guān),下面做法都適用。另外,這里沒有使能USART2的中斷響應(yīng),使用庫函數(shù)組織代碼的話最好使能它,可以省些事。
解決上面問題的第一種做法就是每次在開啟下次DMA接收前將USART重新初始化一下,這個(gè)肯定是有效的。沒理由重新初始化USART了,其FIFO數(shù)據(jù)還不失效吧。見下圖紅框中的代碼。
k1fuxz3u3cw6405507621.png (213.27 KB, 下載次數(shù): 2)
下載附件
保存到相冊
k1fuxz3u3cw6405507621.png
2024-8-21 13:20 上傳
下面是USART DMA接收完成中斷的回調(diào)處理函數(shù)。接收到8個(gè)字符后設(shè)置接收標(biāo)志,并設(shè)置延時(shí)參數(shù),讓對方或線路上可能多發(fā)或多產(chǎn)生的數(shù)據(jù)發(fā)送完畢。
30epaz4nzh36405507721.png (80.99 KB, 下載次數(shù): 0)
下載附件
保存到相冊
30epaz4nzh36405507721.png
2024-8-21 13:20 上傳
不過這個(gè)操作動(dòng)作有點(diǎn)大,有時(shí)可能不太合適。我們可以換個(gè)做法,像下面這樣,通過查詢RXNE標(biāo)志來讀取接收數(shù)據(jù)寄存器。其實(shí)就是將FIFO里的殘留清掉,同時(shí)預(yù)防性地對溢出標(biāo)志清零。
j2345knkftr6405507821.png (228.68 KB, 下載次數(shù): 1)
下載附件
保存到相冊
j2345knkftr6405507821.png
2024-8-21 13:20 上傳
如果前面使能了USART的中斷響應(yīng),基于庫函數(shù)組織代碼時(shí),此處對溢出標(biāo)志清零就不必要了,可以到中斷服務(wù)程序里處理。顯然第二種做法更有針對性,動(dòng)作不波及其它。
當(dāng)然,還有另外一種做法,通過操作特定寄存器清空USART接收FIFO。具體就是對USART_RQR寄存器的RXFRQ位寫1,發(fā)起對接收FIFO清空的請求。操作代碼如下:
oqophsn2ofc6405507921.png (18.93 KB, 下載次數(shù): 0)
下載附件
保存到相冊
oqophsn2ofc6405507921.png
2024-8-21 13:20 上傳
下面是基于上面幾種做法的驗(yàn)證結(jié)果。USART接收時(shí)DMA每次只搬8個(gè)數(shù)據(jù),多發(fā)過來的數(shù)據(jù)不予理睬,也不影響后續(xù)的再次接收。
qo5jmejbmxn6405508022.png (64.94 KB, 下載次數(shù): 0)
下載附件
保存到相冊
qo5jmejbmxn6405508022.png
2024-8-21 13:20 上傳
不管哪種做法,最終目的都一樣,即在開啟下次的USART接收前先清空接收FIFO。OK,今天的分享就到這里,下次再聊~!
猜你喜歡:
WiFi6+藍(lán)牙+星閃,三合一開發(fā)板,真香!
Github上熱門 C 語言項(xiàng)目匯總!
嵌入式,可測試性軟件設(shè)計(jì)!
一些低功耗軟件設(shè)計(jì)的要點(diǎn)!
嵌入式 C 保護(hù)結(jié)構(gòu)體的方式
實(shí)用 | 10分鐘教你通過網(wǎng)頁點(diǎn)燈
談?wù)勄度胧杰浖募嫒菪裕?/strong> |
|