引言
考慮到DMA是一個AHB Master設備,可以同處理器內核一樣,主動向總線發起傳輸請求,將“小臟手”伸向各總線上掛載的各外設模塊,因此,我更愿意把DMA看做是處理器核心服務的一部分,甚至把它當成一個小核或者協處理器都不為過。
DMA可以在CPU之外,捕獲到觸發信號后,自行搬運數據從指定地址到另一個指定地址,并且還可以根據預先的配置自動計算下一次搬運的地址。使用DMA可以有效地節約CPU處理海量數據傳輸的負載。可以想見,如果使用中斷方式處理通過外設發送或者接收數據,CPU將會在頻繁切換中斷服務之間花費大量的時間。
另外,DMA從DMAMUX獲取的觸發源,能夠實現的自動讀寫的操作,若是某些讀操作或者寫操作能夠產生額外的觸發事件,還可以傳遞觸發,形成觸發鏈,最終可實現一些完全不需要硬件干預的自動化任務。總之,DMA真心是一個功能豐富的模塊。
本文將介紹YTM32平臺上DMA的工作機制,對關鍵概念展開講解。
簡介
YTM32(以YTM32B1ME05為例)微控制器上集成的DMA控制器可以支持16個通道,并且搭配了一個多達128個選項的DMA MUX模塊,可以對接任何一個通道。其中多個通道是復用同一個DMA控制器的,并且共用同一個數據搬運引擎。DMA MUX管理了可以觸發DMA通道的硬件事件,每款芯片可能都不一樣(YTM32B1MD14中的DMAMUX只有64個選項),在具體使用時,需要從具體的芯片手冊中查表。
還需要特別注意的是,目前YTM32平臺上的DMA尚未支持異步時鐘模式,它使用core clock驅動,僅能在普通模式下工作,在休眠模式、深度休眠以及更低功耗的休眠模式下,均停止工作。
本DMA控制器通過多個通道的傳輸任務描述符(CTS)管理搬運數據的過程,并且還支持鏈接模式,即將多個傳輸任務描述符連鏈接在一起,形成傳輸任務鏈。
原理與機制
DMA控制器是一個AHB總線主機,但仍同普通的外設一樣,作為一個APB總線從機,被配置成合適的工作模式。DMA控制器通過DMAMUX,可以直接收集來自片上其他外設模塊發出的觸發信號,進而觸發DMA在地址空間搬運數據的過程。如圖x所示。
圖x DMA控制器的系統框圖
需要注意的是,DMA的搬運過程是在地址空間內操作的,可以是從內存到內存,從外設到外設,在內存與外設之間等,對于DMA而言,只是搬數,至于數據映射到物理設備是外設還是內存,均由總線負責落實。
相對于有的DMA控制器將觸發信號和搬運數據源頭地址或目標地址綁定的設計,YTM32的DMA控制器將觸發信號和搬運任務所使用的地址相互獨立,例如,當某個定時器模塊產生的觸發信號觸發了DMA的一個搬運數據的任務(通道),這個任務可以將ADC轉換結果的數據搬運到內存中。這其中,定時器和ADC是沒有直接關聯的。
DMA通道的傳輸任務描述符
YTM32的DMA的各個通道,可以看做是各自獨立的傳輸任務,每個任務都有自己的觸發條件、對觸發條件的響應方式、搬運數據的源地址和目的地址、搬運數據的帶寬、搬運數據的數量、每次搬運完成后對搬運過程進行調整的策略等,如此看來,DMA控制器就是這些獨立任務的調度器,當多個任務被同時觸發時,以一定的調度策略安排他們依次運行。
DMA通道對應的這些獨立的搬運任務,在DMA引擎的建模中,被稱為CTS(DMA Channel Transfer Structure),其結構如圖x所示。
圖x DMA通道的傳輸任務描述符
這個結構的內容并不是以指針的方式存放在SRAM中,而是直接做在寄存器結構里,可以在DMA的寄存器清單中找到與之一一對映的寄存器。如圖x所示。
圖x CTS對應的每個通道各自下轄的一組寄存器
但CTS也可以存放在RAM中,若配置了DMA_CTS_CSR[RLDEN]=1
,則在大循環完成后,直接從寄存器DMA_CTS_DTO
(原來存放的是地址偏移量)存放的指針進行索引,搬運整個CTS結構體的內存覆寫到CTS對應的寄存器中。
除此之外,只是借鑒CTS結構中相關的寄存器,去配置DMA傳輸任務的參數即可,不必受限于CTS的抽象數據結構。
DMA的觸發信號
YTM32的DMA控制器為每個DMA搬運任務設計了兩種觸發方式:軟件觸發和硬件觸發。其中,軟件觸發可由CPU直接向DMA控制器的寄存器寫數(DMA_CTSn_CSR[START]
),主動啟動傳輸過程;硬件觸發使用預設的硬件觸發信號,當來自外設的硬件觸發信號通過DMAMUX到來之時,自動啟動DMA搬運任務開始搬數。DMA的每次觸發,執行一次小循環的搬運過程,一個大循環可以包含多個小循環的,因此一個大循環的搬運任務可能會需要多次觸發才能完成。(關于大小循環的概念,可見樓下)
- 軟件觸發
DMA的軟件觸發是通過軟件寫各通道的寄存器位DMA_CTSn_CSR[START]
,或者寄存器DMA_START
中對應通道的控制位實現的,每寫1次就發出一個觸發信號。每次觸發,執行一次小循環(one trigger loop)的搬運過程,TCNT寄存器中的計數器減1。
特別注意,軟件觸發是直接作用于DMA控制器的,不必配置DMAMUX的那個always_on
的選項。但由此也可知,哪怕有可用的硬件觸發通過DMAMUX輸入到DMA控制器,軟件觸發也可以生效。相當于是,軟件觸發和DMAMUX導入的硬件觸發信號相或,然后統一輸入到DMA控制器。
- 硬件觸發
DMA的硬件觸發信號來自于DMAMUX
,而DMAMUX
則可以從眾多觸發信號的源中選擇其中一個適用于某個指定的通道(寄存器DMA_CHMUXn
)。具體選項可在芯片手冊中查閱,如圖x所示。
圖x 從手冊中查閱DMAMUX選項
DMAMUX選中的觸發信號,還需要經過一個REQEN
的門控開關(寄存器DMA_REQEN
中對應通道的控制位),才能順利進入DMA引擎。因此,每次使用DMA開始傳輸之前,如果要使用外部的硬件觸發源,必須確保打開這個門控開關。另外,每個DMA通道的傳輸描述符中的寄存器位DMA_CTS_CSR[DREQ]=1
還可以控制在每個大循環傳輸完成之后,自動關閉這個門控開關。如果DMA_CTS_CSR[DREQ]=0
,則這個門控開關在大循環傳輸完畢后仍會保持打開。
這里提到的硬件觸發信號,是直接來自于外設的DMA觸發信號,通常會伴隨著這些外設的某些事件的發生,大多同時也可以觸發中斷。以LINFlexD為例,有對應的DMA觸發信號的開關,如圖x所示。
圖x SPI外設模塊的使能DMA請求控制位
DMA的大循環和小循環
一個最完整的DMA傳輸,可以包含多次觸發,而每次觸發,會引起連續地搬運一塊數據(可以是連續的多個字節)。以此,完整的DMA搬運有大循環(Major Loop)
和小循環(Minor Loop)
的概念,大循環包含小循環。
YTM32的手冊中使用了Transfer Loop
和Trigger Loop
的名字:
- Transfer loop means data transferred after one DMA channel trigger.
- Trigger loop means DMA channel could accept how many DMA channel triggers(include software and hardware trigger).
從手冊的描述中可以獲知,Transfer Loop
描述的是一次觸發(one trigger)執行的包含若干個transfer的搬運過程,而Trigger Loop
可以包含多個觸發(many triggers),對應大循環和小循環。如圖x所示。
圖x DMA搬數過程中的大循環和小循環
小循環搬運的字節數,由各DMA通道的BCNT
寄存器指定,它本身也是一個遞減計數器,每傳輸一個字節就減1,減到0時就停止搬運。
大循環的包含的小循環的次數(不是字節數,是對觸發信號的計數),由各DMA通道的TCNT_KDDIS[TCNT]
寄存器字段指定,它本身也是一個遞減計數器,每執行一次小循環(觸發)就減1,減到0時就停止。特別注意,此處的大循環管理的僅僅是觸發,而不是傳輸內存塊,如果使用多個傳輸任務描述符鏈接起來的傳輸任務描述鏈表,則每個任務描述符(可能在不同的地址塊和傳輸模式搬運數據)都對應屬于各自的觸發次數(同一個通道的觸發源仍為同一個)。
大循環執行一半和完畢時都有對應的標志位(DMA_CHTLHDIF
和DMA_CHTLDIF
),這里有個特別的設計,只有啟用DMA傳輸通道的大循環半完成和全完成的中斷時(DMA_CTS_CSR[THDINT]=1
和DMA_CTS_CSR[TDINT]=1
),這兩個標志位才會置位,否則哪怕對應的事件到來,也不會被置位。但另一個傳輸完成標志位(DMA_DONE
和DMA_CTS_CSR[DONE]
),無論是否開啟對應的中斷(DMA_CTS_CSR[LOOPINT]
),都能置位。這里就有一點小糾結了,如果同時啟動了DMA_CTS_CSR[LOOPINT]
和DMA_CTS_CSR[TDINT]=1
,DMA_DONE
和DMA_CHTLDIF
所對應的行為將完全一樣,那么在一個大循環完成后產生中斷,其中的服務程序就需要同時清零這兩個標志位。(這里的設計似乎有點冗余,有似乎缺了點什么。。。)
DMA搬運任務的地址更新策略
DMA外設設計了非常靈活的搬運地址更新策略,可以覆蓋最大范圍的應用場景。但需要整理清楚其中的概念和更新時機,才能玩轉DMA,否則,一不小心產生了錯誤的參數配置狀態,DMA也將會停止工作并報錯(DMA_ERS
)。
重申一次DMA搬數中的操作單元:
- 一次指定帶寬的總線傳輸被稱為一個搬運
Transfer
- 一次觸發可以發起一個或多個連續的
Transfer
,也可被稱為Transfer Loop
或者a loop of transfers
,這也對應文中描述的小循環Minor Loop
。 - 一組觸發可以包含一個或者多個連續的
Minor Loop
,也可被稱為Trigger Loop
或者a loop of triggers
,這對應文中描述的大循環Major Loop
。
以數據源地址指針為例(數據目標地址指針相同):
- 最初的數據地址存放在寄存器
DMA_CSR_SADDR
中。這個寄存器中的值也會隨著DMA搬運過程的執行變化,始終指向即將要搬運數據的地址。 - 預先配置
DMA_CTS_TCNT
寄存器的值大于等于1,表示本次DMA傳輸任務至少包含1次觸發產生的小循環。 - 一次觸發將啟動搬數過程。先從小循環走起。
- 每次總線傳輸搬運的數據長度(寬度),由寄存器
DMA_CSR_TCR[SSIZE]
配置,可以選擇1 Byte、2 Byte、4 Byte,以及16 Byte和32 Byte,這也代表了DMA使用數據總線的數據帶寬。每次搬運都是從當前的數據地址開始搬運帶寬指定數量的字節數。搬運過后,不對當前搬運數據地址產生影響,指針保持不變。 - 每次搬運執行后,可以由軟件指定一個地址偏移量,由寄存器
DMA_CSR_SOFF
配置,可以是正整數,也可以是負整數(地址向前跳)。這個偏移量是作用于當前搬運數據地址指針寄存器DMA_CSR_SADDR
的,當搬運執行后,當前地址指針將會加上這個偏移量,更新成新的地址指針。 - 如果有多次傳輸,則多次傳輸會連續執行。
DMA_CTS_BCNT
寄存器預置了本次小循環的需要數據的總長度(以字節為單位),而不是地址范圍(切記,地址有可能是不連續地跳躍)。DMA控制器內部會自動遞減DMA_CTS_BCNT
寄存器的數,但不會覆寫到DMA_CTS_BCNT
寄存器中,因為整個小循環的搬運過程是連續執行的,用戶看不到中間狀態。 - 當小循環完成后,可以有一個對源數據地址指針的偏移。然而,這里并沒有設計。
DMA_CTS_TCNT
寄存器的值減1,并覆寫到DMA_CTS_TCNT
寄存器中。如果值仍大于0,則說明當前的大循環任務還沒執行完,繼續等下一個觸發啟動一次小循環。如果值被減到0,說明大循環任務完成,此時,DMA_DONE
和DMA_CHTLDIF
(若開放中斷)都會置位,同時,DMA控制器還會更新兩個計數值:- 源數據指針在加上了最后一次搬運的偏移量(由寄存器
DMA_CSR_SOFF
配置)之后,還會立即繼續疊加一個大循環完成地址偏移,由寄存器DMA_CSR_STO
配置,這也是一個可正可負的整數。計算的結果會覆寫到寄存器DMA_CSR_SADDR
中。 - 將
DMA_CTS_TCNTRV
寄存器中預存的重載值覆寫到DMA_CTS_TCNT
寄存器中,以便于啟動下次任務時無需重新配置這些計數器和地址指針。
說起來,個人覺得,如果設計小循環結束后有一個地址偏移,比實現大循環結束后的地址偏移更加直觀一些。大循環專門管理觸發(管理觸發的遞減和循環),小循環管理指針(地址的遞減和遞增等),分工相對更明確些。這里實現的大循環的一次性偏移,也可以等價實現為等分到每次小循環之后的地址偏移。
讀者可以自行進行實驗,觀察DMA寄存器中各計數器的變化。
圖x 利用Keil的寄存器調試界面調試
DMA控制器還支持Scatter Gather模式,將多個DMA傳輸任務串聯在一起,可以實現地址不規則的連續傳輸。在地址增長模式上,還有個回環遞增的模式可以用。可以在具體用到的時候再深究。手冊上的描述比較簡略,屆時仍需要用戶發揮主觀能動性,大膽猜想多做嘗試。
應用要點(軟件)
-
定時器
+關注
關注
23文章
3237瀏覽量
114467 -
協處理器
+關注
關注
0文章
75瀏覽量
18155 -
AHB總線
+關注
關注
0文章
18瀏覽量
9469 -
DMA控制器
+關注
關注
1文章
43瀏覽量
12265 -
SRAM存儲器
+關注
關注
0文章
88瀏覽量
13275
發布評論請先 登錄
相關推薦
評論