项目场景:
使用GD32E230替换STM32F030过程中,发现ADC功能在flash擦除操作时,出现异常。
问题描述:
将ADC进行DMA配置,把3路ADC与内存进行映射,启动ADC和DMA,ADC软件触发,自动循环模式。启动后DMA用ADC采集到的数值不停的刷新内存,程序负责对这段内存分路取平均值即可。.在使用过程中,需要对操作参数进行保存(保存到Flash里),保存一执行,发现采集的ADC发生了突变,调试发现,导致突变的直接原因是DMA映射的通道数据发生了错乱。比如原来的第一路会跑到第二路,第二路会跑到第三路,第三路则变成了第一路。
ADC的配置如下:注意采用了ADC_CTL1_SWRCST|ADC_CONTINUOUS_MODE,软触发和连续模式。
adc_config(void)
{
dma_parameter_struct dma_init_struct;
RCU_REG_VAL(RCU_ADC) |= BIT(RCU_BIT_POS(RCU_ADC));
RCU_REG_VAL(RCU_GPIOA) |= BIT(RCU_BIT_POS(RCU_GPIOA));
RCU_REG_VAL(RCU_GPIOB) |= BIT(RCU_BIT_POS(RCU_GPIOB));
RCU_REG_VAL(RCU_DMA) |= BIT(RCU_BIT_POS(RCU_DMA));
RCU_CFG0 &= ~RCU_CFG0_ADCPSC;
RCU_CFG2 &= ~(RCU_CFG2_ADCSEL | RCU_CFG2_IRC28MDIV | RCU_CFG2_ADCPSC2);
/* set the ADC clock according to ck_adc */
RCU_CFG0 |= RCU_ADC_CKAPB2_DIV8;
RCU_CFG2 |= RCU_CFG2_ADCSEL;
gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_1 | GPIO_PIN_5);//GPIO_PIN_0 |
gpio_mode_set(GPIOB, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_1);
/* ADC channel length config */
// adc_channel_length_config(ADC_REGULAR_CHANNEL, 3);
ADC_RSQ0 &= ~((uint32_t)ADC_RSQ0_RL);
ADC_RSQ0 |= RSQ0_RL((uint32_t)2);
/* ADC regular channel config */
adc_regular_channel6_10_config(0U, ADC_CHANNEL_1, ADC_SAMPLETIME_239POINT5);
adc_regular_channel6_10_config(1U, ADC_CHANNEL_5, ADC_SAMPLETIME_239POINT5);
adc_regular_channel6_10_config(2U, ADC_CHANNEL_9, ADC_SAMPLETIME_239POINT5);
ADC_CTL1 &= ~((uint32_t)ADC_CTL1_ETSRC|ADC_CTL1_DAL);;
ADC_CTL0 |= (ADC_SCAN_MODE);
ADC_CTL1 |= (ADC_EXTTRIG_REGULAR_NONE|ADC_CTL1_ETERC|ADC_CTL1_ADCON|ADC_CTL1_RSTCLB|ADC_CTL1_DMA|ADC_CTL1_SWRCST|ADC_CONTINUOUS_MODE);
/* initialize DMA channel0 */
//dma_deinit(DMA_CH0);
dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
dma_init_struct.memory_addr = (uint32_t)aDC;
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_init_struct.memory_width = DMA_MEMORY_WIDTH_16BIT;
dma_init_struct.number = 24;
dma_init_struct.periph_addr = (uint32_t)&(ADC_RDATA);
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;
dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
dma_init(DMA_CH0, &dma_init_struct);
DMA_CHCTL(DMA_CH0) &= ~DMA_CHXCTL_M2M;
DMA_CHCTL(DMA_CH0) |= (DMA_CHXCTL_CMEN|DMA_CHXCTL_CHEN);
}
原因分析:
具体原因未知,用STM32F030时并没有此问题。这里只讲如何规避,如果有小伙伴知道原因的话,可以让大家一起学习一下。
解决方案:
把自动连续触发模式ADC_CONTINUOUS_MODE
去掉,在主程序中没10ms设置软件触发一次ADC_CTRL1寄存器改为:
ADC_CTL1 |= (ADC_EXTTRIG_REGULAR_NONE|ADC_CTL1_ETERC|ADC_CTL1_ADCON|ADC_CTL1_RSTCLB|ADC_CTL1_DMA);
并在每10ms置位一次软触发:
if(RESET == (ADC_CTL1 & ADC_CTL1_SWRCST))
{
ADC_CTL1 |= ADC_CTL1_SWRCST;
}
这样规避了ADC的DMA映射与flash擦除操作导致的问题。