DMA介绍
DMA(Direct Memory Access)直接存储器存取
DMA可以提供外设和存储器或者存储器和存储器之间的高速数据传输,无须CPU干预,节省了CPU的资源
12个独立可配置的通道: DMA1(7个通道), DMA2(5个通道)
每个通道都支持软件触发和特定的硬件触发
STM32F103C8T6 DMA资源:DMA1(7个通道)
存储器映像
ROM (Read Only Memory) 只读存储器
RAM (Random Access Memory) 随机存取存储器
DMA框图
DMA基本结构
DMA请求映像
DMA配置
开启AHB外设时钟
操作的是AHB外设时钟使能寄存器 (RCC_AHBENR)
参数一:选择AHB总线上的外设
参数二:使能或失能
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
DMA_InStruct结构体![](https://i-blog.csdnimg.cn/blog_migrate/3be6b9ebfd83376fbab9125a4be5c84f.png)
DMA_PeripheralBaseAddr | 设置 DMA 传输的外设基地址,比如要进行串口 DMA 传输,那么外设基地址为串口接受发送数据存储器 USART1->DR 的地址,表示方法为 &USART1->DR。 |
DMA_MemoryBaseAddr | 内存基地址,也就是存放 DMA 传输数据的内存地址。 |
DMA_DIR | 设置数据传输方向,决定是从外设读取数据到内存还送从内存读取数据发送到外设,也就是外设是源地还是目的地,这里设置为从内存读取数据发送到串口, 所以外设自然就是目的地了,所以选择值为 DMA_DIR_PeripheralDST。 |
DMA_BufferSize | 设置一次传输数据量的大小。 |
DMA_PeripheralInc | 设置传输数据的时候外设地址是不变还是递增。如果设置 为递增,那么下一次传输的时候地址加 1,这里因为我们是一直往固定外设地址&USART1->DR 发送数据,所以地址不递增,值为 DMA_PeripheralInc_Disable; |
DMA_MemoryInc | 设置传输数据时候内存地址是否递增。这个参数和 DMA_PeripheralInc 意思接近,只不过针对的是内存。这里我们的场景是将内存中连续存储单 元的数据发送到串口,毫无疑问内存地址是需要递增的,所以值为 DMA_MemoryInc_Enable。 |
DMA_PeripheralDataSize | 设置外设的数据长度是为字节传输(8bits),半字传输 (16bits)还是字传输(32bits),这里我们是8位字节传输,所以值设置为DMA_PeripheralDataSize_Byte。 |
DMA_MemoryDataSize | 设置内存的数据长度,和第八个参数意思接近,这 里我们同样设置为字节传输 DMA_MemoryDataSize_Byte。 |
DMA_Mode | 设置 DMA 模式是否循环采集,比如我们要从内存中采集 64 个字节发送到串口,如果设置为重复采集,那么它会在 64 个字节采集完成之后继续从内存的第一个地址采集,如此循环。这里我们设置为一次连续采集完成之后不循环。所以设置值 为 DMA_Mode_Normal。 |
DMA_Priority | 设置 DMA 通道的优先级,有低,中,高,超高三种模式,这里我们设置优先级别为中级,所以值为 DMA_Priority_Medium。优先级可以随便设置,因为我们只有一个数据流被开启了。假设有多个数据流开启(最多 8 个),那么就要设置优先级了,DMA 仲裁器将根据这些优先级的设置来决定先执行那个数据流的 DMA。优先级越高的,越早执行,当优先级相同的时候,根据硬件上的编号来决定哪个先执行(编号越小越优先)。 |
DMA_M2M | 存储器到存储器模式,使用存储器到存储器时用到,可启动存储器到存储器模式。 |
初始化DMA
操作以下寄存器:
DMA通道x配置寄存器(DMA_CCRx)(x = 1…7)
DMA通道x传输数量寄存器(DMA_CNDTRx)(x = 1…7)
DMA通道x外设地址寄存器(DMA_CPARx)(x = 1…7)
DMA通道x存储器地址寄存器(DMA_CMARx)(x = 1…7)
DMA_Init(DMAy_Channelx,&DMA_InitStruct);
使能DMA
操作以下寄存器:
DMA通道x配置寄存器(DMA_CCRx)(x = 1…7)
DMA_Cmd(DMAy_Channelx, ENABLE);
配置全代码如下:
#include "DMA.h"
//内存地址
unsigned char DMA_MemoryBaseAddr[] = {"mmmmm"};
uint32_t DMA_BufferSize = sizeof(DMA_MemoryBaseAddr);
/*DMA初始化*/
void DMA_InitA(DMA_Channel_TypeDef* DMAy_Channelx)
{
/*使能DMA时钟*/
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
DMA_InitTypeDef DMA_InitStructure;
/*配置DMA参数*/
//配置内存地址
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)DMA_MemoryBaseAddr;
//配置外设地址
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR;
//配置数据传输方向 外设作为数据传输目的地(外设作为数据源)
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
//配置数据传输大小
DMA_InitStructure.DMA_BufferSize = DMA_BufferSize;
//禁止外设地址递增
DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
//允许内存地址是否递增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
//配置外设数据单位 8位字节传输
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
//配置内存数据单位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
//配置DMA模式 单次传输(循环传输)
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
//配置DMA优先级
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
//配置是否使能从内存到内存传输
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
//配置DMA通道初始化
DMA_Init(DMAy_Channelx,&DMA_InitStructure);
DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);
//使能DMA
DMA_Cmd(DMAy_Channelx,ENABLE);
}
/*DMA发送函数*/
void DMASend(DMA_Channel_TypeDef* DMAy_Channelx,unsigned char* MBuff,unsigned int MBuffSize)
{
DMA_Cmd(DMAy_Channelx,DISABLE);
DMAy_Channelx->CMAR = (u32)MBuff;
DMAy_Channelx->CNDTR = MBuffSize;
DMA_Cmd(DMAy_Channelx,ENABLE);
}