2016-09-29 09:33 PM
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);}2016-10-02 12:36 PM
Does the same noise show up in the conversion data ?
If the noise source end up being not fixable, the problem should be easily overcome with oversampling and averaging, since the 5Hz sampling is significantly smaller than the 25KHz noise. Cheers, Hal2016-10-06 05:36 PM
Hi Hal,
Yes the noise shows up in the conversion data. The amplitude of the noise spikes varies so the amount of effect varies. We have tried doing a set of 16 samples from each input and using the average. That helps reduce the noise effect, but it is still big enough that our data isn't valid.If we turn off DMA and just do ''on-demand'' ADC, the noise is much less. We get one spike shortly after doing the ADC_StartOfConversion call.2016-10-10 08:48 AM
Hi dfwbrawler,
The noise may come from spurious charge shots out of AD inputs. Try to eliminate that with the using of ''Averaging'' or ''Digital-signal filtering'' methods described in the application note ''How to get the best ADC accuracy in STM32Fx Series and STM32L1 Series devices'' (page 22 and page 32)-Hannibal-