博客 / 詳情

返回

痞子衡嵌入式:在i.MXRTxxx下使能DMA動態鏈式傳輸誤區及各外設驅動對DMA鏈式支持情況


  大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家介紹的是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主頁、知乎主頁、微信公眾號 平台上。

微信搜索"痞子衡嵌入式"或者掃描下面二維碼,就可以在手機上第一時間看了哦。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.