直接存储器读取
DMA简介
直接存储器存取(DMA)用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU干预,数据可以通过DMA快速地移动,这就节省了CPU的资源来做其他操作。
由图可见,DMA 一共有 DMA1 和 DMA2 两个控制器。DMA1 有7个通道,DMA2 有5个通道。
在存储器和存储器之间传输数据时,可任选通道进行传输;但在外设和存储器之间传输数据时,需要用到专用的通道。
DMA寄存器
-
中断状态寄存器 --- ISR(interrupt status register):存放DMA中断的标志位;
- 注意:若为DMA2,只有低19位有效;
- 作用---传输错误(TE)标志位:位3,7,11,15,19,23,27,发生传输错误时置1;
- 作用---半传输(HT)标志位:位2,6,10,14,18,22,26,传输了一半数据并产生对应事件时置1;
- 作用---传输完成(TC)标志位:位1,5,9,13,17,21,25,传输完成并产生了对应事件时置1;
- 作用---全局中断(GI)标志位:位0,4,8,12,16,20,24,上述3个寄存器任一寄存器置1,该寄存器置1;
- 复位值:0x0000 0000
-
中断标志清除寄存器 --- IFCR(interrupt flag clear register):清除ISR中DMA中断的标志位;
- 注意:若为DMA2,只有低19位有效;
- 作用---清除传输错误(TE)标志位:位3,7,11,15,19,23,27,置1时将 TE 置0;
- 作用---清除半传输(HT)标志位:位2,6,10,14,18,22,26,置1时将 HT 置0;
- 作用---清除传输完成(TC)标志位:位1,5,9,13,17,21,25,置1时将 TC 置0;
- 作用---清除全局中断(GI)标志位:位0,4,8,12,16,20,24,置1时将 TE、HT、TC寄存器均置0;
- 复位值:0x0000 0000
-
通道x配置寄存器 --- CCRx(channel x configuration register):设置通道x的各项配置;
- 注意:若为DMA1,该寄存器有7组(即x可为 0~7);DMA2 就只有5组;
- 作用---开启通道:位0 置1时通道开启,置0时关闭;
- 作用---允许传输完成(TC)中断:位1,置1时允许产生传输完成中断(可检测TC标志位查看是否产生) ;
- 作用---允许半传输(HT)中断:位2,置1时允许产生半传输中断;
- 作用---允许传输错误(TE)中断:位3,置1时允许产生传输错误中断;
- 作用---设置数据来源:位4,置0时表示从外设读取数据,置1时表示从存储器读取数据;
- 注意:若是存储器到存储器,则一般把发送存储器当作外设来进行设置,位14 再置1即可;
- 作用---设置是否循环操作:位5,置0时表示只读取1次数据,置1时表示循环读取该数据;
- 作用---设置外设地址增量模式:位6,置0时传输数据时外设地址不增加,置1则为增加;
- 作用---设置存储器地址增量模式:位7,置0时传输数据时存储器地址不增加,置1则为增加;
- 作用---设置外设数据宽度:位9:8;00为8位,01为16位,10为32位,11为保留;
- 作用---设置存储器数据宽度:位11:10;00为8位,01为16位,10为32位,11为保留;
- 作用---设置通道的优先级:位13:12,00为低,01为中,10为高,11为最高;
- 注意:当通道优先级相同时,DMA1通道比DMA2通道优先级高,DMAx比DMAy通道优先级高(x<y);
- 作用---设置存储器和存储器之间传输:位14,置0表示是外设和存储器之间传输,置1表示是存储器和存储器之间传输;
- 复位值:0x0000 0000
-
通道x传输数量寄存器 --- CNDTRx(channel x number of data register):设置通道x需要传输的数据个数;
- 注意:若为DMA1,该寄存器有7组(即x可为 0~7);DMA2 就只有5组;
- 作用---设置需要传输的数据的个数:位15:0,表示需要传输的数据的个数(易知一次最多只能传输65335个数据);
-
DMA通道x外设地址寄存器 --- CPARx(channel x peripheral address register):存储在外设中需要传输的数据的地址;
- 注意:若为DMA1,该寄存器有7组(即x可为 0~7);DMA2 就只有5组;
- 作用---存储地址:位31:0,存储在外设中需要传输的数据的地址;
-
DMA通道x存储器地址寄存器 --- CMARx(channel x memory address register):存储在存储器中需要传输的数据的地址;
- 注意:若为DMA1,该寄存器有7组(即x可为 0~7);DMA2 就只有5组;
- 作用---存储地址:位31:0,存储在存储器中需要传输的数据的地址;
常用DMA固件库函数 (stm32f10x_dma.h)
USART初始化函数 --- USART_Init
void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct);
- DMAy_Channelx:选择通道端口,y可为 1~2 ,y=1时x可为 1~7 ,y=2时x可为 1~5 ;
-
DMA_InitStruct:DMA_InitTypeDef 结构体
- DMA_MemoryBaseAddr:存储器(发送或将要接收的)数据地址;
- DMA_PeripheralBaseAddr:外设(发送或将要接收的)数据地址;
- DMA_DIR:数据传输方向,可选 外设为源(PeripheralSRC)、外设为目标(PeripheralDST);
- DMA_BufferSize:传输的数据的个数,最大为65335;
- DMA_PeripheralInc:外设是否启动增量模式( Enable 或 Disable);
- DMA_PeripheralDataSize:外设数据的字长;
- DMA_MemoryInc:存储器是否启动增量模式( Enable 或 Disable);
- DMA_MemoryDataSize:存储器数据的字长;
- DMA_Mode:是否循环传输数据,( Normal 或 Circular );
- DMA_Priority:该通道优先级,可为 低(Low)、中(Medium)、高(High)、超高(VeryHigh);
- DMA_M2M:是否是存储器和存储器之间的传输,是(Enable) 或 不是(Disable);
- 示例:
// DMA_M2M 初始化
//定义DMA初始化结构体
DMA_InitTypeDef DMA_InitStructure;
//打开DMA1时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
//配置DMA
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)aSRC_Const_Buffer; //源数据地址
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)aDST_Buffer; //目标数据地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //设置外设(Flash)为源
DMA_InitStructure.DMA_BufferSize = 8; //配置传输数据的个数为8
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable; //外设(源)设置为增量模式
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; //外设数据字长设置为32位
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //存储(SRAM)设置为增量模式
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; //存储数据字长设置为32位
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //只发送一次数据(非循环发送)
DMA_InitStructure.DMA_Priority = DMA_Priority_High; //设置为高优先级
DMA_InitStructure.DMA_M2M = DMA_M2M_Enable; //打开 M2M
//初始化DMA通道
DMA_Init(DMA1_Channel6, &DMA_InitStructure);
DMA清除标志位函数 --- DMA_ClearFlag
void DMA_ClearFlag(uint32_t DMAy_FLAG);
-
DMAy_FLAG:对应的标志位,y可以为 1~2 ;
DMA通道使能函数 --- DMA_Cmd
DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx, FunctionalState NewState);
- DMAy_Channelx:选择通道端口,y可为 1~2 ,y=1时x可为 1~7 ,y=2时x可为 1~5 ;
- NewState:使能或关闭,ENABLE、DISABLE;
- 示例:
//使能DMA1的通道6
DMA_Cmd(DMA1_Channel6, ENABLE);
DMA获取标志位函数 --- DMA_GetFlagStatus
FlagStatus DMA_GetFlagStatus(uint32_t DMAy_FLAG);
- DMAy_FLAG:对应的标志位,y可以为 1~2;