目录
一、DMA简介
二、DMA实现过程
1.框图编辑
2.DMA的处理过程
3.DMA仲裁器
4.DMA通道
5.DMA寄存器
1`DMA中断状态寄存器(DMA_ISR)
2`DMA中断标志清除寄存器(DMA_IFCR)
3`DMA通道x配置寄存器(DMA_CCRx)(x = 1…7)
4`DMA通道x传输数量寄存器(DMA_CNDTRx)(x = 1…7)
5`DMA通道x存储器地址寄存器(DMA_CMARx)(x = 1…7)
6`DMA通道x外设地址寄存器(DMA_CPARx)(x = 1…7)
6.DMA配置结构图
三、库函数使用
一、DMA简介
直接存储器存取(DMA)用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU干预,数据可以通过DMA快速地移动,这就节省了CPU的资源来做其他操作。两个DMA控制器有12个通道(DMA1有7个通道, DMA2有5个通道),每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁器来协调各个DMA请求的优先权。
最大传输量是65535,因为DMA_CNTR寄存器是16位有效的
1. DMA2仅存在于大容量产品和互联型产品。
2. SPI/I2S3、 UART4、 TIM5、 TIM6、 TIM7和DAC的DMA请求仅存在于大容量产品和互联型产品。
3. ADC3、 SDIO和TIM8的DMA请求仅存在于大容量产品
二、DMA实现过程
1.框图
由上图可知,DMA是AHB上的,SRAM,FLASH,外设都能申请DMA传输,DMA有多个通道
2.DMA的处理过程
在发生一个事件后,外设向DMA控制器发送DMA请求,DMA根据通道优先级处理请求。当DMA开始访问发送请求的外设是,会给外设一个应答,外设得到应答后就会立刻释放请求,与此同时DMA撤销应答信号,以便于处理下一个请求,开始下一个DMA传输。
总之,每次DMA传送由三个操作组成
1.从外设数据寄存器或者从我们指示的地址取数据,第一次开始地址是DMA_CPARx或 DMA_CMARx寄存器指定的外设基地址或存储器单元。
2.存数据到外设数据寄存器或者当前外设/存储器地址寄存器指示的存储器地址,第一次传输
时的开始地址是DMA_CPARx或DMA_CMARx寄存器指定的外设基地址或存储器单元。
3.执行一次DMA_CNDTRx寄存器的递减操作,该寄存器包含未完成的操作数目。
3.DMA仲裁器
仲裁器,顾名思义,就是在众多请求中选择一个最合适的。
DMA仲裁器依靠着通道的请求优先级来选择,优先级又分为软件和硬件优先级
硬件优先级:看排序,例如通道1>通道2
软件优先级:分为最高,高,中等,低 四个优先级,在DMA_CCRx寄存器中配置
注意:在大容量产品和互联型产品中, DMA1控制器拥有高于DMA2控制器的优先级!
4.DMA通道
DMA1:有7个通道,可以实现P->M,M->P,M->M
DMA2:有5个通道,可以实现P->M,M->P,M->M,只存在大容量或者互联型
P:外设
M:闪存(flash,只读 存储器)、 SRAM
M->M时所有的通道都能使用
下图是各个外设的DMA通道,具体配置在下面讲解寄存器和库函数时进行
5.DMA寄存器
1`DMA中断状态寄存器(DMA_ISR)
TEIF是传输错误标志位,HEIF是通道的半传输标志位,TCIF是通道x的传输完成标志位
这三个都是在事件发生时,会由硬件自动置1,表示事件发生,我们可以通过DMA_IFCR寄存器相应位写入1来消除这些标志位
GIF是通道x的全局中断标志位,当上面三个事件发生其中一个时,就会被硬件自动置1,也是写入MDA_IFCR寄存器相应位为1来清除
2`DMA中断标志清除寄存器(DMA_IFCR)
CTEIFx:清除通道x的传输错误标志
CHTIFx:清除通道x的半传输标志
CTCIFx:清除通道x的传输完成标志
CGIFx : 清除通道x的全局中断标志
均是写入1清除标志位
3`DMA通道x配置寄存器(DMA_CCRx)(x = 1…7)
EN:使能位
TCIE,HTIE,TEIE都是中断使能位,给1使能
DIR:用来配置数据传输方向,即从哪读取数据,0外设,1存储器
CIRC:配置循环模式,就是进行完一次DMA传输之后是否继续进行下一次的传输
PINC,MINC:配置地址增量模式,即传输和存储的地址是否需要递增,例如,我们使用
M- >M模式,自己定义了两个数组,那么两个数组的地址都需要自动递增
才能实现对应存储。若我们使用的是数据寄存器,因为数据寄存器只有一
个地址,所以不递增
PSIZE,MSIZE:数据宽度,有8,16,32位
少传多,高位补零;多传少,舍弃高位
PL:设置通道优先级
MEM2MEM:选择是M->M,还是P->M,M->P
以上这些都可以用库函数进行直接配置
4`DMA通道x传输数量寄存器(DMA_CNDTRx)(x = 1…7)
5`DMA通道x存储器地址寄存器(DMA_CMARx)(x = 1…7)
6`DMA通道x外设地址寄存器(DMA_CPARx)(x = 1…7)
6.DMA配置结构图
传输计数器:递减,减到零后,自增的地址就会返回到起始地址。写入传输计数器的时候
必须先关闭使能DMA再写入--DMA_CNDTRx
自动重装器:是否恢复传输计数器的最初的值,即是否循环转运数据,自减,每传输一个
就自减一,直到减到0,表示传输完成
软件触发:以最快的速度连续不断的转运数据,一般用于存储器到存储器的转运,一般不
与循环模式同时使用
硬件触发:一般是外设,这些转运需要一定的时机,比如ADC转换完成,串口收到数据,
定时时间……
开关控制:DMA_Cmd函数
数据宽度:少传多,高位补零;多传少,舍弃高位
三、库函数使用
#include "bsp_dma.h"
//const使变量存放在flash中,非易失性存储器
const uint32_t aSRC_Const_Buffer[BUFFER_SIZE]
= { 0x12345678,0x12345677,0x11111111,
0x32165478,0x22554433,0x22335544,
0x33554488,0x22333111,0x54646546};//原始数据-Source
//stm32的变量存放在内部SRAM中,易失性存储器
uint32_t aDST_Buffer[BUFFER_SIZE];
void MtM_DMA_Config()
{
DMA_RCC(DMA1_CLK,ENABLE);//开启AHB时钟
DMA_InitTypeDef DMA_InitStruct;
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)aSRC_Const_Buffer;//外设基地址,数组本质上可以看作指针,我们需要给他强制类型转换为32位的地址
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)aDST_Buffer;//存储器基地址
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;//外设当作Source,即传输方向为外设到寄存器
DMA_InitStruct.DMA_BufferSize = BUFFER_SIZE;//传输的数据个数
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Enable;//外设地址递增
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器地址递增
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;//以一个字节接收
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;//以一个字节发送
DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;//不循环模式
DMA_InitStruct.DMA_Priority = DMA_Priority_VeryHigh;//配置优先级
DMA_InitStruct.DMA_M2M = DMA_M2M_Enable;//使能M->M
DMA_Init(DMA1_Channel1,&DMA_InitStruct);
DMA_ClearFlag(DMA1_FLAG_TC1);//可以先清除传输完成标志位,以避免其他错误
DMA_Cmd(DMA1_Channel1,ENABLE);
}
#ifndef __BSP_DMA_H
#define __BSP_DMA_H
#include "stm32f10x.h"
#define BUFFER_SIZE 9
#define DMA_RCC RCC_AHBPeriphClockCmd
#define DMA1_CLK RCC_AHBPeriph_DMA1
#define DMA2_CLK RCC_AHBPeriph_DMA2
extern uint32_t aDST_Buffer[BUFFER_SIZE];
extern const uint32_t aSRC_Const_Buffer[BUFFER_SIZE];
void MtM_DMA_Config(void);
uint8_t Buffercmp(const uint32_t *Tra,uint32_t *Rec,uint32_t Num);
#endif
为了检测是否传输的数据正确,可以进行判断
uint8_t Buffercmp(const uint32_t *Tra,uint32_t *Rec,uint32_t Num)
{
while(Num--)
{
if(*Tra != *Rec)
{
return 10;
}
Tra++;
Rec++;
}
return 255;
}
补充一点文章来源:https://www.toymoban.com/news/detail-840117.html
文章来源地址https://www.toymoban.com/news/detail-840117.html
到了这里,关于STM32--DMA详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!