STM32 DMA模塊的配置與使用


DMA有什么用?

       直接存儲器存取用來提供在外設和存儲器之間或者存儲器和存儲器之間的高速數據傳輸。無須CPU的干預,通過DMA數據可以快速地移動。這就節省了CPU的資源來做其他操作。

有多少個DMA資源?

       有兩個DMA控制器,DMA1有7個通道,DMA2有5個通道。

數據從什么地方送到什么地方?

       外設到SRAM(I2C/UART等獲取數據並送入SRAM);

       SRAM的兩個區域之間;

       外設到外設(ADC讀取數據后送到TIM1控制其產生不同的PWM占空比);

       SRAM到外設(SRAM中預先保存的數據送入DAC產生各種波形);

       ……還有一些目前還搞不清楚的。

DMA可以傳遞多少數據?

       傳統的DMA的概念是用於大批量數據的傳輸,但是我理解,在STM32中,它的概念被擴展了,也許更多的時候快速是其應用的重點。數據可以從1~65535個。

直接存儲器存取(Direct Memory Access,DMA)是計算機科學中的一種內存訪問技術。它允許某些電腦內部的硬體子系統(電腦外設),可以獨立地直接讀寫系統存儲器,而不需繞道 CPU。在同等程度的CPU負擔下,DMA是一種快速的數據傳送方式。它允許不同速度的硬件裝置來溝通,而不需要依於 CPU的大量中斷請求。【摘自Wikipedia】

現在越來越多的單片機采用DMA技術,提供外設和存儲器之間或者存儲器之間的高速數據傳輸。當 CPU 初始化這個傳輸動作,傳輸動作本身是由 DMA 控制器 來實行和完成。STM32就有一個DMA控制器,它有7個通道,每個通道專門用來管理一個或多個外設對存儲器訪問的請求,還有一個仲裁器來協調各個DMA請求的優先權。

DMA 控制器和Cortex-M3核共享系統數據總線執行直接存儲器數據傳輸。當CPU和DMA同時訪問相同的目標(RAM或外設)時,DMA請求可能會停止 CPU訪問系統總線達若干個周期,總線仲裁器執行循環調度,以保證CPU至少可以得到一半的系統總線(存儲器或外設)帶寬。

在發生一個事件后,外設發送一個請求信號到DMA控制器。DMA控制器根據通道的優先權處理請求。當DMA控制器開始訪問外設的時候,DMA控制器立即發送給外設一個應答信號。當從DMA控制器得到應答信號時,外設立即釋放它的請求。一旦外設釋放了這個請求,DMA控制器同時撤銷應答信號。如果發生更多的請求時,外設可以啟動下次處理。

簡單來說:

DMA,全稱為:Direct Memory Access,即直接存儲器訪問。DMA傳輸方式無需CPU 直接控制傳輸,也沒有中斷處理方式那樣保留現場和恢復現場的過程,通過硬件為RAM 與I/O設備開辟一條直接傳送數據的通路,能使CPU 的效率大為提高。
       STM32中 DMA1有7個通道,DMA2有5個通道(DMA2 僅存在大容量產品中)。DMA掛載的時鍾為AHB總線,其時鍾為72Mhz,所以可以實現高速數據搬運。
       STM32F103RBT6 只有1 個DMA控制器,DMA1 ,下面我們就針對DMA1 進行介紹。
       從外設(TIMx、ADC、SPIx 、I2Cx 和USARTx )產生的DMA請求,通過邏輯或輸入到DMA控制器,這就意味着同時只能有一個請求有效。外設的DMA請求,可以通過設置相應的外設寄存器中的控制位,被獨立地開啟或關閉。
       DMA1各通道一覽:
這里我們要使用的是串口 1 的 DMA 傳送,也就是要用到通道 4。
 
1、DMA的配置
要配置的有DMA傳輸通道選擇,傳輸的成員和方向、普通模式還是循環模式等等。
void DMA_Configuration(void)
{
    DMA_InitTypeDef DMA_InitStructure;
     //DMA設置:
    //設置DMA源:內存地址&串口數據寄存器地址
    //方向:內存-->外設
    //每次傳輸位:8bit
    //傳輸大小DMA_BufferSize=SENDBUFF_SIZE
    //地址自增模式:外設地址不增,內存地址自增1
    //DMA模式:一次傳輸,非循環
    //優先級:中
    DMA_DeInit(DMA1_Channel4);//串口1的DMA傳輸通道是通道4
    DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff;
    DMA_InitStructure.DMA_DIR =  DMA_DIR_PeripheralDST;//外設作為DMA的目的端
    DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;//傳輸大小
    DMA_InitStructure.DMA_PeripheralInc =  DMA_PeripheralInc_Disable;//外設地址不增加
    DMA_InitStructure.DMA_MemoryInc =  DMA_MemoryInc_Enable;//內存地址自增1
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode =  DMA_Mode_Circular;
    //DMA_Mode_Normal(只傳送一次), DMA_Mode_Circular (不停地傳送)
    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//(DMA傳送優先級為中等)
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel4, &DMA_InitStructure);
}
注:
1、傳輸通道:通過查表,串口1的發送對應的是DMA的通道4,所以此處選擇通道4.
2、DMA傳輸方式:
(1) DMA_Mode_Normal,正常模式,當一次DMA數據傳輸完后,停止DMA傳送,對於上例而言,就是DMA_PeripheralDataSize_Byte個字節的傳送完成后,就停止傳送。
(2) DMA_Mode_Circular
循環模式,當傳輸完一次后,重新接着傳送,永不停息。
2、外設的DMA方式設置
將串口1設置成DMA模式:
每一個外設都有一個類似以下的一個DMA調用函數:xxx_DMACmd();
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);//發送就為USART_DMAReq_Tx;讀取就為USART_DMAReq_Rx
3、待傳輸數據的定義和初始化
#define SENDBUFF_SIZE   10240
vu8 SendBuff[SENDBUFF_SIZE];
    for(i=0;i<sendbuff_size;i++)
    {
        SendBuff[i] = i%10+'0';
    }
4、開始DMA傳輸(使能對應的DMA通道)
DMA_Cmd(DMA1_Channel4, ENABLE);
5、DMA傳輸的完成
 while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET)
 {
       LED_1_REV;      //LED翻轉
       Delay();        //浪費時間
 }
當傳輸完成后,就會跳出上面的死循環。
 
當然,使用串口作為外設的時候,還需要對串口進行初始化。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM