Question
Noise with DMA/ADC
Posted on September 30, 2016 at 06:33
We get the noise regardless of whether we are driving the inputs from an op-amp or other amounts of impedance.Is there anything in the code that we can do to reduce this noise? Would changing SampleTime help?What we ultimately want to do is to have the set of ADC inputs sampled around 5Hz and we need as much of the 12 bits resolution as possible.
We are running a number of channels of ADC on the STM32F0-Discovery board. We have the code below configured to continually read the input signal levels. The code is based on routines posted elsewhere in this forum.
The noise we are seeing is spikes which is very periodic. The code below gives about a 25KHz rate of noise. The noise appears on all the ADC pins. The noise doesn't start appearing until the StartConversion call.If we don't use DMA and just use on-demand ADC almost all the noise is gone.Here is an image of what the noise looks like:
We get the noise regardless of whether we are driving the inputs from an op-amp or other amounts of impedance.Is there anything in the code that we can do to reduce this noise? Would changing SampleTime help?What we ultimately want to do is to have the set of ADC inputs sampled around 5Hz and we need as much of the 12 bits resolution as possible.volatile uint16_t RegularConvData[SAMPLES];
void ADC_Config(void){ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; ADC_InitTypeDef ADC_InitStructure; DMA_InitTypeDef DMA_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; // ADC1 DeInit ADC_DeInit(ADC1); // ADC1 Periph clock enable RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_TIM1, ENABLE); // DMA1 clock enable RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); // GPIO clock enable RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE); // Configure ADC Channels as analog input GPIO_StructInit(&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOA, &GPIO_InitStructure); // TIM2 Configuration TIM_DeInit(TIM1); // Time base configuration TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); TIM_TimeBaseStructure.TIM_Prescaler = (SystemCoreClock / 1000000) - 1; // 1 MHz, from 48 MHz TIM_TimeBaseStructure.TIM_Period = 10 - 1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); // Output Compare PWM Mode configuration TIM_OCStructInit(&TIM_OCInitStructure); TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // low edge by default TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = 1; TIM_OC4Init(TIM1, &TIM_OCInitStructure); // TIM1 enable counter TIM_Cmd(TIM1, ENABLE); // Main Output Enable TIM_CtrlPWMOutputs(TIM1, ENABLE); // DMA1 Channel1 Config DMA_DeInit(DMA1_Channel1); DMA_StructInit(&DMA_InitStructure); DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&RegularConvData[0]; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = 6; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA1_Channel1, &DMA_InitStructure); // DMA1 Channel1 enable DMA_Cmd(DMA1_Channel1, ENABLE); // ADC DMA request in circular mode ADC_DMARequestModeConfig(ADC1, ADC_DMAMode_Circular); // Enable ADC_DMA ADC_DMACmd(ADC1, ENABLE); // Configure the ADC1 in continous mode withe a resolution equal to 12 bits ADC_StructInit(&ADC_InitStructure); ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC4; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_ScanDirection = ADC_ScanDirection_Upward; ADC_Init(ADC1, &ADC_InitStructure); // initialize each ADC channel in order ADC_ChannelConfig(ADC1, ADC_Channel_0 , ADC_SampleTime_7_5Cycles); ADC_ChannelConfig(ADC1, ADC_Channel_1 , ADC_SampleTime_7_5Cycles); ADC_ChannelConfig(ADC1, ADC_Channel_2 , ADC_SampleTime_7_5Cycles); ADC_ChannelConfig(ADC1, ADC_Channel_3 , ADC_SampleTime_7_5Cycles); ADC_ChannelConfig(ADC1, ADC_Channel_4 , ADC_SampleTime_7_5Cycles); ADC_ChannelConfig(ADC1, ADC_Channel_5 , ADC_SampleTime_7_5Cycles); // ADC Calibration ADC_GetCalibrationFactor(ADC1); // Enable ADC1 ADC_Cmd(ADC1, ENABLE); // Wait the ADCEN flag while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADEN)); // ADC1 regular Software Start Conv ADC_StartOfConversion(ADC1);}