目录
DMA是什么
DMA是指外部设备不通过CPU而直接与系统内存交换数据的接口技术。为了好理解,可以称之为只能传输数据的CPU,或者说是数据的搬运工。
DMA的作用
在机器操作的过程中,由于含有大量数据的传输。在传输的过程中会占用CPU,为了避免CPU过载,我们就使用DMA来执行数据的传输。
说白了,DMA就是数据的搬运工。
DMA传输方向
1-储存器——>储存器
这种情况下DMA的通道是可以随意的,没有太大的硬性要求,这里使用的是DMA1的通道6。
void DMA_Config(void)
{
DMA_InitTypeDef DMA_InitStructure;
// 开启DMA时钟
RCC_AHBPeriphClockCmd(DMA_CLOCK, ENABLE);
// 源数据地址
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)aSRC_Const_Buffer;
// 目标地址
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)aDST_Buffer;
// 方向:外设到存储器(这里的外设是内部的FLASH)
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
// 传输大小
DMA_InitStructure.DMA_BufferSize = BUFFER_SIZE;
// 外设(内部的FLASH)地址递增
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
// 内存地址递增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
// 外设数据单位
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
// 内存数据单位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
// DMA模式,一次或者循环模式
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ;
//DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
// 优先级:高
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
// 使能内存到内存的传输
DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;
// 配置DMA通道
DMA_Init(DMA_CHANNEL, &DMA_InitStructure);
//清除DMA数据流传输完成标志位
DMA_ClearFlag(DMA_FLAG_TC);
// 使能DMA
DMA_Cmd(DMA_CHANNEL,ENABLE);
}
2-储存器——>外设
void DMA_Config()
{
DMA_InitTypeDef DMA_InitStruct;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
DMA_InitStruct.DMA_BufferSize=SENDBUFF_SIZE;
DMA_InitStruct.DMA_DIR=DMA_DIR_PeripheralDST;
DMA_InitStruct.DMA_M2M=DMA_M2M_Disable;
DMA_InitStruct.DMA_MemoryBaseAddr=(uint32_t)SendBuff;//必须强制为32位,因为使用的是32位芯片
DMA_InitStruct.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte ;
DMA_InitStruct.DMA_MemoryInc=DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_Mode=DMA_Mode_Normal;
DMA_InitStruct.DMA_PeripheralBaseAddr=USART_DR_ADDRESS;
DMA_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;
DMA_InitStruct.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
DMA_InitStruct.DMA_Priority=DMA_Priority_High;//随便配置
DMA_Init(DMA1_Channel4,&DMA_InitStruct);
DMA_Cmd(DMA1_Channel4,ENABLE);
}
3-外设——>储存器
void USARTx_DMA_Config(void)
{
DMA_InitTypeDef DMA_InitStructure;
// 开启DMA时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
// 设置DMA源地址:串口数据寄存器地址*/
DMA_InitStructure.DMA_PeripheralBaseAddr = USART_DR_ADDRESS;
// 内存地址(要传输的变量的指针)
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ReceiveBuff;
// 方向:从外设到内存
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
// 传输大小
DMA_InitStructure.DMA_BufferSize = RECEIVEBUFF_SIZE;
// 外设地址不增
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
// 内存地址自增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
// 外设数据单位
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
// 内存数据单位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
// DMA模式,一次或者循环模式
// DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
// 优先级:中
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
// 禁止内存到内存的传输
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
// 配置DMA通道
DMA_Init(USART_TX_DMA_CHANNEL, &DMA_InitStructure);
// 使能DMA
DMA_Cmd (USART_TX_DMA_CHANNEL,ENABLE);
}
DMA.h
#ifndef __USARTDMA_H
#define __USARTDMA_H
#include "stm32f10x.h"
#include <stdio.h>
// 串口工作参数宏定义
#define DEBUG_USARTx USART1
#define DEBUG_USART_CLK RCC_APB2Periph_USART1
#define DEBUG_USART_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_BAUDRATE 115200
// USART GPIO 引脚宏定义
#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOA)
#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_TX_GPIO_PORT GPIOA
#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_9
#define DEBUG_USART_RX_GPIO_PORT GPIOA
#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_10
// 串口对应的DMA请求通道
#define USART_TX_DMA_CHANNEL DMA1_Channel4
// 外设寄存器地址
#define USART_DR_ADDRESS (USART1_BASE+0x04)
// 一次发送的数据量
#define SENDBUFF_SIZE 5000
void USART_Config(void);
void USARTx_DMA_Config(void);
#endif /* __USARTDMA_H */
这样配置好之后,就能使用了,当然要是用到了外设,那么就需要打开外设的DMA通道。
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
比如这个串口,我们在使用DMA的时候就需要打开,作用是选择DMA从哪个串口运输。
总结
要想使用DMA,首先把DMA的结构体中数据配置好,依据自己的情况去选择。
之后就是把上面用到的IO口初始化,调用的时候先把IO初始化,这样更加保险。
最后在使用时,记得打开外设对DMA的使用。