DMA
1.DMA基本介绍
1.1基本特点
(1) 双AHB主总线架构,一个用于存储器访问,一个用于外设访问;
(2)仅支持32位访问的AHB从编程接口;
(3)每个DMA有8个数据流,每个数据流有8个通道
(4)每个数据流有单独的四级32位FIFO,可用于FIFO模式或直接模式
FIFO模式:可通过软件将阈值级别选取为FIFO大小的1/4、1/2、3/4
直接模式:每个DMA请求会立即启动对存储器的传输
(5)通过硬件可将数据流配置为:1、支持外设到存储器、存储器到外设、存储器到存储器传输的常规通道。2、支持在存储器方双缓冲的双缓冲区通道。
(6)8个数据流中的每一个都连接到专用硬件DMA通道
(7)DMA数据流请求之间的优先级可用软件编程(4个级别),软件级别相同由硬件优先级决定
(8)每个数据流也支持通过软件触发存储器到存储器传输(仅限DMA2)
(9)每个数据流选择的通道请求多达8个
(10)要传输的数据项数目可以又DMA控制器或外设管理
(11)独立的源和目标传输宽度(字节、半字、字)
(12)对源和目标的增量和非增量寻址
(13)支持4个、8个、16个节拍的增量突发传输
(14)每个数据流都支持循环缓冲区管理
(15)5个事件标志(DMA半传输、DMA传输完成、DMA传输错误、DMA FIFO错误、直接模式错误)
1.2 DMA结构原理
1.2.1通道选择
DMA控制器通过DMA数据流x配置寄存器DMA_SxCR(x为0-7)的CHSEL[2:0]位选择对应通道作为目标外设。
DMA映射图如下:
1.2.2仲裁器
通过仲裁器确定数据流的优先级,配置优先级分为两个方面。软件优先级和硬件优先级。软件优先级高于硬件优先级。当软优先级相同时,硬件编号低的优先级高。软件优先级由DMA_SxCR寄存器配置。
1.2.3FIFO
FIFO是先进先出存储器缓冲区。每个数据流都有一个独立的4级32位FIFO。可以通过DMA数据流xFIFO控制寄存器DMA_SxFCR的FTH[1:0]位来设置4种阈值。可配置为1/4、1/2、3/4和满。
1.2.4存储器与外设端口
采用AHB总线,可通过控制AHB总线矩阵来启动AHB事务。
外设到存储器的传输;
存储器到外设的传输;
存储器到存储器的传输。
1.2.5 AHB从器件编程接口
用于对DMA控制器进行编程(仅支持32位访问)
2.相关寄存器
2.1 DMA结构体
typedef struct
{
uint32_t DMA_Channel;//通道选择
uint32_t DMA_PeripheralBaseAddr;//外设地址
uint32_t DMA_Memory0BaseAddr;//存储器0地址
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_FIFOMode;//FIFO模式
uint32_t DMA_FIFOThreshold;//FIFO阈值
uint32_t DMA_MemoryBurst;//存储器突发传输
uint32_t DMA_PeripheralBurst;//外设突发传输
}DMA_InitTypeDef;
3.配置方法
3.1 DMA初始化分步配置
(1)配置时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);//DMA1时钟使能
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);//DMA2时钟使能
(2)等待DMA可配置
使能 DMA 时钟后,我们就可以对 DMA 进行相关配置,要对配置寄存器 (DMA_SxCR)进行设置,必须先等待其最低位为 0(也就是 DMA 传输禁止了), 才可以进行配置。
while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){}//等待DMA可配置
(3)配置DMA结构体并初始化
DMA_InitStructure.DMA_Channel = chx; //通道选择
DMA_InitStructure.DMA_PeripheralBaseAddr = par;//DMA外设地址
DMA_InitStructure.DMA_Memory0BaseAddr = mar;//DMA 存储器0地址
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;//存储器到外设模式
DMA_InitStructure.DMA_BufferSize = ndtr;//数据传输量
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;//中等优先级
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//存储器突发单次传输
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//外设突发单次传输
DMA_Init(DMA_Streamx, &DMA_InitStructure);//初始化DMA Stream
3.2 DMA初始化完整配置
/*******************************************************************************
* 函 数 名 : DMAx_Init
* 函数功能 : DMA初始化函数
* 输 入 : DMA_Streamx:DMA数据流,DMA1_Stream0~7/DMA2_Stream0~7
chx:DMA通道选择,@ref DMA_channel DMA_Channel_0~DMA_Channel_7
par:外设地址
mar:存储器地址
ndtr:数据传输量
* 输 出 : 无
*******************************************************************************/
void DMAx_Init(DMA_Stream_TypeDef *DMA_Streamx,u32 chx,u32 par,u32 mar,u16 ndtr)
{
DMA_InitTypeDef DMA_InitStructure;
if((u32)DMA_Streamx>(u32)DMA2)//得到当前stream是属于DMA2还是DMA1
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);//DMA2时钟使能
}
else
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);//DMA1时钟使能
}
DMA_DeInit(DMA_Streamx);
while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){}//等待DMA可配置
/* 配置 DMA Stream */
DMA_InitStructure.DMA_Channel = chx; //通道选择
DMA_InitStructure.DMA_PeripheralBaseAddr = par;//DMA外设地址
DMA_InitStructure.DMA_Memory0BaseAddr = mar;//DMA 存储器0地址
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;//存储器到外设模式
DMA_InitStructure.DMA_BufferSize = ndtr;//数据传输量
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;//中等优先级
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//存储器突发单次传输
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//外设突发单次传输
DMA_Init(DMA_Streamx, &DMA_InitStructure);//初始化DMA Stream
}
讲解不到位的希望大家指出,有需要我讲解的部分,希望大家提出,我会出文档讲解。