DMA: Data memory Access, 直接存储器访问。 可以把数据从一个地方传输到另一个地方,而且不占用CPU。 DMA1: 7个通道,M->M,P->M,M->P. DMA2: 5个通道 , M->M,P->M,M->P. (存在大容量、互联型(f105/f107)产品中)
系统结构

DMA1请求映射

DMA2请求映射

多个DMA同时请求:
1.软件阶段,DMA_CCRx DMA通道配置寄存器PL--->设置通道优先级
2.硬件阶段,通道编号小的优先级大,DMA1优先级大于DMA2的优先级
下面用两种传输方向来介绍DMA结构体
1.M - > M: Flash to SRAM, 内部FLASH (CODE)的数据传输到内部的SRAM(变量)
2.M -> P : SRAM to 串口 + LED,延时DMA传输数据不需要占用CPU
注:当源端数据宽度和目标数据宽度不一样时可参考中文参考手册DMA模块数据对齐表
M->M:
1.在FLASH中定义好要传输的数据,在SRAM中定义好接收FLASH数据的变量
2.初始化DMA结构体
3.编写比较函数
4.main函数应用
dma.c:
cs
#include "stm32f10x.h"
#include "dma.h"
//const 关键字 把数组Buffer定义为常量类型,表示数据存储在内部的flash中
const uint32_t SRC_Buffer[BUFFER_SIZE] = {
0x01020304,0x05060708,0x090A0B0C,0x0D0E0F10,
0x11121314,0x15161718,0x191A1B1C,0x1D1E1F20,
0x21222324,0x25262728,0x292A2B2C,0x2D2E2F30,
0x31323334,0x35363738,0x393A3B3C,0x3D3E3F40
};
//定义DMA传输的目标存储器,存储在内部SRAM
uint32_t DST_BUFFER[BUFFER_SIZE];
void DMA_MTM_Init(void)
{
DMA_InitTypeDef DMA_InitStruct;
RCC_AHBPeriphClockCmd( RCC_AHBPeriph_DMA1,ENABLE);
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)SRC_Buffer;//外设地址
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)DST_BUFFER;//存储器地址
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;//传输方向,外设作为源
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_High;//通道优先级
DMA_InitStruct.DMA_M2M = DMA_M2M_Enable;//存储器到存储器模式使能
DMA_Init(DMA1_Channel6,&DMA_InitStruct);
DMA_ClearFlag( DMA1_FLAG_TC6);//清除发送完成标志位
DMA_Cmd(DMA1_Channel6,ENABLE);
}
uint8_t Buffercmp(const uint32_t* pBffer1, uint32_t *pBffer2,uint32_t BfferLength)
{
while(BfferLength--)//数据长度递减
{
if(*pBffer1 != *pBffer2)//判断两个数据源是否相等
{
return 0; //对应数据源不相等返回0
}
pBffer1++; //递增两个数据源地址指针
pBffer2++;
}
return 1; //完成判断并且对应数据源相等返回1
}
dma.h
cs
#ifndef _DMA_H_
#define _DMA_H_
#include "stm32f10x.h"
void DMA_MTM_Init(void);
uint8_t Buffercmp(const uint32_t* pBffer1, uint32_t *pBffer2,uint32_t BfferLength);
void USART_DMA_Init(void);
#define BUFFER_SIZE 16
#define USART_DR_ADDR (USART1_BASE+0X04)
#define SEND_SIZE 500
#endif
main.c
cs
int main(void)
{
uint8_t status = 0;
extern const uint32_t SRC_Buffer[BUFFER_SIZE] ;
extern uint32_t DST_BUFFER[BUFFER_SIZE];
LED_Init();
DMA_MTM_Init();
status = Buffercmp(SRC_Buffer,DST_BUFFER,BUFFER_SIZE);
if(status == 0)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_1);//如果返回值为0,则传输失败PA1引脚输出低电平led亮
}
else
{
GPIO_SetBits(GPIOA, GPIO_Pin_1);//相反
}
while(1)
{
}
}
M->P:
dma.c:
cs
uint8_t SendBuffer[SEND_SIZE];
void USART_DMA_Init(void)
{
DMA_InitTypeDef DMA_InitStruct;
RCC_AHBPeriphClockCmd( RCC_AHBPeriph_DMA1,ENABLE);
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)USART_DR_ADDR;//外设地址(串口1数据寄存器的地址)
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)SendBuffer;//存储器地址
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST;//传输方向,外设作为传输目标
DMA_InitStruct.DMA_BufferSize = SEND_SIZE;//传输数目
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器地址增量模式
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址增量模式关闭
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设数据宽度
DMA_InitStruct.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;//存储器数据宽度
DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;//模式选择只发送一次
DMA_InitStruct.DMA_Priority = DMA_Priority_High;//通道优先级
DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;//存储器到存储器模式关闭
DMA_Init(DMA1_Channel4,&DMA_InitStruct);//初始化DMA1通道4结构体
DMA_ClearFlag( DMA1_FLAG_TC4);//清除发送完成标志位
DMA_Cmd(DMA1_Channel4,ENABLE);//DMA1通道4使能
}
dma.h
cs
#ifndef _DMA_H_
#define _DMA_H_
#include "stm32f10x.h"
void DMA_MTM_Init(void);
uint8_t Buffercmp(const uint32_t* pBffer1, uint32_t *pBffer2,uint32_t BfferLength);
void USART_DMA_Init(void);
#define BUFFER_SIZE 16
#define USART_DR_ADDR (USART1_BASE+0X04)
#define SEND_SIZE 500
#endif
usart.c
cs
// USART1初始化
void myusart_init(void)
{
GPIO_InitTypeDef GPIOInitStruct;
USART_InitTypeDef USARTInitStruct;
NVIC_InitTypeDef NVIC_Initstruct;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1,ENABLE);
//A9 TX
GPIOInitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIOInitStruct.GPIO_Speed = GPIO_Speed_10MHz;
GPIOInitStruct.GPIO_Pin = GPIO_Pin_9;
GPIO_Init(GPIOA,&GPIOInitStruct);
//A10 RX
GPIOInitStruct.GPIO_Mode = GPIO_Mode_IPU;
GPIOInitStruct.GPIO_Pin = GPIO_Pin_10;
GPIO_Init(GPIOA,&GPIOInitStruct);
USARTInitStruct.USART_BaudRate = 115200;
USARTInitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USARTInitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USARTInitStruct.USART_Parity = USART_Parity_No;
USARTInitStruct.USART_StopBits = USART_StopBits_1;
USARTInitStruct.USART_WordLength = USART_WordLength_8b;
USART_Init(USART1,&USARTInitStruct);
USART_Cmd(USART1,ENABLE);
USART_ITConfig(USART1, USART_IT_RXNE,ENABLE);
NVIC_Initstruct.NVIC_IRQChannel = USART1_IRQn;
NVIC_Initstruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_Initstruct.NVIC_IRQChannelSubPriority = 0;
NVIC_Initstruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_Initstruct);
}
main.c
cs
int main(void)
{
uint16_t i=0;
extern uint8_t SendBuffer[SEND_SIZE];
for(i=0;i<SEND_SIZE;i++)
{
SendBuffer[i] = '0';
}
myusart_init();
USART_DMA_Init();
USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);
while(1)
{
}
}
传输完成:
