AnsweredAssumed Answered

Noise with DMA/ADC

Question asked by dfwbrawler on Sep 30, 2016
Latest reply on Oct 10, 2016 by FTITI.Walid
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:
TEK0030.BMP

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);
}
 

Outcomes