DMA,意思为直接存储器访问。
DMA 可 用于实现外设与存储器之间或者存储器与存储器之间数据高效传输。
因为 DMA 传输数据移动过程无需 CPU 直接操作,这样节省的 CPU 资 源就可供其它操作使用。
从硬件层面来理解,DMA 就好像是 RAM 与 I/O 设备间数 据传输的通路,外设与存储器之间或者存储器与存储器之间可以直接在这条通路 上进行数据传输。
这里说的外设一般指外设的数据寄存器,比如 ADC、SPI、I2C、 DCMI 等外设的数据寄存器,存储器一般是指片内 SRAM、外部存储器、片内 Flash 等。
STM32F1 最多有 2 个 DMA 控制器,DMA1 有 7 个通道。 DMA2 有 5 个通道。每个通道专门用来管理来自于一个或多个外设 对存储器访问的请求。还有一个仲裁器来协调各个 DMA 请求的优先权。
DMA1通道对应外设请求
DMA2通道对应外设请求
DMA就像一个中转站一样,里面有源地址和目标地址,多通道并用可以配置优先级,
只要开启DMA就可以直接实现源地址里的内容传送给目标地址,不需要CPU来管理,它就像个通道一样,开启就传输。
dma.c
#include "dma.h"
/*******************************************************************************
* 函 数 名 : DMAx_Init
* 函数功能 : DMA初始化函数
* 输 入 :
DMAy_Channelx:DMA通道选择,@ref DMA_channel DMA_Channel_0~DMA_Channel_7
par:外设地址
mar:存储器地址
buff_size:数据传输量
* 输 出 : 无
*******************************************************************************/
void DMAx_Init(DMA_Channel_TypeDef* DMA1_Channelx,u32 par,u32 mar,u16 buff_size)
{
DMA_InitTypeDef DMA_InitStructure;
//1*开启相应时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
//2*DMA结构体配置
DMA_InitStructure.DMA_PeripheralBaseAddr = par; //外设目标地址
DMA_InitStructure.DMA_MemoryBaseAddr = mar; //存储器源地址
DMA_InitStructure.DMA_DIR =DMA_DIR_PeripheralDST ; //方向是DMA存储器到外设寄存器。方向还有外设到存储器,存储器到存储器
DMA_InitStructure.DMA_BufferSize = buff_size; //传输的字节数目
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设寄存器地址自递增,外设通常是一个不需要递增
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryInc_Enable; //传输数据多字节时需要地址自增,实现开启就全部传输完
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //DMA传输模式,单次传输
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //优先级配置,用于多通道时
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //存储器到存储器时打开
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //存储器数据长度为1Byte,8位
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设接收数据长度为必须要存储器发送数据长度一样
DMA_Init(DMA1_Channelx,&DMA_InitStructure);
}
/*******************************************************************************
* 函 数 名 : DMAx_Enable
* 函数功能 : 开启一次DMA传输
* 输 入 : DMAy_Channelx:DMA通道选择,@ref DMA_channel DMA_Channel_0~DMA_Channel_7
buff_size:数据传输量,传输时再赋值一遍防止出错
* 输 出 : 无
*******************************************************************************/
//3*开启DMA
void DMAx_ENABLE(DMA_Channel_TypeDef* DMA1_Channelx,u16 buff_size)
{
DMA_Cmd(DMA1_Channelx,DISABLE); //先关闭DMA使能来赋
DMA_SetCurrDataCounter(DMA1_Channelx,buff_size);
DMA_Cmd(DMA1_Channelx,ENABLE);
}
dma.h
#ifndef _dma_H
#define _dma_H
#include "system.h"
void DMAx_Init(DMA_Channel_TypeDef* DMA1_Channelx,u32 par,u32 mar,u16 buff_size);
void DMAx_ENABLE(DMA_Channel_TypeDef* DMA1_Channelx,u16 buff_size);
#endif
main.c
#include "systick.h"
#include "led.h"
#include "system.h"
#include "key.h"
#include "usart.h"
#include "dma.h"
#define data_size 5000
u8 data[data_size];
//数组赋值专用函数
void Data_zhuang(u8 *p)
{
u16 i;
for(i=0;i<data_size;i++)
{
*p = '5';
p++;
}
}
int main()
{
u8 i=0;
u8 key;
SysTick_Init(72); //系统时钟初始
LED_INIT();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
USART1_Init(9600);
KEY_INIT();
Data_zhuang(data); //给数组赋值
DMAx_Init(DMA1_Channel4,(u32)&USART1->DR,(u32)data,data_size); //DMA初始化,(u32)&USART1->DR是串口1的数据寄存器,(u32)data是我们在内存中造的数组
while(1)
{
key = KEY_Scan(0);
if(key==KEY_UP)
{
USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE); //是哪个外设就开启哪个的DMA功能
DMAx_ENABLE(DMA1_Channel4,data_size); //使能DMA
while(1)
{
if(DMA_GetFlagStatus(DMA1_FLAG_TC4)==1) //判断DMA1的通道4是否传输完成
{
DMA_ClearFlag(DMA1_FLAG_TC4); //清除传输完成标志
break;
}
led2=!led2;
delay_ms(300);
}
}
i++;
if(i%20==0) //200ms变换一次
{
led1=!led1;
}
}
}
网友评论