一、什么是DMA
1、M to M:FLASH to SRAM,把内部FLASH的数据传输到内部的SRAM(FLASH最常用来存储代码)。
2、M to P:SRAM to 串口,DMA的传数据不需要占用CPU。
3、M to M 的编程要点
(1).在FLASH 中定义好要传输的数据,在SRAM中定义好用来接收FLASH数据的变量。
(2).初始化DMA,主要是配置DMA初始化结构体。
(3).编写比较函数。
(4).编写main函数。
二、各个通道的DMA请求
三、DMA的仲裁器
四、DMA初始化结构体
1、DMA初始化结构体各成员介绍
要注意的是外设地址和寄存器地址都是32位的。只有寄存器到寄存器的模式才使能M2M,传输方向一是外设作为源,二是外设作为目的地。外设的数据宽度与寄存器数据宽度一样。
2、DMA初始化结构体各成员功能
五、寄存器到串口程序演示DMA的作用
1、DMA的初始化
#include "dma_mtop.h"
//typedef struct
//{
// 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;
//Memory ->P(USART->DR) 地址偏移 0x04
/* 定义DMA传输目标存储器
* 存储在内部的SRAM中
*/
uint8_t Send_Buffer[BUFFER1_SIZE];
void MYDMA_MTOP_Init(void)
{
//打开DMA1的时钟
RCC_AHBPeriphClockCmd(MTP_DMA_CLK,ENABLE);
//初始化DMA
DMA_InitTypeDef DMA_InitStruct;
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)USART_DR_ADRESS;
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)Send_Buffer;
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStruct.DMA_BufferSize = BUFFER1_SIZE;
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//4个字节32位
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
DMA_InitStruct.DMA_Priority = DMA_Priority_High;//由于这里只使用了DAM1这一个通道所以优先级可随意配置,当使用多个通道时则需要比较通道的大小,通道越小优先级越高。且DAM1的优先级大于DMA2的优先级。
DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;
DMA_Init(MTP_DMA_Channel, &DMA_InitStruct);//MtoM模式下,通道可任意选择
DMA_ClearFlag(MTP_DMA_FLAG_TC);
DMA_Cmd(MTP_DMA_Channel, ENABLE);
}
#include "stm32f10x.h"
// 要发送的数据大小
#define BUFFER1_SIZE 5000
#define MYDMA1 1
#define MYDMA2 0
#if MYDMA1
#define MTP_DMA_CLK RCC_AHBPeriph_DMA1
#elif MYDMA2
#define MTP_DMA_CLK RCC_AHBPeriph_DMA2
#endif
#define MTP_DMA_Channel DMA1_Channel4
#define MTP_DMA_FLAG_TC DMA1_FLAG_TC4
#define USART_DR_ADRESS (USART1_BASE+0x04)
void MYDMA_MTOP_Init(void);
#endif
六、验证
void MtoP(void)
{
for(uint16_t i=0;i<BUFFER1_SIZE;i++)
{
Send_Buffer[i] = 'A';
}
MYDMA_MTOP_Init();
USART_DMACmd(DEBUG_USARTx, USART_DMAReq_Tx, ENABLE);
}
int main(void)
{
LED_GPIO_Config();
KEY_Init();
KEYPA0_EXTI_Init();
Myusart_Init();
MtoP();
while(1)
{
LED_RED_TOGGLE();
Delay(0xFFFFFF);
}
}
首先我们将Send_Buffer[BUFFER1_SIZE]这个数组赋值是每一个元素都为A,然后调用MYDMA_MTOP_Init()这个初始化函数,然后使能串口DMA函数(USART_DMACmd),最后在while(1)中的调用小灯翻转函数。