STM32标准库开发——DMA数据转运【存储器与存储器/外设与存储器】

发布时间:2024年01月18日

DMA转运基本结构图

在这里插入图片描述

在转运过程中,Flash是比较特殊的存储器,只能读不能写,因此只能是源地址不能是目的地址
自动重装器启用时不能使用软件触发,否则软件触发将永远停不下来 M2M(Memory To
Memory)置为0时开启硬件触发,为1时开启软件触发 传输计数器需要赋值初始值,意味着转运几次数据
在代码运行时,Const声明的数据存储在Flash中,其他存储在SRAM中。

DMA存储器与存储器

开启DMA1时钟

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);

修改DMA配置寄存器,设置为一次性转运模式,外设与存储器地址均自增,Size代表传输次数,AddaA,AddaB代表不同数组起始地址。

DMA_InitTypeDef DMA_InitStruct;
DMA_InitStruct.DMA_BufferSize=Size;
DMA_InitStruct.DMA_DIR=DMA_DIR_PeripheralSRC;
DMA_InitStruct.DMA_M2M=DMA_M2M_Enable;
DMA_InitStruct.DMA_MemoryBaseAddr=AddaB;
DMA_InitStruct.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;
DMA_InitStruct.DMA_MemoryInc=DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_Mode=DMA_Mode_Normal;
DMA_InitStruct.DMA_PeripheralBaseAddr=AddaA;
DMA_InitStruct.DMA_PeripheralDataSize=DMA_MemoryDataSize_Byte;
DMA_InitStruct.DMA_PeripheralInc=DMA_PeripheralInc_Enable;
DMA_InitStruct.DMA_Priority=DMA_Priority_Medium;
DMA_Init(DMA1_Channel1,&DMA_InitStruct);

每次启动DMA前需要先将DMA关闭,为传输次数寄存器赋值,再启动DMA

DMA_Cmd(DMA1_Channel1,DISABLE);
DMA_SetCurrDataCounter(DMA1_Channel1,MYDMA_Size);
DMA_Cmd(DMA1_Channel1,ENABLE);

等待DMA转运完成

while(DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);
DMA_ClearFlag(DMA1_FLAG_TC1);

AD外设与存储器(连续扫描+单次/循环转换模式)

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);

	//ADC时钟主频来自ADC预分频器
	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;
	GPIO_Init(GPIOA,&GPIO_InitStruct);

	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_ContinuousConvMode=DISABLE;
/*
	如果设置为Enable,那么AD会自动循环转换
	ADC_InitStruct.ADC_ContinuousConvMode=ENABLE;
*/
	ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;
	ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;
	ADC_InitStruct.ADC_Mode=ADC_Mode_Independent;
	ADC_InitStruct.ADC_NbrOfChannel=4;
	ADC_InitStruct.ADC_ScanConvMode=ENABLE;
	ADC_Init(ADC1,&ADC_InitStruct);
	
	DMA_InitTypeDef DMA_InitStruct;
	DMA_InitStruct.DMA_BufferSize=4;
	DMA_InitStruct.DMA_DIR=DMA_DIR_PeripheralSRC;
	DMA_InitStruct.DMA_M2M=DMA_M2M_Disable;
	DMA_InitStruct.DMA_MemoryBaseAddr=(uint32_t)&Ad_Value;
	DMA_InitStruct.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord;
	DMA_InitStruct.DMA_MemoryInc=DMA_MemoryInc_Enable;
	DMA_InitStruct.DMA_Mode=DMA_Mode_Normal;
/*
	如果设置为Enable,DMA会在传输次数寄存器为0后自动赋值为原来的值,继续转运,搭配AD转换的循环模式可以实现高度硬件自动化搬运	
	DMA_InitStruct.DMA_Mode=DMA_Mode_Circular;
*/
	DMA_InitStruct.DMA_PeripheralBaseAddr=(uint32_t)&ADC1->DR;
	DMA_InitStruct.DMA_PeripheralDataSize=DMA_MemoryDataSize_Byte;
	DMA_InitStruct.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
	DMA_InitStruct.DMA_Priority=DMA_Priority_Medium;
	DMA_Init(DMA1_Channel1,&DMA_InitStruct);
	
	DMA_Cmd(DMA1_Channel1,ENABLE);
	
	ADC_DMACmd(ADC1,ENABLE);
	ADC_Cmd(ADC1,ENABLE);
	
	ADC_ResetCalibration(ADC1);
	while(ADC_GetResetCalibrationStatus(ADC1) == SET);
	ADC_StartCalibration(ADC1);
	while(ADC_GetCalibrationStatus(ADC1)==SET);
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);
/*	
	如果配置为连续扫描+循环转换 AD转换只需要在初始化末尾启动一次就可以了,DMA也不用去判断是否转换完成,需要的数据直接拿取即可。
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);
*/
/*
	如果是AD单次转换模式,才需要每次都配置一遍DMA,以及判断DMA是否转运结束
*/
DMA_Cmd(DMA1_Channel1,DISABLE);
DMA_SetCurrDataCounter(DMA1_Channel1,4);
DMA_Cmd(DMA1_Channel1,ENABLE);	

ADC_SoftwareStartConvCmd(ADC1,ENABLE);

while(DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);
DMA_ClearFlag(DMA1_FLAG_TC1);

注意:DMA在第一次转运完成后,在单次模式下,如果需要再次开启,必须先失能DMA,配置传输计数器的值,再使能DMA才能开始转运

文章来源:https://blog.csdn.net/zhoutan001/article/details/135672689
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。