愛伊米

什麼是DMA?STM32如何配置DMA?

一、DMA簡介

1、DMA簡介

DMA(Direct Memory Access:直接記憶體存取)是一種可以大大減輕CPU工作量的資料轉移方式。

CPU有轉移資料、計算、控制程式轉移等很多功能,但其實轉移資料(尤其是轉移大量資料)是可以不需要CPU參與。比如希望外設A的資料複製到外設B,只要給兩種外設提供一條資料通路,再加上一些控制轉移的部件就可以完成資料的複製。

DMA就是基於以上設想設計的,它的作用就是解決大量資料轉移過度消耗CPU資源的問題。有了DMA使CPU更專注於更加實用的操作——計算、控制等。

2、DMA的工作原理

DMA的作用就是實現資料的直接傳輸,而去掉了傳統資料傳輸需要CPU暫存器參與的環節,主要涉及四種情況的資料傳輸,但本質上是一樣的,都是從記憶體的某一區域傳輸到記憶體的另一區域(外設的資料暫存器本質上就是記憶體的一個儲存單元)。四種情況的資料傳輸如下:

外設到記憶體

記憶體到外設

記憶體到記憶體

外設到外設

當用戶將引數設定好,主要涉及源地址、目標地址、傳輸資料量這三個,DMA控制器就會啟動資料傳輸,傳輸的終點就是剩餘傳輸資料量為0(迴圈傳輸不是這樣的)。換句話說只要剩餘傳輸資料量不是0,而且DMA是啟動狀態,那麼就會發生資料傳輸。

3、DMA是否影響CPU的執行

在X86架構系統中,當DMA運作時(假設我們從磁碟複製一個檔案到隨身碟),DMA實際上會佔用系統匯流排週期中的一部分時間。也就是說,在DMA未開啟前,系統匯流排可能完全被CPU使用;當DMA開啟後,系統匯流排要為DMA分配一定的時間,以保證DMA和CPU同時運作。那麼顯然,DMA會降低CPU的執行速度。

在STM32控制器中,晶片採用Cortex-M3架構,匯流排結構有了很大的最佳化,DMA佔用另外的匯流排,並不會與CPU的系統匯流排發生衝突。也就是說,DMA的使用不會影響CPU的執行速度。

二、STM32的DMA結構

1、DMA的主要特性

● 12個 獨立的可配置的通道(請求)DMA1有7個通道,DMA2 有5個通道

● 每個通道都直接連線專用的硬體DMA請求,每個通道都同樣支援軟體觸發。這些功能透過

軟體來配置。

● 在七個請求間的優先權可以透過軟體程式設計設定(共有四級:很高、高、中等和低),假如在相

等優先權時由硬體決定(請求0優先於請求1,依此類推) 。

● 獨立的源和目標資料區的傳輸寬度(位元組、半字、全字),模擬打包和拆包的過程。源和目標

地址必須按資料傳輸寬度對齊。

● 支援迴圈的緩衝器管理

● 每個通道都有3個事件標誌(DMA 半傳輸,DMA傳輸完成和DMA傳輸出錯),這3個事件標誌邏輯或成為一個單獨的中斷請求。

● 儲存器和儲存器間的傳輸

● 外設和儲存器,儲存器和外設的傳輸

● 快閃記憶體、SRAM 、外設的SRAM 、APB1 APB2和AHB外設均可作為訪問的源和目標。

● 可程式設計的資料傳輸數目:最大為65536

下面為功能框圖:

什麼是DMA?STM32如何配置DMA?

2、兩個DMA控制器結構

DMA1 controller

什麼是DMA?STM32如何配置DMA?

DMA2 controller

什麼是DMA?STM32如何配置DMA?

3、DMA暫存器列表

中斷類

DMA_ISR:DMA中斷狀態暫存器

DMA_IFCR:DMA中斷標誌位清除暫存器

說明:DMA1、DMA2分別有一組暫存器。

控制傳輸類

DMA_CCRx:DMA通道x配置暫存器

DMA_CNDTRx: DMA通道x資料數量暫存器

DMA_CPARx: DMA通道x外設地址暫存器

DMA_CMARx:DMA通道x記憶體地址暫存器

說明:

每一個通道都有一組暫存器。

DMA_CPARx、DMA_CMARx是沒有差別的,它們都可以存放外設的地址、記憶體的地址。DMA_CPARx、DMA_CMARx只不過起得名字有差別而已。

4、STM32的DMA工作特點

DMA進行資料傳輸的必要條件

剩餘傳輸資料量大於0,DMA通道傳輸使能通道上DMA資料傳輸有事件請求前兩者都好理解,對於第三點確實需要詳細的解釋,請看下邊的三條。

外設到XX方向的傳輸

假設是ADC到儲存器的資料傳輸,顯然ADC的DMA傳輸的源地址是ADC的資料暫存器。並不是說只要DMA通道傳輸使能後,就立即進行資料傳輸。只有當一次ADC轉化完成,ADC的DMA通道的傳輸事件有效,DMA才會從ADC的資料暫存器讀出資料,寫入目的地址。當DMA在讀取ADC的資料暫存器時,同時使ADC的DMA通道傳輸事件無效。顯然,要等到下一次ADC轉換完成後,才能啟動再一次的資料傳輸。

儲存器對XX的DMA傳輸

因為資料是準備好的,不像ADC還需要等待資料到位。所以,不需要對應通道的事件。只要使能DMA資料傳輸就一直傳輸,直到達到設定的傳輸量。

example:

1。記憶體到記憶體,DMA傳輸請求一直有效

2。記憶體到串列埠,DMA傳輸請求一直有效

一種解釋:儲存器對儲存器的置位,就相當於相應通道的事件有效。對應通道的事件有效和儲存器對儲存器的置位,就是傳輸的觸發位。每次傳輸的事件置位一次,完成一次傳輸。如果是由外設引發的DMA傳輸,則傳輸完成後,相應傳輸事件會置為無效,而儲存器對儲存器的傳輸,則一次傳輸完成後,相應事件一直有效,直至完成設定的傳輸量。

外設以DMA方式工作時,能否再以軟體方式進行操作?

有一點是肯定的,當外設以DMA方式正在資料傳輸時,不可能再相應CPU的軟體控制命令,否則這不符合邏輯。

但是,倘若外設僅僅配置成DMA工作方式,但是DMA請求並未產生,資料傳輸並沒有進行。此時,軟體控制命令仍然能夠對外設進行控制。這是筆者在串列埠以DMA方式傳送資料情形下,所得到的測試結論。

三、STM32的DMA軟體程式設計

1、“記憶體到記憶體”模式傳輸

初始化配置

uint8_t SendBuff[SENDBUFF_SIZE];

uint8_t ReceiveBuff[RXBUFF_SIZE];

/**

* @brief USART1 TX DMA 配置,記憶體到記憶體

* @param 無

* @retval 無

*/

void DMA_Mem2Mem_Config(void)

{

DMA_InitTypeDef DMA_InitStructure;

/*開啟DMA時鐘*/

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

/*設定DMA源地址*/

DMA_InitStructure。DMA_MemoryBaseAddr = (uint32_t)SendBuff;

/*設定DMA目的地址*/

DMA_InitStructure。DMA_PeripheralBaseAddr = (uint32_t)ReceiveBuff;

/*方向:從記憶體SendBuff到記憶體ReceiveBuff*/

DMA_InitStructure。DMA_DIR = DMA_DIR_PeripheralDST;

/*傳輸大小DMA_BufferSize=SENDBUFF_SIZE*/

DMA_InitStructure。DMA_BufferSize = SENDBUFF_SIZE;

/*ReceiveBuff地址自增*/

DMA_InitStructure。DMA_PeripheralInc = DMA_PeripheralInc_Enable;

/*SENDBUFF_SIZE地址自增*/

DMA_InitStructure。DMA_MemoryInc = DMA_MemoryInc_Enable;

/*ReceiveBuff資料單位*/

DMA_InitStructure。DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

/*SENDBUFF_SIZE資料單位*/

DMA_InitStructure。DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;

/*DMA模式:正常模式*/

DMA_InitStructure。DMA_Mode = DMA_Mode_Normal ;

/*優先順序:中*/

DMA_InitStructure。DMA_Priority = DMA_Priority_Medium;

/*使能記憶體到記憶體的傳輸 */

DMA_InitStructure。DMA_M2M = DMA_M2M_Enable;

/*配置DMA1的4通道*/

DMA_Init(DMA1_Channel4, &DMA_InitStructure);

/*失能DMA1的4通道,一旦使能就開始傳輸*/

DMA_Cmd (DMA1_Channel4,DISABLE);

}

DMA中斷配置

/**

* @brief DMA 中斷配置

* @param 無

* @retval 無

*/

void DMA_NVIC_Configuration(void)

{

NVIC_InitTypeDef NVIC_InitStructure;

/* 配置中斷源 */

NVIC_InitStructure。NVIC_IRQChannel = DMA1_Channel4_IRQn;

NVIC_InitStructure。NVIC_IRQChannelPreemptionPriority = 1;

NVIC_InitStructure。NVIC_IRQChannelSubPriority = 1;

NVIC_InitStructure。NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

/* 配置DMA傳送完成後產生中斷 */

DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);

}

啟動傳輸

DMA_Cmd (DMA1_Channel4,ENABLE);

2、利用DMA實現迴圈傳輸

方法1:單次傳輸模式

當傳輸結束時,觸發DMA中斷,在中斷程式中首先失能DMA通道,然後修改該通道的傳輸資料量。最後重新使能DMA通道,注意只有失能的DMA通道才能成功修改傳輸資料量。

方法2:迴圈傳輸模式

當傳輸結束時,硬體自動會將傳輸資料量暫存器進行重灌,進行下一輪的資料傳輸。

四、再談STM32的DMA傳輸是否影響CPU的執行速度

宣告:經過筆者測試,當DMA工作在記憶體到外設的傳輸和記憶體到記憶體的傳輸時,都不會影響CPU的執行速度。為了給這種現象一個合理的解釋,筆者做以下猜測:

1、S3C2440的DMA傳輸

S3C2440的SDRAM是外接的,並且SDRAM的資料線、地址線、控制線總共只有一組。假設DMA傳輸的方向是記憶體到外設,當DMA運作時,需要佔用SDRAM的三類線才才能實現傳輸;而與此同時CPU也需要透過這三類線來訪問SDRAM來讀取程式、讀寫資料。

顯然,DMA的執行與CPU的執行有交叉點,DMA就會影響到CPU的執行。

2、STM32的DMA傳輸

STM32與S3C2440的區別是很大的,S3C2440是微處理器,RAM外接且空間很大;STM32是微控制器,RAM片內整合且空間較小。此時,ST公司就有可能提升DMA的運作效率,使DMA的工作不影響到CPU的執行。

外設與外設之間的DMA傳輸,因為與CPU的執行沒有交叉點(CPU的資料流注意是在Flash、記憶體、暫存器中傳輸),所以不會影響CPU的執行速度。唯一有可能影響的是外設與記憶體或者記憶體與記憶體之間的DMA傳輸。

倘若ST公司的SRAM是一個雙口RAM,也就是同時可以由兩組介面對RAM進行訪問,就可以很好的解決速度影響問題。倘若CPU恆定佔有一組介面,而另一組介面留給DMA控制器。那麼當外設與記憶體或者記憶體與記憶體之間的DMA傳輸時,由於不與CPU的訪問SRAM介面衝突,所以可以解決速度影響問題。

但其實偶爾還是會影響的,當CPU訪問SRAM的空間和DMA訪問SRAM的空間相同時,SRAM勢必會對這種情況進行仲裁,這可能會影響到CPU的訪問SRAM的速度。其實,這種情況的機率也是很小的,所以即使影響CPU的執行速度,也不會很大。