雅特力AT32F403A,解决DMA搬运ADC多通道数据错位问题

使用ADC1采集5路ADC通道采集数据,发现采集过程中出现数据移位问题。

原始ADC与DMA配置:

//******************************************************************************
// 函数功能: DMA配置
// 函数参数:
// 返 回 值:
// 说    明:配置DMA的ADC采集
//******************************************************************************
static void ADC_DmaConfig(void)
{
	dma_init_type dma_init_struct;
	//DAM1时钟是能
  crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE);
	//中断分组
  nvic_irq_enable(DMA1_Channel1_IRQn, 0, 0);
	//重置DMA1通道
  dma_reset(DMA1_CHANNEL1);
	//初始化配置结构体
  dma_default_para_init(&dma_init_struct);
	//传输数据长度				50
  dma_init_struct.buffer_size = 25;
	//传输方向						外设到地址
  dma_init_struct.direction = DMA_DIR_PERIPHERAL_TO_MEMORY;
	//内存地址
  dma_init_struct.memory_base_addr = (uint32_t)g_adc_original_data;
	//字节宽度						ADC是16位的
  dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_HALFWORD;
	//内存增量模式
  dma_init_struct.memory_inc_enable = TRUE;
	//外设地址
  dma_init_struct.peripheral_base_addr = (uint32_t)&(ADC1->odt);
	//字节宽度
  dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_HALFWORD;
	//增量模式						关闭
  dma_init_struct.peripheral_inc_enable = FALSE;
	//仲裁优先级					高
  dma_init_struct.priority = DMA_PRIORITY_HIGH;
	//循环模式						开启
  dma_init_struct.loop_mode_enable = TRUE;
	//初始配置
  dma_init(DMA1_CHANNEL1, &dma_init_struct);
	//中断使能
	dma_interrupt_enable(DMA1_CHANNEL1,DMA_FDT_INT,TRUE);
  //DMA通道1使能
  dma_channel_enable(DMA1_CHANNEL1, TRUE);
	
}
//******************************************************************************
// 函数功能: ADC配置
// 函数参数:
// 返 回 值:
// 说    明:ADC初始化配置
//******************************************************************************
static void ADC_AdcConfig(void)
{
	adc_base_config_type adc_base_struct;
	//ADC1_1GPIO初始化
  GPIO_SetPinMode(GPIOA,GPIO_PINS_0, GPIO_MODE_ANALOG, GPIO_PULL_NONE);
	//ADC1_5GPIO初始化
  GPIO_SetPinMode(GPIOA,GPIO_PINS_1, GPIO_MODE_ANALOG, GPIO_PULL_NONE);
	//ADC1_6GPIO初始化
  GPIO_SetPinMode(GPIOA,GPIO_PINS_5, GPIO_MODE_ANALOG, GPIO_PULL_NONE);
	//ADC1_7GPIO初始化
  GPIO_SetPinMode(GPIOA,GPIO_PINS_6, GPIO_MODE_ANALOG, GPIO_PULL_NONE);
	//ADC1_8GPIO初始化
  GPIO_SetPinMode(GPIOA,GPIO_PINS_7, GPIO_MODE_ANALOG, GPIO_PULL_NONE);
	//使能ADC1时钟
	crm_periph_clock_enable(CRM_ADC1_PERIPH_CLOCK, TRUE);
	//配置时钟
  crm_adc_clock_div_set(CRM_ADC_DIV_6);
	//设置独立模式
  adc_combine_mode_select(ADC_INDEPENDENT_MODE);
	//配置结构体初始化
  adc_base_default_para_init(&adc_base_struct);
	//开启序列模式
  adc_base_struct.sequence_mode = TRUE;
	//开启反复转化
  adc_base_struct.repeat_mode = TRUE;
	//设置右对齐
  adc_base_struct.data_align = ADC_RIGHT_ALIGNMENT;
	//设置转化通道数
  adc_base_struct.ordinary_channel_length = 5;
	//配置ADC1
  adc_base_config(ADC1, &adc_base_struct);
	//配置通道序列
  adc_ordinary_channel_set(ADC1, ADC_CHANNEL_0, 1, ADC_SAMPLETIME_28_5);
	adc_ordinary_channel_set(ADC1, ADC_CHANNEL_1, 2, ADC_SAMPLETIME_28_5);
	adc_ordinary_channel_set(ADC1, ADC_CHANNEL_5, 3, ADC_SAMPLETIME_28_5);
	adc_ordinary_channel_set(ADC1, ADC_CHANNEL_6, 4, ADC_SAMPLETIME_28_5);
	adc_ordinary_channel_set(ADC1, ADC_CHANNEL_7, 5, ADC_SAMPLETIME_28_5);
	//设置触发转换方式
  adc_ordinary_conversion_trigger_set(ADC1, ADC12_ORDINARY_TRIG_SOFTWARE, TRUE);
	//开启DMA模式
  adc_dma_mode_enable(ADC1, TRUE);
	//使能ADC
	adc_enable(ADC1, TRUE);
	//上电初始化
  adc_calibration_init(ADC1);
	//等待配置完成
	while(adc_calibration_init_status_get(ADC1));
	//上电校准
	adc_calibration_start(ADC1);
	//等待配置完成
  while(adc_calibration_status_get(ADC1));
}
//DAM1中断处理函数
void DMA1_Channel1_IRQHandler(void)
{
  if(dma_flag_get(DMA1_FDT1_FLAG) != RESET)
  {
		//DMA搬运ADC数据完成标志有效
		g_adc_conversion = true;
		//清理标志
    dma_flag_clear(DMA1_FDT1_FLAG);
		//关闭DMA通道
    dma_channel_enable(DMA1_CHANNEL1, FALSE);
		//重写装载
		DMA1_CHANNEL1->dtcnt = 25;
		//开启DMA传输
		dma_channel_enable(DMA1_CHANNEL1, TRUE);
  }
}

我这里是采集5个ADC通道的数据,每周期每个通道采集5个数据,开启了ADC的反复转换和DMA的循环模式,在DMA中断中处理对应采集数据完成标志位和重载DMA传输。

问题原因分析:

ADC的转换是一直开启的,ADC开启反复转换后会按照配置转换周期不停的采集转换,在DMA搬运数据完成后进入中断处理时ADC是不会停止转换的。

由于DMA每次搬运数据是从当前ADC采集转换完成后的开始往初始地址0开始搬运,不能保证搬运开始的第一个数据就是自己配置的第一个通道,所以导致出现DMA搬运数据错位的问题。

解决方法:

由于我们ADC转换是使用的软件触发的方式,所以可以在DMA搬运数据完成后在中断中将ADC转换给停止掉(由于ADC开启了反复转换,ADC还是会自动开启的),所以考虑关闭掉DMA循环模式,在DMA中断中重新开启DMA数据搬运和停止ADC数据转换。

//DAM1中断处理函数
void DMA1_Channel1_IRQHandler(void)
{
  if(dma_flag_get(DMA1_FDT1_FLAG) != RESET)
  {
		g_colect_index += 5;
		for(u8 i= 0;i<ADC_GATHER_CHANNELNUM; i++)
		{
			g_colect_org_data[g_colect_index - ADC_GATHER_CHANNELNUM + i] = g_adc_org_data[i];
		}
		if(g_colect_index == (ADC_GATHER_MAX_NUM * ADC_GATHER_CHANNELNUM))
		{
			g_colect_index = 0;
			//DMA搬运ADC数据完成标志有效  qian'ru'shi
			g_adc_conversion = true;
		}
		//使用软件触发关闭ADC采集转换
		adc_ordinary_conversion_trigger_set(ADC1,ADC12_ORDINARY_TRIG_SOFTWARE,FALSE);
		//清理标志
    dma_flag_clear(DMA1_FDT1_FLAG);
		//关闭DMA通道
    dma_channel_enable(DMA1_CHANNEL1, FALSE);
		//重写装载
		DMA1_CHANNEL1->dtcnt = ADC_GATHER_CHANNELNUM;
		//开启DMA传输
		dma_channel_enable(DMA1_CHANNEL1, TRUE);
		
  }
}

这里我更换采集了250个数据,即每个通道50个,大家可以参考就好了,只需要关闭DMA的循环模式和在中断中关闭ADC转换就可以

//DMA配置  更改这里
dma_init_struct.loop_mode_enable = FALSE;

//DMA中断配置增加这里
adc_ordinary_conversion_trigger_set(ADC1,ADC12_ORDINARY_TRIG_SOFTWARE,FALSE);

好了现在数据采集正常了。

  • 10
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值