使用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);
好了现在数据采集正常了。