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控制器同時撤銷應答信號。如果發生更多的請求時,外設可以啟動下次處理。
簡單來說:
STM32F103RBT6 只有1 個DMA控制器,DMA1 ,下面我們就針對DMA1 進行介紹。
從外設(TIMx、ADC、SPIx 、I2Cx 和USARTx )產生的DMA請求,通過邏輯或輸入到DMA控制器,這就意味着同時只能有一個請求有效。外設的DMA請求,可以通過設置相應的外設寄存器中的控制位,被獨立地開啟或關閉。

{
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_InitStructure.DMA_Priority = DMA_Priority_Medium;//(DMA傳送優先級為中等)
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel4, &DMA_InitStructure);
}
vu8 SendBuff[SENDBUFF_SIZE];
{
SendBuff[i] = i%10+'0';
}
4、開始DMA傳輸(使能對應的DMA通道)
DMA_Cmd(DMA1_Channel4, ENABLE);
{
LED_1_REV; //LED翻轉
Delay(); //浪費時間
}