华大 MCU 之七 DMA 导致 SPI 异常停止的原因分析、DMA 配置的那些坑
緣起
??在最近的項目測試中發現,SPI 通信總是莫名其妙的失敗,查看寄存器發現 SPI 已經被停止了。根據手冊,SPI 在異常情況下會被強制停止(SPI 的使能為被清零),而根據波形顯示通信過程沒有問題。下圖是我實際中的 DMA 及 SPI 使用情況:
問題分析
??最初懷疑是 SPI 的問題,因為在初始實現這部分功能時就遇到了很多坑,我也寫過博文華大 MCU 之五 SPI 從機 DMA 模式 配置(不能正常接收問題處理) 來專門記錄遇到的問題。但是再一次整理了一下 SPI 的配置流程,并沒有發現啥問題。在測試中發現,將 SPI2 使用的 DMA 停止,則不會出現問題,于是開始調查 DMA 的問題。
DMA 的坑
??最開始將問題重點放到了 DMA 的配置上,懷疑是不是 DMA 部分配置項不正確。但是,讀數情況下 SPI 是工作正常的,如果是配置不對,應該是一個必出現的問題。轉而又開始懷疑是不是配置時序(寄存器的配置的先后順序)不對,反復查看代碼也沒有發現問題。正在一籌莫展之時,有同事提出了手冊中 DMA 章節給出的一個注意事項:
??其實,最開始實現 SPI 驅動時就關注過該注意事項,只是開始的理解是,這條注意事項是針對同一通道而言的,同一通道在工作時不能再次配置上面說的這些寄存器,不同 DMA 通道之間應該互不影響。然而實際情況是,只要 DMA 有任意一個通道在傳輸數據,其他所有通道都不可以配置!
??這就導致了一個很大的問題,外設在工作中不可避免的要重新配置 DMA。例如,SPI 的 DMA 發送,由于發送數據長度是動態變化的,必須每次重新進行配置,則根據上面這一條,必須把該 DMA 下的其他通道(例如上面我的 SPI1 使用的通道)也都全部停止,這樣就可能導致其他外設丟失數據。
??最麻煩的是,這個問題沒有找到任何其他的解決方法,只能是停止該 DMA 下的所有通道,進而來配置自己需要的那個通道參數。起初在尋找解決方法的時候,也考慮是不是可以用下圖所示的寄存器位來進行一下判斷,而是實際是下面的位根本沒有任何用處。
還是以我上面的使用示例來說,SPI2 作為從機接收,由于使用了 DMA,MCU 并不能確定數據何時到來。即使 MCU 檢測 DMAACT 未動作,可能在實際配置通道時,DMA 又變為了動作狀態。
配置
??根據手冊,使用 DMA 時需要先寫寄存器將 DMA 控制器使能,使能方法是寫 DMA 使能寄存器 DMA_EN.EN 位。 如下圖所示:
我試了一下,不先使能貌似也沒法發現啥問題啊!不知道為啥!?
無法獲取當前傳出數據長度
??先來說一下需求:在串口驅動中,串口的接收使用 DMA 來實現,DMA 配置為循環模式,在指定緩沖區中循環存放收到的數據,通過讀寫指針來標記數據的讀和寫位置。
??然而,驅動庫中 DMA 接口并沒有能獲取當前 DMA 傳輸了多少字節的接口!!!無奈只能選擇修改驅動庫,添加一些指定的接口,如下圖所示:
??后來,為了不修改驅動庫,我直接把接口放到了自己的驅動里面,然后使用寄存器直接讀取:M4DMA1->MONRPT0_f.DRPT,這樣的話,需要注意與通道號的對應關系,如 MONRPT0 即通道 0。
中斷的使用
??在華大的 DMA 中,中斷默認都是開啟的,這點在配置 DMA 的時候需要特殊注意。我們需要使用 DMA 的屏蔽中斷寄存器來屏蔽不使用的中斷。如下圖示:
在實際寫代碼時,需要調用 en_result_t DMA_DisableIrq(M4_DMA_TypeDef* pstcDmaReg, uint8_t u8Ch, en_dma_irq_sel_t enIrqSel); 來關閉不需要的中中斷。例如,DMA 的塊傳輸完成中斷 和 傳輸完成中斷 通常不會一起使用!這點對于用慣了 ST MCU 的人來說需要特殊注意!
結論
參考
總結
以上是生活随笔為你收集整理的华大 MCU 之七 DMA 导致 SPI 异常停止的原因分析、DMA 配置的那些坑的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux 之五 最新 2021 一图看
- 下一篇: Linux 之七 SSH、SSL、Ope