喜歡用STM32的DMA功能。一方面STM32的DMA和MPU的DMA一樣,可以提高資料傳輸效率。另一方面,作為一種MCU上的DMA,它可以提高針對外設(peripheral)的資料傳輸的實時性,改變了傳統MCU只能用定時中斷實現實時控制的方法。
比較STM32F4和STM32F1系列的DMA控制器,可以發現區別主要有三:1)增加了DMA流(Stream)的概念;2)限制了兩個DMA控制器的資料流向;3)為每個資料流新增了可配置的FIFO緩衝區。
本文逐一比較了以上三種硬體上的改變帶來的功能方面的升級和不同。另外,還大膽猜測了STM32的晶片設計者對DMA的工作機制和場景的構想。以下原創內容歡迎網友轉載,但請註明出處: https://www.cnblogs.com/helesheng
1. 增加DMA流(Stream)的概念
1.1 不同之處
我認為STM32F4的DMA控制器的流(Stream)雖然是新增的,但可以理解為只是對原有通道(Channel)概念的細化和擴充套件,新增的只是“概念”而非實體。請大家對比兩個系列資料手冊中的DMA1傳輸請求表。
圖1 STMF1系列DMA1控制器的外設傳輸請求表
圖2 STMF4系列DMA1控制器的外設傳輸請求表
可以發現,兩個系列DMA1可以響應的外設的傳輸請求,都是可以表示為二維的矩形表格。由於外設種類和路數也相差不大,可以想象STM32F1和STM32F4兩類控制器的DMA1和DMA2所能管理的外設傳輸請求種類和總數數也相差不大。不同點在於:STM32F4將原來STM32F1中以列方式存在的“通道x”傳輸請求轉換成了行的方式,替代了STM32F1表格中每行所對應的某種具體外設;STM32F4的表格中同時還將現在的每一列取了一個新的名字流(stream)。由於兩個表格中沒有增加“實體”,所以我才認為新增的只是流這個“概念”本身。
但“流”這個概念的增加,卻使得STM32F4程式設計師可以透過軟體指定流和通道的具體編號,定位表格中的某一個確切的傳輸請求。而不像STM32F1只能指定某一通道,而無法進一步在圖1表格中定位傳輸請求來一列中的那個具體外設。也就是說在STM32F1中,每當發生外設引發的DMA傳輸請求時,程式設計師只能確定該傳輸請求來自圖1表格中某一列中的任何一個外設,而無法像在STM32F4中一樣定位到表格中的任意具體位置的外設。這意味著,STM32F1的程式設計師無法同時使用表格一列中的兩種以上外設傳輸請求,而STM32F4卻可以。
1.2 對STM32外設DMA工作機制理解的深化
1)對比的兩種DMA 外設請求組織的形式,給我個人最大的啟示在於進一步深刻的意識到:圖1、圖2表格中的外設只是DMA的傳輸“請求”(require),而非傳輸資料來源(source)或目標(destination)。DMA外設資料的傳輸是由表格指定的外設動作“引發”,但傳輸資料來源或目標可以和產生傳輸請求的外設完全無關。
例如,需要用STM32F4的DMA控制SPI1持續地間隔1ms傳送資料,就需要選擇能夠定時1ms的某個定時器(此處不妨選擇TMR3)作為DMA的外設傳輸請求,檢視圖2得到對應的通道和流為DMA1_STREAM2_CH5。但在對DMA1_STREAM2_CH5的傳輸引數進行配置的時候,卻需要指定以SPI1的資料暫存器地址作為傳輸目標,待傳送資料儲存區地址號作為傳輸資料來源。
這種“傳輸請求”和“傳輸源和目標”分離的DMA工作機制其實在STM32F1中就一直存在,但手冊中圖1表格每行開始的“外設”一列很容易讓人產生“傳輸源”和“傳輸源/目標”只能是一種外設的誤解。
2)傳輸模式中可以選擇“外設到記憶體/記憶體到外設”或“儲存器到儲存器”兩種型別的區別,僅僅在於DMA控制器啟動一次資料傳輸,是需要等到下一次外設的傳輸(require)請求到來(“外設到記憶體/記憶體到外設”模式);還是可以在一次傳輸完成之後不用等待指定外設的傳輸請求,直接啟動DMA傳輸(“儲存器到儲存器”模式)。
例如,當用FSMC介面擴充套件了一個高速並行介面DAC,需要定時地向FSMC並行介面寫入資料,以產生指定波形。該應用需要定時用DMA向FSMC擴充套件DAC的地址傳輸資料。雖然DMA資料來源和目標都是儲存器地址(記憶體和FSMC),但配置DMA時還必須選擇“記憶體到外設”或“外設到記憶體模式”。應為如果配置為“儲存器到儲存器”模式,則會導致DMA用自己最快的速度完成資料的傳輸,而不會等到定時器到取樣間隔後再輸出資料。
根據我自己對上述DMA工作機制的加深理解,我“解鎖”了GPIO高速同步資料傳輸的“新技能”,將在下一篇博文中展示用DMA 和STM32F4的高速GPIO(AHB匯流排)實現對獨立10MSPS ADC的控制方法和程式碼,歡迎大家捧場!
2. 分別限制了兩個DMA控制器的資料流向
2.1 不同之處
STM32F1系列除了在圖1的表格中指定了每個通道的DMA請求外設之外,並沒有限制兩個DMA控制器的資料來源和目標源種類。但STM32F4卻透過下圖指定了兩個DMA控制器的資料來源和目標源的種類。
圖3 STM32F4系列兩個DMA控制器埠(源和目標)連線的外設/儲存器種類
我自己初次看到這張圖並沒有什麼太深的感觸,但隨著對STM32F4的DMA使用經驗的增加,會發現這張圖對於DMA1和DMA2兩個控制器的選擇,有著重要的影響。
例如,要想實現片上SRAM儲存器到片上SRAM儲存器的資料搬運,你會發現STM32F4只能使用DMA2控制器——因為DMA1靠下的埠被固定連線到APB1的資料埠上,無法實現SRAM到SRAM的資料傳輸。
又如,要實現上文提到的片上SRAM和GPIO之間的高速資料同步傳輸,由於STM32F4的GPIO被連線到AHB1上,而連線到AHB1的資料埠只被連線到了DMA2的兩個埠,所以也只能選用DMA2控制器來實現SRAM和GPIO之間的高速資料同步傳輸。
2.2 怎樣選擇STM32F4中的DMA控制器、流和通道
在實際使用STM32F4中的DMA時,需要根據具體應用的要求的傳輸源和目標的硬體型別和種類,查詢圖3來確定DMA1或DMA2,舉例說明:
要將Flash中的100位元組資料透過USART2(串列埠2)傳送出去。由於USART屬於慢速裝置,傳送速率遠低於Flash儲存器的讀取速度。用DMA匹配二者“產生”和“消費”資料的速度,實現速度匹配的方法一般有兩種:
連續傳送法:USART2並在其每傳送完一個位元組後,由USART2傳送完成事件觸發下一次DMA資料傳輸。此時只能選擇“儲存器到外設”的工作模式,而DMA傳輸請求為“USART2傳送完成”,在圖2表格中找到USART2_TX在DMA1控制器資料流6通道4。反過來在圖3中核查一下DMA1是否有能力實現所需的資料傳輸:USART2屬於APB1匯流排上的外設(參加下圖4中的STM32F40x內部匯流排結構),可以使用圖3中DMA1靠下的埠,而DMA1另一靠上的埠的灰色連線可以連線到Flash的DCODE匯流排。因此使用DMA1_STREAM6_CH4可以實現這種要求的資料傳輸。
圖4 STM32F40x內部結構框圖
定時傳送法:每間隔一段時間t(長於USART2傳送一個位元組的時間,如10ms)USART2向外傳送一個位元組,傳送完成後USART2空閒,一直等到下一個t開始在向外傳送下一個位元組。也就是DMA向USART2的傳送資料暫存器傳輸資料的動作由其他定時器TMR來觸發。此時可以選擇“儲存器到外設”或“外設到儲存器”模式,但不能選擇“儲存器到儲存器”模式。DMA傳輸請求可以是任意TMR的計數器更新事件。當然在啟動DMA之前,還需要將TMR3的時基配置為10ms溢位一次。最後,在圖1或下圖5所示的STM32F4的DMA2外設傳輸請求表中選擇任意空閒的TMR更新事件。不失一般性,我選擇圖1中DMA1_STREAM2_CH5中的TMR3更新作為DMA傳輸請求。最後,同樣需要在圖3中核查一下DMA1是否有能力實現所需的資料傳輸,器過程和上一種同步方法相同,這裡不再贅述。
圖5 STMF4系列DMA2控制器的外設傳輸請求表
3. 每個資料流(STREAM)增添了先進先出的緩衝FIFO
3.1 DMA FIFO的作用
STM32F4為每個DMA資料流新增了獨立的四級,每級32位的先進先出緩衝區FIFO。可以看到有網文介紹DMA FIFO能夠提升DMA資料傳輸的頻寬,防止外設資料由於匯流排繁忙造成丟失——理由是外設資料的傳輸需求,只受DMA傳輸請求控制,傳輸請求到來時,由於系統匯流排繁忙,理論上有可能造成外設資料的丟失。但我個人認為,STM32F4屬於微控制器MCU,一般常見應用不會涉及高頻寬的純資料傳輸;而外設的DMA資料傳輸頻寬都不會太大,因此需要用FIFO提升DMA頻寬和可靠性的情況很少。在搜尋引擎和大模型中搜尋基本很少看到DMA FIFO的應用例項,就是這一結論的旁證。
我個人認為STM32F4的DMA FIFO的作用主要在於實現DMA源和目標資料寬度不等情況下的轉換和傳輸,以及DMA的突發傳輸(burst transfers)。而這兩個功能都是STM32F1系列DMA不具備的。
3.2 實現資料寬度不同的源與目標間的緩衝和轉換
DMA的源和目的是不同的外設和儲存器,當二者的資料寬度不同時,對於DMA控制器而言就會出現資料“生產”和“消費”速度不等的問題。為使二者相等,資料寬度較小的一側所需的傳輸次數就必須多於資料較寬的一側。DMA控制器就需要暫時緩衝資料寬度較窄一側前幾次傳輸來的資料,DMA FIFO就可以用於實現對這些資料的緩衝。
下圖6所示的就是兩側資料寬度不同時,FIFO中存放資料的順序。
圖6 資料寬度不同時,DMA FIFO中存放資料的結構
注意:左側資料寫入的順序是B0 -> B1 -> B2 -> B3 -> B4 -> B5 -> B6…… H0 -> H1 -> H2 -> H3 …… ;
而右側讀出資料的順序是W0 -> W1 -> W2 -> W3…… H0 -> H1 -> H2 -> H3 …… 。
可以看到資料在矩形的FIFO中儲存後,以列的形式從右側讀出,而兩側的資料傳輸次數都不相等。
當然FIFO還可以被設定為1-4的不同深度,從而使用圖5矩形中的1-4列儲存器。
3.3 實現DMA資料突發傳輸
所謂“突發傳輸”是指,一個DMA請求引發多次資料傳輸。當源和目標的資料寬度相等,源和目標的突發傳輸次數也相同時,DMA傳輸中資料“生產”和“消費”速度也相同,理論上就不需要FIFO來參與DMA的資料緩衝和傳輸。但源和目標的資料寬度,或突發傳輸次數只要有不同,就有可能造成資料“生產”和“消費”速度不相等,此時就必須有FIFO緩衝資料。STM32F4系列要求:只有當DMA FIFO開啟時,才允許資料突發傳輸。當然,兩側資料的寬度和兩側突發傳輸的次數的關係,必須滿足資料“生產”和“消費”速度相等的基本要求。