大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家介紹的是i.MXRTxxx下各通信外設驅動對DMA鏈式傳輸支持情況。
文接上篇《在i.MXRTxxx下使能DMA鏈式傳輸可達到SPI從設備接收速率上限50Mbps》,當我們實現了 DMA 鏈式傳輸後:這裏又分為兩種情況,一種是靜態 DMA 鏈式傳輸,另一種是動態 DMA 鏈式傳輸。
所謂靜態 DMA 鏈式,就是在啓動 DMA 傳輸前把所有鏈表一次性全配置好,傳輸過程中不再修改鏈表。而動態 DMA 鏈式,則是在傳輸過程中動態地配置鏈表,比如在一個鏈表傳輸完成後,再添加下一個鏈表。
靜態 DMA 鏈式適用於需要預先知道全部傳輸數據的場景,如固定大小的數據塊傳輸,或者先緩存後處理的場景(比如 ping-pong buffer 方式收數據,再將數據從 buffer 搬移到目的地址);動態 DMA 鏈式則更適合處理長度可變或實時生成的數據流,或者目標地址可變且無需 buffer 緩存的場景(比如直接讓 DMA 將數據存到變化的目標地址),提供更靈活的數據傳輸方式。
今天痞子衡就和大家聊一聊動態 DMA 鏈式傳輸使能過程中的一個小誤區,以及當前版本 SDK 下各通信外設 DMA 版本驅動對於鏈式傳輸的支持情況:
一、由使能SPI動態DMA鏈式傳輸發現的問題
回到痞子衡支持 RT600 AR 眼鏡客户的應用場景,RT600 作為 SPI 從設備接收數據,為了實現最高 50MHz SPI 傳輸,我們必須使能 DMA 鏈式傳輸,保證在一包數據傳輸過程中不能出現間隔(比如一包數據是 4KB,而一次 DMA 傳輸 1KB,那麼就需要 4 次 DMA 傳輸)。
為了實現連續無間隔的 4 次 DMA 傳輸,既可以用靜態 DMA 鏈式,也可以用動態 DMA 鏈式,為了便於描述兩者差別,這裏痞子衡用了 4 個 DMA 描述符示例(實際 2 個 DMA 描述符頭尾相連組成 ping-pong 傳輸就可以了)。
靜態 DMA 鏈式傳輸情況下,我們先要將 DMA 描述符 0,1,2,3串起來,然後再啓動 DMA 傳輸。而動態 DMA 鏈式傳輸情況時,我們是先串了 DMA 描述符 0,1,然後就直接啓動了 DMA 傳輸,在每次 DMA 傳輸結束時,再將下一個未鏈接的 DMA 描述符按序串上去。
在這個 AR 眼鏡客户應用場景裏,RT600 從 SPI 接收的數據是在 SRAM 執行的程序固件,其有指定內部 SRAM 存放地址,而且在每包數據傳輸過程中還涉及 CRC 校驗,如果校驗出錯需要重新傳輸這一包數據。綜合考慮,痞子衡選擇了 DMA 動態鏈式傳輸方案,直接用 DMA 將數據放到目的 SRAM 地址,所以必須動態配置 DMA 描述符,因為每個描述符裏目標地址需要更新。
在改造 SDK 裏的 fsl_spi_dma 驅動(v2.2.2)時,痞子衡發現了一個隱藏的誤區,該驅動基於公共 DMA 函數 DMA_SubmitTransfer() 來創建一個 DMA 描述符,這個函數設計上完全是為了非鏈式傳輸,其僅能在 DMA 處於空閒狀態才能被調用(根據 DMAx->COMMON[0].ACTIVE 寄存器),這麼做的主要原因是函數最後會設置 DMAx->CHANNEL[n].XFERCFG 寄存器,而這個決定 DMA 傳輸配置的最重要寄存器 XFERCFG 在 DMA 傳輸期間不能夠重新設置,哪怕相同的值再次寫入也不行,一旦發生寫入行為,DMA 會發生異常從而立即停止工作。
二、各通信外設對DMA鏈式傳輸支持情況
在 RT600 上支持 DMA 傳輸的通信類外設有很多,這些外設在 SDK 裏大多數既有普通驅動,也有 DMA 版本驅動。痞子衡將全部驅動和例程均看了一遍,做了一個總結。原則上每個外設 DMA 版本驅動均可以做到支持鏈式傳輸,但目前 SDK 裏的各外設 DMA 驅動實現並不一致,原因可能跟該外設自身應用特點有關。比如音頻類外設 I2S 和 DMIC 就很適合做鏈式傳輸,因為它們數據流必須是連續的,否則 record_playback 場景下音頻會出現雜音。
由於這些外設驅動並不是同一個人寫成的,因此代碼風格各不相同,其中關於 DMA 鏈式傳輸實現,痞子衡最喜歡 fsl_i2s_dma 這個驅動,想要為 USART/SPI/I2C 添加 DMA 鏈式傳輸支持的朋友不妨參考這個驅動。
- Note:下表是以 SDK_25_09 版本代碼為準
| 外設類型 | 有無DMA版本驅動 | DMA版本驅動是否支持鏈式傳輸 | 基於DMA的例程 |
|---|---|---|---|
| FC USART | 有 | 否 | dma_low_power
dma_transfer 單次傳輸 dma_double_buffer_transfer 鏈式傳輸 |
| FC SPI | 有 | 否 | dma_b2b_transfer 單次傳輸 |
| FC I2C | 有 | 否 | dma_b2b_transfer 單次傳輸 |
| FC I2S | 有 | 是 | dma_transfer 鏈式傳輸
dma_transfer_tfa9xxx 鏈式傳輸 dma_record_playback 鏈式傳輸 |
| I3C | 有 | 是 | 無 |
| DMIC | 有 | 是 | dmic_dma 單次傳輸
dmic_i2s_dma 鏈式傳輸 dmic_multi_channel 鏈式傳輸 |
| FLEXSPI | 有 | 是 | dma_transfer 鏈式傳輸 |
| eSPI | 無 | N/A | N/A |
至此,i.MXRTxxx下各通信外設驅動對DMA鏈式傳輸支持情況痞子衡便介紹完畢了,掌聲在哪裏~~~
歡迎訂閲
文章會同時發佈到我的 博客園主頁、CSDN主頁、知乎主頁、微信公眾號 平台上。
微信搜索"痞子衡嵌入式"或者掃描下面二維碼,就可以在手機上第一時間看了哦。