一、DMA简介:

       DMA(Direct Memory Access,直接存储区访问)为实现数据高速在外设寄存器存储器之间或者存储器存储器之间传输提供了高效的方法。
DMA1P->MM->P

DMA2P->MM->PM->M

二、通道和流:

是数据传输的一条链路,每个DMA控制器有8条独立的数据流,每次传输的数据量最大为65535,如果数据的单位为字的话,那一次可以传输256KB

通道每个数据流有8个通道选择,每个通道对应不同的DMA请求。

1、DMA1 请求映射

2、DMA2 请求映射

三、仲裁器

多个DMA同时请求,怎么办?

1、软件阶段,DMA_SxCRPL

2、硬件阶段,数据流编号小的优先级大

同一个数据流只能使用一个通道,同一个DMA控制器可以使用多个数据流。

四、DMA结构体详解:

typedef struct {
uint32_t DMA_Channel;             通道选择
uint32_t DMA_PeripheralBaseAddr;  外设地址
uint32_t DMA_Memory0BaseAddr;     存储器 0 地址
uint32_t DMA_DIR;                 传输方向
uint32_t DMA_BufferSize;          数据数目
uint32_t DMA_PeripheralInc;       外设递增
uint32_t DMA_MemoryInc;           存储器递增
uint32_t DMA_PeripheralDataSize;  外设数据宽度
uint32_t DMA_MemoryDataSize;      存储器数据宽度
uint32_t DMA_Mode;                模式选择
uint32_t DMA_Priority;            优先级
uint32_t DMA_FIFOMode;            FIFO 模式
uint32_t DMA_FIFOThreshold;       FIFO 阈值
uint32_t DMA_MemoryBurst;         存储器突发传输
uint32_t DMA_PeripheralBurst;     外设突发传输
} DMA_InitTypeDef;

DMA_ChannelDMA 请求通道选择,可选通道 0 至通道 7,每个外设对应固定的通道DMA_SxCR :CHSEL[2:0]

DMA_PeripheralBaseAddr外设地址, DMA_SxPAR

DMA_Memory0BaseAddr存储器 0 地址DMA_SxM0AR

DMA_DIR传输方向选择,可选外设到存储器、存储器到外设以及存储器到存储器,DMA_SxCR :DIR[1:0]

DMA_BufferSize设定一次传输的数据个数,DMA_SxNDTR

DMA_PeripheralInc外设地址是否递增, DMA_SxCR :PINC

DMA_MemoryInc存储器地址是否递增DMA_SxCR :MINC

DMA_PeripheralDataSize外设数据宽度,可选字节(8 )、半字(16 )和字(32)DMA_SxCR :PSIZE[1:0]

DMA_BufferSize设定一次传输的数据个数,DMA_SxNDTR

DMA_MemoryDataSize存储器数据宽度,可选字节(8 )、半字(16 )和字(32)DMA_SxCR :MSIZE[1:0]

DMA_Mode DMA 传 输 模 式 选 择 , 可 选 一 次 传 输 或 者 循 环 传 输 , DMA_SxCR :CIRC 位的值

DMA_Priority优先级,非常高、高、中和DMA_SxCR :PL[1:0]。

DMA_FIFOModeFIFO 模式使能DMA_SxFCR :DMDIS

DMA_FIFOThresholdFIFO 阈值选择1/41/23/4 满,DMA_SxFCR :FTH[1:0]

DMA_MemoryBurst存储器突发模式选择,单次模式、 4 节拍、8 节拍、16 节拍,DMA_SxCR :MBURST[1:0]。

DMA_PeripheralBurst外设突发模式选择,单次模式、 4 节拍、8 节拍、16 节拍,DMA_SxCR :PBURST[1:0]

五、编程时需要用到的固件库函数

1-初始化DMA的寄存器到复位状态

DMA_DeInit(DMA_Stream_TypeDef* DMAy_Streamx);

2-DMA初始化函数

void DMA_Init(DMA_Stream_TypeDef* DMAy_Streamx, DMA_InitTypeDef* DMA_InitStruct);

3-DMA使能函数

DMA_Cmd(DMA_Stream_TypeDef* DMAy_Streamx, FunctionalState NewState);

六、串口1的接收和发送的DMA的配置

DMA 存储器到串口1模式/
 
uint8_t SendBuff[SENDBUFF_SIZE];
 
void USART1_TX_DMA_Config(void)
{
	DMA_InitTypeDef DMA_InitStructure;
 
  /*开启DMA时钟*/
  RCC_AHB1PeriphClockCmd(USART1_DMA_CLK, ENABLE);
  
  /* 复位初始化DMA数据流 */
  DMA_DeInit(USART1_TX_DMA_STREAM);
 
  /* 确保DMA数据流复位完成 */
  while (DMA_GetCmdStatus(USART1_TX_DMA_STREAM) != DISABLE)  { }
 
  /*usart1 tx对应dma2,通道4,数据流7*/	
  DMA_InitStructure.DMA_Channel = USART1_DMA_CHANNEL;  
  /*设置DMA源:串口数据寄存器地址*/
  DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_BASE;	 
  /*内存地址(要传输的变量的指针)*/
  DMA_InitStructure.DMA_Memory0BaseAddr = (u32)SendBuff;
  /*方向:从内存到外设*/		
  DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;	
  /*传输大小DMA_BufferSize=SENDBUFF_SIZE*/	
  DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;
  /*外设地址不增*/	    
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 
  /*内存地址自增*/
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;	
  /*外设数据单位*/	
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  /*内存数据单位 8bit*/
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;	
  /*DMA模式:不断循环*/
  //DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;	
  /*优先级:中*/	
  DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; 
	
  /*禁用FIFO*/
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;        
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;    
  /*存储器突发传输 单次传输*/
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;    
  /*外设突发传输 单次传输*/
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
	
  /*配置DMA2的数据流7*/		   
  DMA_Init(USART1_TX_DMA_STREAM, &DMA_InitStructure);
  
  /*使能DMA*/
  DMA_Cmd(USART1_TX_DMA_STREAM, ENABLE);
  
  /* 等待DMA数据流有效*/
  while(DMA_GetCmdStatus(USART1_TX_DMA_STREAM) != ENABLE);
}
 
uint8_t RevBuff[REVBUFF_SIZE];
 
void USART1_RX_DMA_Config(void)
{
	DMA_InitTypeDef DMA_InitStructure;
 
  /*开启DMA时钟*/
  RCC_AHB1PeriphClockCmd(USART1_DMA_CLK, ENABLE);
  
  /* 复位初始化DMA数据流 */
  DMA_DeInit(USART1_RX_DMA_STREAM);
 
  /* 确保DMA数据流复位完成 */
  while (DMA_GetCmdStatus(USART1_RX_DMA_STREAM) != DISABLE)  { }
 
  /*usart1 tx对应dma2,通道4,数据流2*/	
  DMA_InitStructure.DMA_Channel = USART1_DMA_CHANNEL;  
  /*设置DMA源:串口数据寄存器地址*/
  DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_BASE;	 
  /*内存地址(要传输的变量的指针)*/
  DMA_InitStructure.DMA_Memory0BaseAddr = (u32)RevBuff;
  /*方向:从外设到内存*/		
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;	
  /*传输大小DMA_BufferSize=REVBUFF_SIZE*/	
  DMA_InitStructure.DMA_BufferSize = REVBUFF_SIZE;
  /*外设地址不增*/	    
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 
  /*内存地址自增*/
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;	
  /*外设数据单位*/	
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  /*内存数据单位 8bit*/
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;	
  /*DMA模式:不断循环*/
  //DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;	
  /*优先级:中*/	
  DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; 
	
  /*禁用FIFO*/
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;        
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;    
  /*存储器突发传输 单次传输*/
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;    
  /*外设突发传输 单次传输*/
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
	
  /*配置DMA2的数据流2*/		   
  DMA_Init(USART1_RX_DMA_STREAM, &DMA_InitStructure);
  
  /*使能DMA*/
  DMA_Cmd(USART1_RX_DMA_STREAM, ENABLE);
  
  /* 等待DMA数据流有效*/
  while(DMA_GetCmdStatus(USART1_RX_DMA_STREAM) != ENABLE);
}
#ifndef __BSP_DMA_H
#define	__BSP_DMA_H
 
#include "stm32f4xx.h"
#include "bsp_led.h" 
#include "bsp_systick.h"
 
#define as 0
 
/*存储器到外设串口1TX*/
#define USART1_DR_BASE               (uint32_t)&(USART1->DR)		//数据发送到 USART_DR 寄存器,该寄存器相对 USART 偏移地址为0x04
#define SENDBUFF_SIZE                5000				//发送的数据量  小于65535
 
#define USART1_DMA_CLK               RCC_AHB1Periph_DMA2	
#define USART1_DMA_CHANNEL           DMA_Channel_4       //通道4
#define USART1_TX_DMA_STREAM            DMA2_Stream7        //数据流 7
/*存储器到外设串口1RX*/
#define USART1_DR_BASE               (uint32_t)&(USART1->DR)		//数据发送到 USART_DR 寄存器,该寄存器相对 USART 偏移地址为0x04
#define REVBUFF_SIZE                5				//发送的数据量  小于65535
 
#define USART1_DMA_CLK               RCC_AHB1Periph_DMA2	
#define USART1_DMA_CHANNEL           DMA_Channel_4       //通道4
#define USART1_RX_DMA_STREAM         DMA2_Stream2        //数据流 2
 
void USART1_TX_DMA_Config(void);
void USART1_RX_DMA_Config(void);
#endif