STM32 DMA直接存储器存取

一、DMA简介

  • DMA(Direct Memory Access)直接存储器存取
  • DMA可以提供外设和存储器或者存储器和存储器之间的高速数据传输,无须CPU干预,节省了CPU的资源
  • 12个独立可配置的通道: DMA1(7个通道), DMA2(5个通道)
  • 每个通道都支持软件触发(存储器和存储器)和特定的硬件触发(外设和存储器)
  • STM32F103C8T6 DMA资源:DMA1(7个通道)

二、存储器地址

三、DMA框图

四 、DMA基本结构

五、两种转运模式

六、代码部分

cpp 复制代码
void DMA_DeInit(DMA_Channel_TypeDef* DMAy_Channelx);//恢复缺损配置
void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct);//初始化
void DMA_StructInit(DMA_InitTypeDef* DMA_InitStruct);//结构体初始化
void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx, FunctionalState NewState);//使能
void DMA_ITConfig(DMA_Channel_TypeDef* DMAy_Channelx, uint32_t DMA_IT, FunctionalState NewState);//中断输出使能

//设置当前数据寄存器
void DMA_SetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx, uint16_t DataNumber);

 //获取当前数据寄存器,返回传输寄存器的值
uint16_t DMA_GetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx);
FlagStatus DMA_GetFlagStatus(uint32_t DMAy_FLAG);//获取标志位状态
void DMA_ClearFlag(uint32_t DMAy_FLAG);//清除标志位
ITStatus DMA_GetITStatus(uint32_t DMAy_IT);//获取中断状态
void DMA_ClearITPendingBit(uint32_t DMAy_IT);//清除中断挂起位 

数据转运整体代码:

cpp 复制代码
#include "stm32f10x.h"                  // Device header

//DMA转运的3个条件:
//1:传输计数器大于0
//2:触发源有触发信号(软件触发,所以一直都有触发信号)
//3:DMA使能
 
 uint16_t MyDMA_size;
 
void MyDMA_init(uint32_t AddrA,uint32_t AddrB,uint16_t Size)
{
	MyDMA_size = Size;
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);//DMA是AHB总线设备
	
	DMA_InitTypeDef DMA_InitStruct;
	DMA_InitStruct.DMA_PeripheralBaseAddr = AddrA; //外设站点的起始地址,写一个32位的地址
	DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; 
	//外设站点的数据宽度,这里是以字节的方式传输
// DMA_PeripheralDataSize_Byte     字节,就是uint8_t   
// DMA_PeripheralDataSize_HalfWord    半字,就是uint16_t
// DMA_PeripheralDataSize_Word        字,就是uint32_t
	                                                                     
	DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Enable;      //外设站点的是否自增
	
	DMA_InitStruct.DMA_MemoryBaseAddr = AddrB;     //存储器站点的起始地址
	DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;     //存储器站点的数据宽度
	DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;          //存储器站点的是否自增,选择自增。
	
	
	DMA_InitStruct.DMA_DIR  = DMA_DIR_PeripheralSRC;               //传输方向
// DMA_DIR_PeripheralDST         外设站点作为DST,destination,目的地,传输方向是存储器站点到外设站点     
// DMA_DIR_PeripheralSRC         外设站点作为	SRC,source,源头,外设站点到存储器站点的传输方向     
	DMA_InitStruct.DMA_BufferSize = Size;         //缓冲区大小,也就是传输计数器,传输次数
	DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;    //传输模式,是否使用自动重装
	DMA_InitStruct.DMA_M2M = DMA_M2M_Enable;      
	//选择是否是存储器到存储器,也就是选择硬件触发还是软件触发,这里选择软件触发
	DMA_InitStruct.DMA_Priority = DMA_Priority_Medium;    //优先级,按照参数要求,给一个优先级
	 
	DMA_Init(DMA1_Channel1,&DMA_InitStruct);
	
	
	DMA_Cmd(DMA1_Channel1,DISABLE);
}

void MyDMA_Transfer(void)  //DMA传输函数
{
	 //需要给传输计数器赋值,需要先给DMA失能!!!!!!!!!!
	DMA_Cmd(DMA1_Channel1,DISABLE);
	
	DMA_SetCurrDataCounter(DMA1_Channel1,MyDMA_size);
	DMA_Cmd(DMA1_Channel1,ENABLE);
	
	//等待转运完成
while	(DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET); 	//这里选择转运完成标志位
DMA_ClearFlag(DMA1_FLAG_TC1);
//DMA1_FLAG_GL1  全局标志位
//DMA1_FLAG_TC1  转运完成标志位
//DMA1_FLAG_HT1  转运过半标志位
//DMA1_FLAG_TE1  转运错位标志位
}

AD多通道加DMA转运代码:

cpp 复制代码
#include "stm32f10x.h"                  // Device header

uint16_t AD_Value[4];

void AD_init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);//DMA是AHB总线设备
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6); 
	
	GPIO_InitTypeDef GPIO_InitStruct;                     //第一个是结构体类型,后面是它的名字
	GPIO_InitStruct.GPIO_Mode= GPIO_Mode_AIN;         //模式为模拟输入
	GPIO_InitStruct.GPIO_Pin= GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;            //开启所有端口  
	GPIO_InitStruct.GPIO_Speed= GPIO_Speed_50MHz;         //选择50mhz
	GPIO_Init(GPIOA, &GPIO_InitStruct);
	

	
	//配置序列里的通道((1:ADCX,2:指定的通道,3:序列几的位置,4:指定通道的采样时间))
	ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_1,2,ADC_SampleTime_55Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_2,3,ADC_SampleTime_55Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_3,4,ADC_SampleTime_55Cycles5);


	ADC_InitTypeDef ADC_InitStruct;
	ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;//ADC转换模式,这里选择独立模式,ADC1和ADC2各自转换
	ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;//左对齐还是右对齐
  ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
	//外部触发转换选择,触发控制的触发源选择,这里的参数是外部触发none,也就是不使用外部触发,使用内部触发
	ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;//连续转换模式,非扫描模式
	ADC_InitStruct.ADC_ScanConvMode =  ENABLE;      //扫描转换模式,单次转换
  ADC_InitStruct.ADC_NbrOfChannel =  4;           //通道数目,
  ADC_Init(ADC1,&ADC_InitStruct);
	
	//中断和看门狗如果有需要可以在下面配置//
	
	
	//*******************//
	
	
	//****************DMA配置***************//
	
	DMA_InitTypeDef DMA_InitStruct;
	DMA_InitStruct.DMA_PeripheralBaseAddr =(uint32_t)&ADC1->DR; //外设站点的起始地址,写一个32位的地址
	DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; 
	//外设站点的数据宽度,这里是以字节的方式传输
// DMA_PeripheralDataSize_Byte     字节,就是uint8_t   
// DMA_PeripheralDataSize_HalfWord    半字,就是uint16_t
// DMA_PeripheralDataSize_Word        字,就是uint32_t
	                                                                     
	DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;      //外设站点的是否自增
	
	DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)AD_Value;     //存储器站点的起始地址
	DMA_InitStruct.DMA_MemoryDataSize = DMA_PeripheralDataSize_HalfWord;     //存储器站点的数据宽度
	DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;          //存储器站点的是否自增,选择自增。
	
	
	DMA_InitStruct.DMA_DIR  = DMA_DIR_PeripheralSRC;               //传输方向
// DMA_DIR_PeripheralDST         外设站点作为DST,destination,目的地,传输方向是存储器站点到外设站点     
// DMA_DIR_PeripheralSRC         外设站点作为	SRC,source,源头,外设站点到存储器站点的传输方向     
	DMA_InitStruct.DMA_BufferSize = 4;         //缓冲区大小,也就是传输计数器,传输次数
	DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;    //传输模式,是否使用自动重装
	DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;      
	//选择是否是存储器到存储器,也就是选择硬件触发还是软件触发,这里选择软件触发
	DMA_InitStruct.DMA_Priority = DMA_Mode_Circular;    //优先级,按照参数要求,给一个优先级
	 
	DMA_Init(DMA1_Channel1,&DMA_InitStruct);
	
	ADC_DMACmd(ADC1,ENABLE);
	DMA_Cmd(DMA1_Channel1,ENABLE);
	
	
	
	//*****************************************//
	
	ADC_Cmd(ADC1,ENABLE);
	
	//***********对ADC进行校准*****************//
	ADC_ResetCalibration(ADC1);//复位校准
  while (ADC_GetResetCalibrationStatus(ADC1) == SET);//返回复位校准的状态,一直循环等它硬件清0.说明复位校准完成
  ADC_StartCalibration(ADC1);//启动校准,内部电路自动进行校准
  while (ADC_GetCalibrationStatus(ADC1) == SET);//获取校准状态,等待校准是否完成

	ADC_SoftwareStartConvCmd(ADC1,ENABLE); //软件触发转换的函数,ADC开始转换。

}
相关推荐
沉在嵌入式的鱼4 小时前
linux串口对0X0D、0X0A等特殊字符的处理
linux·stm32·单片机·特殊字符·串口配置
学习路上_write4 小时前
AD5293驱动学习
c语言·单片机·嵌入式硬件·学习
影阴4 小时前
存储器和寄存器
stm32·单片机·嵌入式硬件
吃西瓜的年年5 小时前
3. C语言核心语法2
c语言·嵌入式硬件·改行学it
李洛克076 小时前
RDMA CM UDP 通信完整指南
单片机·网络协议·udp
思茂信息6 小时前
CST电动车EMC仿真——电机控制器MCU滤波仿真
javascript·单片机·嵌入式硬件·cst·电磁仿真
小曹要微笑6 小时前
I2C总线技术解析(纯文字版)
单片机·嵌入式硬件·esp32·iic
我送炭你添花6 小时前
可编程逻辑器件(PLD)的发展历程、原理、开发与应用详解
嵌入式硬件·fpga开发
袖手蹲6 小时前
Arduino UNO Q 从 Arduino Cloud 远程控制闪烁 LED
人工智能·单片机·嵌入式硬件·电脑
平凡灵感码头7 小时前
第一次做蓝牙产品,从零开发 嵌入式开发日志(2)AC63NSDK 完整合并版目录说明
stm32·单片机·嵌入式硬件