DMA简介
DMA全称Direct Memroy Access, 既直接存储器访问。
DMA传输将数据从一个地址空间复制到另一个地址空间。当CPU初始化这个传输动作,传输动作本身是由DMA控制器来实现和完成的。
DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场过程,通过硬件为RAM和IO设备开辟一条直接数据的通道,使得CPU的效率大大提高,为CPU减轻负担。
常用的DMA库函数
void DMA_Init(); //DMA初始化函数
void DMA_Cmd();//DMA使能函数
void DMA_ITConfig();//DMA中断开启
void DMA_SetCurrDataCounter();//设置DMA要传输数量
uint16_t DMA_GetCurrDataCounter();//获取DMA还需要传输的数量
FlagStatus DMA GetFlagStatus();//获取状态标志位
void DMA ClearFlag();//清除标注位
ITStatus DMA GetITStatus();//获取中断标志位
void DMA_ClearlTPendingBit();//清除中断标志位
常用的外设DMA使能库函数
void USART_DMACmd();//串口DMA使能
void ADC_DMACmd();//模拟转数字DMA使能
void DAC DMACmd();//数字转模拟DMA使能
void SDIO_DMACmd();//SDIO DMA使能
void TIM_DMAConfig();//定时器DMA配置数
void TIM DMACmd()l//定时器DMA使能函数
DMA_Init_TypeDef结构体详解
Typedef struct
{
uint32_t DMA_PeripheralBaseAddr; //外设基地址
uint32_t DMA_MemoryBaseAddr; //存储器基地址
uint32_t DMA_DIR;//数据传输方向
uint32_t DMA_BufferSize; //通道传输数据量
uint32_t DMA_Peripherallnc;//外设增量模式
uint32_t DMA_Memorylnc; //存储器增量模式
uint32_t DMA_PeripheralData Size; //外设数据宽度
uint32_t DMA_MemoryDataSize;//存储器数据宽度
uint32_t DMA_Mode; //模式:是否循环
uint32_t DMA_Priority; //优先级
uint32_t DMA M2M; //是否存储器到存储器方式
}DMA_Init_TypeDef
DMA配置程序过程
1.使能DMA时钟
RCC_AHBPeriphClockCmd();
2.初始化DMA通道参数
DMA_Init();
3.使能串口DMA发送,串口DMA使能函数:
USART_DMACmd();
4.使能DMA1通道,启动传输。
DMA_Cmd()
5.查询DMA传输状态
DMA_GetFlag Status(),
6.获取设置通道当前剩余数据量:
DMA_GetCurrDataCounter();
DMA_SetCurrDataCounter();
实验源码
/**
******************************************************************************
* @file : user_rcc_config.c
* @brief : V1.00
******************************************************************************
* @attention
*
******************************************************************************
*/
/* Include 包含---------------------------------------------------------------*/
#include "user_rcc_config.h"
/* Typedef 类型----------------------------------------------------------------*/
/* Define 定义----------------------------------------------------------------*/
/* Macro 宏------------------------------------------------------------------*/
/* Variables 变量--------------------------------------------------------------*/
/* Constants 常量--------------------------------------------------------------*/
/* Function 函数--------------------------------------------------------------*/
/*!
\brief RCC配置
\param[in] none
\param[out] none
\retval none
*/
void Rcc_config(void)
{
/*使能GPIOA时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
/*使能UART1时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
/*使能DMA1时钟*/
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
}
/************************************************************** END OF FILE ****/
/**
******************************************************************************
* @file : user_gpio.c
* @brief : V1.00
******************************************************************************
* @attention
*
******************************************************************************
*/
/* Include 包含---------------------------------------------------------------*/
#include "user_gpio.h"
/* Typedef 类型----------------------------------------------------------------*/
/* Define 定义----------------------------------------------------------------*/
/* Macro 宏------------------------------------------------------------------*/
/* Variables 变量--------------------------------------------------------------*/
/* Constants 常量--------------------------------------------------------------*/
/* Function 函数--------------------------------------------------------------*/
/*!
\brief GPIO初始化函数
\param[in] none
\param[out] none
\retval none
*/
void Gpio_Init(void)
{
/*GPIO结构体*/
GPIO_InitTypeDef GPIO_InitTypeDefstruct;
/*UART1发送引脚配置*/
GPIO_InitTypeDefstruct.GPIO_Mode = GPIO_Mode_AF_PP;//推挽复用输出
GPIO_InitTypeDefstruct.GPIO_Pin = GPIO_Pin_9;
GPIO_InitTypeDefstruct.GPIO_Speed = GPIO_Speed_10MHz;
/*写入结构体到GPIOA*/
GPIO_Init(GPIOA,&GPIO_InitTypeDefstruct);
/*UART1接收引脚配置*/
GPIO_InitTypeDefstruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_InitTypeDefstruct.GPIO_Pin = GPIO_Pin_10;
GPIO_InitTypeDefstruct.GPIO_Speed = GPIO_Speed_10MHz;
/*写入结构体到GPIOA*/
GPIO_Init(GPIOA,&GPIO_InitTypeDefstruct);
}
/************************************************************** END OF FILE ****/
/**
******************************************************************************
* @file : user_uart.c
* @brief : V1.00
******************************************************************************
* @attention
*
******************************************************************************
*/
/* Include 包含---------------------------------------------------------------*/
#include "user_uart.h"
/* Typedef 类型----------------------------------------------------------------*/
/* Define 定义----------------------------------------------------------------*/
/* Macro 宏------------------------------------------------------------------*/
/* Variables 变量--------------------------------------------------------------*/
extern uint16_t USART_RX_STA;
extern uint8_t USART_RX_BUF[200];
/* Constants 常量--------------------------------------------------------------*/
/* Function 函数--------------------------------------------------------------*/
#if 1
#pragma import(__use_no_semihosting)
/*实现Printf代码*/
struct __FILE
{
int handle;
};
FILE __stdout;
void _sys_exit(int x)
{
x = x;
}
//重定义fputc函数
int fputc(int ch, FILE *f)
{
while((USART1->SR&0X40)==0);//循环发送,直到发送完毕
USART1->DR = (u8) ch;
return ch;
}
#endif
/*!
\brief UART1初始化
\param[in] none
\param[out] none
\retval none
*/
void Uart1_Init(u32 bound)
{
/*UART结构体*/
USART_InitTypeDef USART_InitTypeDefstruct;
/*UART结构体配置*/
USART_InitTypeDefstruct.USART_BaudRate = bound; //波特率
USART_InitTypeDefstruct.USART_HardwareFlowControl =USART_HardwareFlowControl_None; //不使用硬件流
USART_InitTypeDefstruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//发送接收使能
USART_InitTypeDefstruct.USART_Parity = USART_Parity_No; //不使用奇偶校验
USART_InitTypeDefstruct.USART_StopBits = USART_StopBits_1; //1个停止位
USART_InitTypeDefstruct.USART_WordLength = USART_WordLength_8b; //8个数据位
/*写入USART1*/
USART_Init(USART1,&USART_InitTypeDefstruct);
/*使能串口1*/
USART_Cmd(USART1,ENABLE);
/*使能串口1的DMA发送*/
USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);
}
/*!
\brief UART1中断服务函数
\param[in] none
\param[out] none
\retval none
*/
void USART1_IRQHandler(void)
{
}
/************************************************************** END OF FILE ****/
/**
******************************************************************************
* @file : user_dma.c
* @brief : V1.00
******************************************************************************
* @attention
*
******************************************************************************
*/
/* Include 包含---------------------------------------------------------------*/
#include "user_dma.h"
/* Typedef 类型----------------------------------------------------------------*/
/* Define 定义----------------------------------------------------------------*/
/* Macro 宏------------------------------------------------------------------*/
/* Variables 变量--------------------------------------------------------------*/
extern uint8_t DMA_Buff[10];
/* Constants 常量--------------------------------------------------------------*/
/* Function 函数--------------------------------------------------------------*/
/*!
\brief DMA1初始化
\param[in] none
\param[out] none
\retval none
*/
void DMA1_Init()
{
/*DMA结构体*/
DMA_InitTypeDef DMA_InitStructure;
/*复位DMA1通道14*/
DMA_DeInit(DMA1_Channel4);
/*DMA配置*/
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR; //DMA外设基地址串口发送寄存器
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)DMA_Buff; //DMA内存基地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //数据传输方向,从内存读取发送到外设
DMA_InitStructure.DMA_BufferSize = 3; //DMA通道的DMA缓存的大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不变
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //数据宽度为8位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //数据宽度为8位
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //不循环
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 x拥有中优先级
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x没有设置为内存到内存传输
/*写入DMA1通道14*/
DMA_Init(DMA1_Channel4, &DMA_InitStructure);
}
/*!
\brief 开启一次DMA传输
\param[in] none
\param[out] none
\retval none
*/
void DMA1_Enable(uint8_t len)
{
/*关闭USART1 TX DMA1 所指示的通道*/
DMA_Cmd(DMA1_Channel4, DISABLE );
/*设置DMA通道的DMA缓存的大小*/
DMA_SetCurrDataCounter(DMA1_Channel4,3);
/*开启USART1 TX DMA1 所指示的通道*/
DMA_Cmd(DMA1_Channel4, ENABLE);
}
/************************************************************** END OF FILE ****/
/**
******************************************************************************
* @file : user_mian.h
* @brief : V1.00
******************************************************************************
* @attention
*
******************************************************************************
*/
/* Include 包含---------------------------------------------------------------*/
#include "stm32f10x.h"
#include <stdbool.h>
#include "user_gpio.h"
#include "user_delay.h"
#include "user_rcc_config.h"
#include "user_uart.h"
#include "user_dma.h"
/* Typedef 类型----------------------------------------------------------------*/
/* Define 定义----------------------------------------------------------------*/
/* Macro 宏------------------------------------------------------------------*/
/* Variables 变量--------------------------------------------------------------*/
uint8_t DMA_Buff[3] = {'a',0x20}; //20 是空格
/* Constants 常量--------------------------------------------------------------*/
/* Function 函数--------------------------------------------------------------*/
int main(void)
{
uint8_t a=0;
/*配置系统中断分组为2位抢占2位响应*/
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
/*延时函数初始化*/
delay_init();
/*RCC配置*/
Rcc_config();
/*GPIO初始化*/
Gpio_Init();
/*USART1初始化*/
Uart1_Init(9600);
/*初始化DMA1*/
DMA1_Init();
/*传输一次*/
/*死循环*/
while(1){
/*开启一次DMA传输*/
DMA1_Enable(3);
delay_ms(1000);
if(a<100)
{
DMA_Buff[0] = DMA_Buff[0]+1;
}else
{
DMA_Buff[0] = 0;
}
}
}
/************************************************************** END OF FILE ****/