場景:
can標準幀中每一幀只能傳輸8字節,而應用中傳輸一包的內容往往超過8字節,因此需要把一個包拆成多個幀發送,接收端才把收到的多幀重新組裝成一個完整的包
問題描述
在一問一答的兩塊板間通信,多幀連發是能夠按照順序發送的。但是,在一個主板和多個從板之間輪詢一問一答的通信中,偶爾出現持續一段時間或者長時間無法通信的情況,特別高幀率發送的情況下,幾乎無法通信。
原因分析:
抓取can總線數據發現不同板之間的幀相互交叉亂序
,導致接收到的包因為亂序無法還原。但是不能保證多幀連續發送的話,就會導致無法還原包。如圖,7E和E7之間為一包,但其出現亂序
發送過程大致為
- 把包根據8字節拆分為多個幀
- 調用發送函數HAL_CAN_AddTxMessage塞第一幀進發送郵箱,id為本設備ID
- can自動從郵箱里面取出該幀發送
- 發送完畢觸發郵箱發送完畢中斷,在中斷里面再調用HAL_CAN_AddTxMessage塞下一幀進發送郵箱,ID為0,以最高優先級占用CAN總線,循環直到最后一幀
以上過程按道理很快就可以連續發送,但是就是會出現不連續的情況。因為采用的輪詢方式,很難保證其他can總線的設備不也在同時在競爭can總線,在發送完畢進入中斷塞數據進郵箱的空隙,盡管ID號是0,但是在競爭總線的時刻,還在中斷里面塞數據進郵箱,并未參與can總線競爭,就會被其他的設備競爭掉總線了,待填充完郵箱,因為ID號為0,其又可以占用can進行發送,就出現了本設備的幀和其他設備的幀交叉了。
解決方案:
其原因就是發送中出現時間停頓,讓其他can設備有了可乘之機
,因此保證多幀之間在上一幀發送完畢立馬競爭總線進入下一幀發送就可以保證該包是連續發送的。以下是我的改進:
- 開啟郵箱按照填寫順序發送(而不是根據郵箱ID優先級發送)
- 一包多幀的數據持續塞滿三個郵箱,確保多幀發送過程中沒有出現三個郵箱都出現空的情況
在裸機的時候,其可以連續高幀率發送不出現亂幀,但是開啟FREERTOS后,還會出現亂幀的情況,其原因是can的發送中斷被freertos管理,需要把use freertos function關掉,使用裸機的中斷,我把其優先級設為1.
但是!還是有但是!我的freertos任務多了以后,還是出現亂幀的情況,檢查后發送,我的第一次填寫郵箱是在代碼里面進行的,也就是說我塞郵箱的過程中,freertos會打斷我塞數據的過程,導致有概率不是連續塞數據進去郵箱的。如圖,雖然我在代碼調用的發送中斷函數,但是其程序指針運行在psp下,而不是msp下,優先級就是普通的freerto任務,自然不能保證以高優先級連續塞數據進發送郵箱了。
改進為如下,分包好后,通過HAL_NVIC_SetPendingIRQ追加一個發送中斷,其不會執行發送過程就可以直接觸發發送中斷,這下子沒其他東西在打擾塞滿發送郵箱了吧!
總結:
經過測試,can總線每秒8000幀數據的情況下,有10%的錯誤率,檢查后發現,順序沒亂,有些幀沒能發送來就丟棄了,因為我設置的發送失敗不重發。降低速率至6000,1%內的錯誤率,幀沒發出現的數量大幅度下降,證明還是太快了。設置3000,0%錯誤率,為什么3000就是0%呢,看了一下can總線,發送我的每一包發送需要時間是1ms,一包大概3幀,也就是1s上限差不多是3000多幀。