STM32的DMA详解

        DMA,全称为:Direct Memory Access,即直接存储器访问。可以实现高速外设和存储器之间自动批量交换数据,并且只有在开始和结束时需要CPU干预,可以减轻CPU负担
        STM32最多有2个 DMA 控制器(DMA2仅存在大容量产品中),DMA1有7个通道。DMA2有5个通道。每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁器来协调各个 DMA 请求的优先权。

STM32 的 DMA 有以下一些特性:
①每个通道都直接连接专用的硬件 DMA请求,每个通道都同样支持软件触发。这些功能通过软件来配置。
②七个通道的优先级可以通过软件编程设置(共有四级:很高、高、中等和低),优先级相等的话通道编号小的优先级高。
③独立的源和目标数据区的传输宽度(字节、半字、全字),模拟打包和拆包的过程。源和目标地址必须按数据传输宽度对齐。
④支持循环的缓冲器管理
⑤每个通道都有3个事件标志(DMA 半传输,DMA 传输完成和 DMA 传输出错),这3个事件标志逻辑或成为一个单独的中断请求。
⑥存储器和存储器间的传输,外设和存储器,存储器和外设的传输
⑦闪存、SRAM、外设的 SRAM、APB1 APB2 和 AHB 外设均可作为访问的源和目标。

下图是STM32的DMA各通道一览表:

 下面以串口1发送的DMA通道来介绍一下DMA配置过程,串口1用的是DMA1的通道4:

①使能DMA时钟

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

②将DMA通道1寄存器重设为缺省值

DMA_DeInit(DMA1_Channel4); //将 DMA 的通道 1 寄存器重设为缺省值

③初始化DMA通道4参数

DMA_InitTypeDef DMA_InitStructure;//初始化结构体
DMA_InitStructure.DMA_PeripheralBaseAddr =&USART1->DR;//外设基地址,串口1的数据寄存器
DMA_InitStructure.DMA_MemoryBaseAddr = cmar;// 内存基地址,自定义的数组 
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;// 传输方向存储器到外设
DMA_InitStructure.DMA_BufferSize = 64;//一次传输数据量的大小
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_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//普通模式,不循环发送							
DMA_InitStructure.DMA_Priority = DMA_Priority_High;//优先级高
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//不是内存到内存
	
DMA_Init(DMA1_Channel2, &DMA_InitStructure);

④使能串口DMA输出

USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);

⑤使能DMA1通道4,启动传输

DMA_Cmd(DMA1_Channel4, ENABLE);

⑥开启一次DMA传输

void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx)
{ 
DMA_Cmd(DMA1_Channel4, DISABLE ); //关闭 USART1 TX DMA1 所指示的通道 
DMA_SetCurrDataCounter(DMA1_Channel4,64);//设置 DMA 缓存的大小
DMA_Cmd(DMA1_Channel4, ENABLE); //使能 USART1 TX DMA1 所指示的通道
}

总体代码如下:

#include "dma.h"
DMA_InitTypeDef DMA_InitStructure;
u16 DMA1_MEM_LEN;//保存 DMA 每次数据传送的长度 
//DMA1 的各通道配置
//这里的传输形式是固定的,这点要根据不同的情况来修改
//从存储器->外设模式/8 位数据宽度/存储器增量模式
//DMA_CHx:DMA 通道 CHx
//cpar:外设地址
//cmar:存储器地址
//cndtr:数据传输量
void MYDMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr)
{
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能 DMA 时钟
DMA_DeInit(DMA_CHx); //将 DMA 的通道 1 寄存器重设为缺省值
DMA1_MEM_LEN=cndtr;
DMA_InitStructure.DMA_PeripheralBaseAddr = cpar; //DMA 外设 ADC 基地址
DMA_InitStructure.DMA_MemoryBaseAddr = cmar; //DMA 内存基地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //数据传输方向内存到外设
DMA_InitStructure.DMA_BufferSize = cndtr; //DMA 通道的 DMA 缓存的大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址不变
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//内存地址寄存器递增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //数据宽度为 8 位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //数据宽度为 8 位
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //工作在正常缓存模式
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DM 通道拥有中优先级
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //非内存到内存传输
DMA_Init(DMA_CHx, &DMA_InitStructure); //初始化 DMA 的通道
} 
//开启一次 DMA 传输
void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx)
{ 
DMA_Cmd(DMA_CHx, DISABLE ); //关闭 USART1 TX DMA1 所指示的通道 
DMA_SetCurrDataCounter(DMA1_Channel4,DMA1_MEM_LEN);//设置 DMA 缓存的大小
DMA_Cmd(DMA_CHx, ENABLE); //使能 USART1 TX DMA1 所指示的通道
}

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值