DMA基本原理

Posted studying~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DMA基本原理相关的知识,希望对你有一定的参考价值。

DMA:全称Direct Memory Access(直接存储器访问),把一个地址空间的值“复制”到另一个地址空间,使用DMA传输方式无需CPU直接控制传输,通过硬件为RAM和IO设备开辟一条直接传输数据的通道,使得CPU的效率大大提高。
作用:为CPU减负。

硬件方面,STM32最多有2个DMA控制器(DMA2仅存在大容量产品中),DMA1有7个通道,DMA2有5个通道。每个通道专门用来管理来自于一个或多个外设对存储器访问的请求(由硬件决定),附图DMA各通道限定可处理请求:
在这里插入图片描述
在这里插入图片描述
还有一个“仲裁器”来协调各个DMA请求的优先级(可以通过软件编程设置,共有四级:很高、高、中等和低),相同优先级的DMA请求,低编号通道优先于高编号通道传输。

DMA框图

在这里插入图片描述
大致流程(以外设->存储器为例):
外设(APB1、2)发送DMA请求–》经仲裁器处理–》发送到对应通道–》经DMA总线–》对存储器进行访问

STM32的DMA的特性

1.每个通道都直接连接专用的硬件DMA请求,反映在各个通道可处理的DMA请求的类型不同,都支持软件触发,这些通过软件来配置。
2.在七个请求间的优先权可以通过软件编程设置(共有四级:很高、高、中等和低),假如在相等优先权时由硬件决定(请求0优先于请求1,前面有提到,依此类推) 。
3.存储器(闪存、SRAM、外设的SRAM)、外设(APB1 APB2和AHB)均可作为访问的源和目标

4.独立的源和目标数据区的传输宽度(字节(8位)、半字(16位)、全字(32位))
5.可编程的数据传输数目:0~65536
在这里插入图片描述

6.支持循环的缓冲器管理,即传输完数据又从数据头传输,反反复复
在这里插入图片描述

7.每个通道都有3个事件标志(DMA 半传输,DMA传输完成和DMA传输出错),若使能对应的中断使能位,则产生中断。
在这里插入图片描述

8.传输方向:外设和存储器之间的传输,存储器和外设之间的传输 ,存储器和存储器之间的传输
在这里插入图片描述
9.指针增量模式:即每传输完一个数据,地址自增

====================================================================
在这里插入图片描述
归纳(每次DMA传送有以下4个操作):
1.将外设基地址写入CPARx
2.将存储器基地址写入CMARx
3.将要传输的数据数目写入CNDTRx,每传输一个数据,该寄存器自减1
4.设置DIR位,即确定数据传输方向

====================================================================

常用的DMA库函数

void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx,
DMA_InitTypeDef* DMA_InitStruct);
void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx,
FunctionalState NewState);
void DMA_ITConfig(DMA_Channel_TypeDef* DMAy_Channelx,
uint32_t DMA_IT, FunctionalState NewState);
void DMA_SetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx,
uint16_t DataNumber);
uint16_t DMA_GetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx);

FlagStatus DMA_GetFlagStatus(uint32_t DMAy_FLAG);
void DMA_ClearFlag(uint32_t DMAy_FLAG);
ITStatus DMA_GetITStatus(uint32_t DMAy_IT);
void DMA_ClearITPendingBit(uint32_t DMAy_IT);

常用的外设DMA使能库函数

void USART_DMACmd(USART_TypeDef* USARTx, uint16_t USART_DMAReq,
FunctionalState NewState);
void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void DAC_DMACmd(uint32_t DAC_Channel, FunctionalState NewState);
void I2C_DMACmd(I2C_TypeDef* I2Cx, FunctionalState NewState);
void SDIO_DMACmd(FunctionalState NewState);
void SPI_I2S_DMACmd(SPI_TypeDef* SPIx, uint16_t SPI_I2S_DMAReq,
FunctionalState NewState);

void TIM_DMAConfig(TIM_TypeDef* TIMx, uint16_t TIM_DMABase,
uint16_t TIM_DMABurstLength)
void TIM_DMACmd(TIM_TypeDef* TIMx, uint16_t TIM_DMASource,
FunctionalState NewState);

void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct)
typedef struct
{
uint32_t DMA_PeripheralBaseAddr; //外设基地址
uint32_t DMA_MemoryBaseAddr; //存储器基地址
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_M2M; //是否存储器到存储器方式
}DMA_InitTypeDef;

DMA配置程序过程

① 使能DMA时钟
RCC_AHBPeriphClockCmd();
② 初始化DMA通道参数
DMA_Init();
③使能串口DMA发送,串口DMA使能函数:
USART_DMACmd();
④使能DMA1通道,启动传输。
DMA_Cmd();
⑤查询DMA传输状态
DMA_GetFlagStatus();
⑥获取/设置通道当前剩余数据量:
DMA_GetCurrDataCounter();
DMA_SetCurrDataCounter();

以上是关于DMA基本原理的主要内容,如果未能解决你的问题,请参考以下文章

[架构之路-47]:目标系统 - 系统软件 - Linux OS硬件设备驱动 - CPU内存管理单元MMUDMA与IO内存管理单元IOMMU

DMA原理

DMA控制器原理详解

DMA控制器原理详解

[STM32F103]DMA原理

STM32DMA原理,配置步骤超详细,一文搞懂DMA