赞
踩
DMA(Direct Memory Access)即直接存储访问。
简单理解,DMA就是不占用CPU资源的数据传输模式。DMA 传输将数据从A地址空间复制到B地址空间,这个过程由 DMA 控制器来完成,CPU只需要把DMA进行初始化设置就可以了,在数据传输时不需要CPU参与。
使用DMA可以大大减轻CPU工作量,尤其是数据量非常大的时候。
比如从ADC或者串口来了3000个数据,CPU复制数据就需要进行3000次操作:
for(int i = 0;i < 3000;i++)
{
buf[i] = data;
}
虽然目前的CPU主频很高,3000个数据马上也能传输完成,但是在某些场合下这是不行的。在数据传输的这时间段,CPU只负责传输数据,十分浪费CPU资源。所以对于大容量数据传输这种情况其实不需要CPU一直参与,只需在A、B之间创建个通道,让它们自己传输即可。这就是DMA,一般对于大量数据转移都用DMA进行数据传输。
使用DMA,只需要提供两个地址和一个数据长度就可以了,目的地址和数据源地址,启动DMA后,DMA自动把数据从数据源地址搬运到目的地址。这样就解放了CPU,使得CPU可以去做其他更重要的事情。
DMA的数据搬运模式有下面三种:
1、内存到外设
2、外设到内存
3、内存到内存
DMA控制器:
从上图可以看到,DMA有八个数据流,每个数据流又有8个通道。
流:数据传输的链路,一次最大传输256KB数据。
通道:每个数据流都有8个通道选择,每个通道对应不同的DMA请求,比如ADC、DAC、串口等。
DMA请求映射:
DMA_SxCR设置DMA通道、数据流、优先级等设置
当多个DMA请求同时来的时候,DMA会通过DMA仲裁器觉决定先处理谁。
软件:DMA_SxCR的PL位决定。
硬件:数据流编号小的优先级高。
同一个数据流只能使用一个通道,同一个DMA控制器可以使用多个数据流。
DMA控制器中的FIFO可以简单认为是一块缓冲区,为数据源和目标之间提供以一个数据中转空间。
DMA数据搬运有直接模式、FIFO模式等。
直接模式就是数据到了FIFO直接传出去。
FIFO可以设置传进来几个字节后在传出去,如传进来4、8、12、16个字节后在开始传出
FIFO突发模式:看你的数据分几次发,一次发送、两次发送等等。
DMA相关结构体和初始化函数(基于标准库):
DMA初始化结构体DMA_ InitTypeDef
:
typedef struct
{
uint32_t
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_DeInit(DMA_Stream_TypeDef* DMAy_Streamx);
DMA初始化:
void DMA_Init(DMA_Stream_TypeDef* DMAy_Streamx,DMA_InitTypeDef* DMA_InitStruct);
DMA使能函数:
MDA_Cmd(DMA_Stream_TypeDef* DMAy_Streamx,FunctionalState NewState);
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。