AnsweredAssumed Answered

3-way Simultaneous ADC-DMA Sampling inversion glitches

Question asked by levy.noah on Feb 18, 2015
Latest reply on Feb 19, 2015 by waclawek.jan
We are currently working on using the three ADCs on the STM32F407 to simultaneously sample three analog waveforms. Our target waveform is at about ~30Khz, but to illustrate our problem I have slowed the input waveforms down to 3Khz. 

We have been capturing data by running our code through the debugger and exporting via gdb (using ST-UTIL in linux). This is our output. The waveform generator we are using to get these waveforms is also being measured with an oscilloscope; the sign inversion is not seen there. This leads us to believe it is being introduced somehow by the STM32F4. What is particularly curious is that the DC component of the individual signals is correct (i.e. ADC1 is offset above ADC2 and ADC3 is not connected to anything). Any suggestions would be greatly appreciated.

STM32F4_glitch_small.png
001.//Adapted From STM32 ADC IQ Sample @ 200 KHz (PC.1, PC.2) STM32F4 Discovery - sourcer32@gmail.com
002.// Assumptions per system_stm32f4xx.c CPU @ 168 MHz, APB2 @ 84 MHz (/2), APB1 @ 42 MHz (/4)
003. #include "stm32f4_discovery.h"
004.#include "stm32f4xx_conf.h"
005.  
006./**************************************************************************************/
007.  
008.void RCC_Configuration(void)
009.{
010.  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
011.  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
012.  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
013.  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);
014.  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);
015.  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
016.}
017.  
018./**************************************************************************************/
019.  
020.void GPIO_Configuration(void)
021.{
022.  GPIO_InitTypeDef GPIO_InitStructure;
023.  
024.  /* ADC Channel 10 -> PC0
025.     ADC Channel 12 -> PC2
026.     ADC Channel 13 -> PC3
027.  */
028.  
029.  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_2 |GPIO_Pin_3;
030.  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
031.  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
032.  GPIO_Init(GPIOC, &GPIO_InitStructure);
033.}
034.  
035./**************************************************************************************/
036.  
037.void ADC_Configuration(void)
038.{
039.  ADC_CommonInitTypeDef ADC_CommonInitStructure;
040.  ADC_InitTypeDef ADC_InitStructure;
041.  
042.  /* ADC Common Init */
043.  ADC_CommonInitStructure.ADC_Mode = ADC_TripleMode_RegSimult;
044.  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
045.  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1; // DMA mode 1 enabled (2 / 3 half-words one by one - 1 then 2 then 3)
046.  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
047.  ADC_CommonInit(&ADC_CommonInitStructure);
048.  
049.  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
050.  ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 1 Channel
051.  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; // Conversions Triggered
052.  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;
053.  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO;
054.  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
055.  ADC_InitStructure.ADC_NbrOfConversion = 1;
056.  ADC_Init(ADC1, &ADC_InitStructure);
057.  ADC_Init(ADC2, &ADC_InitStructure); // Mirror on ADC2
058.  ADC_Init(ADC3, &ADC_InitStructure); // Mirror on ADC3
059.  
060.  /* ADC1 regular channel 10 configuration */
061.  ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_15Cycles); // PC1
062.  
063.  /* ADC2 regular channel 12 configuration */
064.  ADC_RegularChannelConfig(ADC2, ADC_Channel_12, 1, ADC_SampleTime_15Cycles); // PC2
065.  
066.  /* ADC3 regular channel 13 configuration */
067.  ADC_RegularChannelConfig(ADC3, ADC_Channel_13, 1, ADC_SampleTime_15Cycles); // PC3
068.  /* Enable DMA request after last transfer (Multi-ADC mode)  */
069.  ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);
070.  
071.  /* Enable ADC1 */
072.  ADC_Cmd(ADC1, ENABLE);
073.  
074.  /* Enable ADC2 */
075.  ADC_Cmd(ADC2, ENABLE);
076.  
077.  /* Enable ADC3 */
078.  ADC_Cmd(ADC3, ENABLE);
079.  
080.}
081.  
082./**************************************************************************************/
083.  
084.#define BUFFERSIZE 300  // I+Q 200KHz x2 HT/TC at 1KHz
085.  
086.__IO uint16_t ADCTripleConvertedValues[BUFFERSIZE]; // Filled as triple ADC1, ADC2, ADC3
087.  
088.static void DMA_Configuration(void)
089.{
090.  DMA_InitTypeDef DMA_InitStructure;
091.  
092.  DMA_InitStructure.DMA_Channel = DMA_Channel_0;
093.  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCTripleConvertedValues[0];
094.  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)0x40012308; // CDR_ADDRESS; Packed ADC1, ADC2 add pack for addr 3 ??
095.  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
096.  DMA_InitStructure.DMA_BufferSize = BUFFERSIZE; // Count of 16-bit words
097.  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
098.  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
099.  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
100.  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
101.  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
102.  DMA_InitStructure.DMA_Priority = DMA_Priority_High;
103.  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
104.  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
105.  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
106.  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
107.  DMA_Init(DMA2_Stream0, &DMA_InitStructure);
108.  
109.  /* Enable DMA Stream Half / Transfer Complete interrupt */
110.  DMA_ITConfig(DMA2_Stream0, DMA_IT_TC | DMA_IT_HT, ENABLE);
111.  
112.  /* DMA2_Stream0 enable */
113.  DMA_Cmd(DMA2_Stream0, ENABLE);
114.}
115.__IO uint16_t ADCTripleConvertedValues[BUFFERSIZE]; // Filled as triples ADC1, ADC2, ADC3
116.  
117./**************************************************************************************/
118.  
119.void TIM2_Configuration(void)
120.{
121.  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
122.  
123.  /* Time base configuration */
124.  TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
125.  TIM_TimeBaseStructure.TIM_Period = (84000000 / 200000) - 1; // 200 KHz, from 84 MHz TIM2CLK (ie APB1 = HCLK/4, TIM2CLK = HCLK/2)
126.  TIM_TimeBaseStructure.TIM_Prescaler = 0;
127.  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
128.  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
129.  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
130.  
131.  /* TIM2 TRGO selection */
132.  TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update); // ADC_ExternalTrigConv_T2_TRGO
133.  
134.  /* TIM2 enable counter */
135.  TIM_Cmd(TIM2, ENABLE);
136.}
137.  
138./**************************************************************************************/
139.  
140.void NVIC_Configuration(void)
141.{
142.  NVIC_InitTypeDef NVIC_InitStructure;
143.  
144.  /* Enable the DMA Stream IRQ Channel */
145.  NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;
146.  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
147.  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
148.  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
149.  NVIC_Init(&NVIC_InitStructure);
150.}
151.  
152./**************************************************************************************/
153.  
154.void DMA2_Stream0_IRQHandler(void) // Called at 1 KHz for 200 KHz sample rate, LED Toggles at 500 Hz
155.{
156.  /* Test on DMA Stream Half Transfer interrupt */
157.  if(DMA_GetITStatus(DMA2_Stream0, DMA_IT_HTIF0))
158.  {
159.    /* Clear DMA Stream Half Transfer interrupt pending bit */
160.    DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_HTIF0);
161.  
162.    /* Turn LED3 off: Half Transfer */
163.    STM_EVAL_LEDOff(LED3);
164.  
165.        // Add code here to process first half of buffer (ping)
166.  }
167.  
168.  /* Test on DMA Stream Transfer Complete interrupt */
169.  if(DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0))
170.  {
171.    /* Clear DMA Stream Transfer Complete interrupt pending bit */
172.    DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);
173.  
174.    /* Turn LED3 on: End of Transfer */
175.    STM_EVAL_LEDOn(LED3);
176.  
177.        // Add code here to process second half of buffer (pong)
178.  }
179.}
180.  
181./**************************************************************************************/
182.  
183.int main(void)
184.{
185.  RCC_Configuration();
186.  
187.  GPIO_Configuration();
188.  
189.  NVIC_Configuration();
190.  
191.  TIM2_Configuration();
192.  
193.  DMA_Configuration();
194.  
195.  ADC_Configuration();
196.  
197.  STM_EVAL_LEDInit(LED3); /* Configure LEDs to monitor program status */
198.  STM_EVAL_LEDInit(LED4); /* Configure LEDs to monitor program status */
199.  
200.  STM_EVAL_LEDOn(LED3); /* Turn LED3 on, 500 Hz means it working */
201.  
202.  /* Start ADC1 Software Conversion */
203.  ADC_SoftwareStartConv(ADC1);
204.  uint32_t t = 0;
205.  
206.  while(1) // Don't want to exit
207.  {
208.      STM_EVAL_LEDToggle(LED4);
209.      for(t=0; t < 5000000; t++ );
210.  }
211.}

Outcomes