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