AnsweredAssumed Answered

ADC and DMA, again

Question asked by ponikvar.dusan on Apr 18, 2013
Latest reply on Apr 24, 2013 by Clive One
Hi,

I am fighting with an application for FIR filtering on STM32F407.
The idea is to simultaneously sample two signals using two ADCs running in continuous mode. The samples are transferred from ADCs into the primary circular buffer formed in memory using first DMA transfer. The circular buffer is divided in quarters; once a quarter is filled-up (this will be checked within the timer IRQ function), the processor executes the filtering and moves results into the corresponding quarter of the secondary circular buffer, from where the second DMA transfer sends them to two DACs.

I'm currently having problems with the first part that is the DMA transfer from ADCs into the primary circular buffer. The source code is appended. When a sawtooth signal is sampled, the values of samples in the primary circular buffer should increase. However, the content of the primary circular buffer gets scattered as if samples are stored into the buffer at random positions. When I disable the circular mode and allow DMA to fill the entire buffer once only, samples are as they should be.

I have spent the last two days looking for an error and playing with variants of the code, but with no success. What am I doing wrong?
Thanks!

/*********************************************************************
#define ADC_CDR_ADDRESS     ((uint32_t)0x40012308)
#define ADC1_DR_ADDRESS     ((uint32_t)0x4001204c)
#define ADC2_DR_ADDRESS     ((uint32_t)0x4001214c)
#define DAC_DHR12RD_ADDRESS ((uint32_t)0x40007420)
#define DAC_DHR12R2_ADDRESS ((uint32_t)0x40007414)

GPIO_InitTypeDef        GPIO_InitStructure;
ADC_InitTypeDef         ADC_InitStructure;
ADC_CommonInitTypeDef   ADC_CommonInitStructure;
DAC_InitTypeDef         DAC_InitStructure;
DMA_InitTypeDef         DMA_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;

uint32_t CBin[1024];
uint32_t CBout[1024];
unsigned int ptr = 0;

void main(void) {
  /* GPIOE configuration - test outputs only ************************/
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
  GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_8 | GPIO_Pin_10 | GPIO_Pin_12 | GPIO_Pin_14;
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_Init(GPIOE, &GPIO_InitStructure);
 
  /* DAC1 & DAC2 configuration *************************/
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
  GPIO_InitStructure.GPIO_Pin   = 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);
 
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
  DAC_InitStructure.DAC_OutputBuffer   = DAC_OutputBuffer_Enable;
  DAC_InitStructure.DAC_Trigger        = DAC_Trigger_None;
  DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
  DAC_Init(DAC_Channel_1, &DAC_InitStructure);
  DAC_Init(DAC_Channel_2, &DAC_InitStructure);
  DAC_Cmd(DAC_Channel_1, ENABLE);  
  DAC_Cmd(DAC_Channel_2, ENABLE);

  /* DMA2 configuration: data from ADC1 & ADC2 to circular buffer **/
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
  DMA_StructInit(&DMA_InitStructure);
  DMA_InitStructure.DMA_Channel            = DMA_Channel_0;
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC_CDR_ADDRESS;
  DMA_InitStructure.DMA_Memory0BaseAddr    = (uint32_t)&CBin;
  DMA_InitStructure.DMA_DIR                = DMA_DIR_PeripheralToMemory;
  DMA_InitStructure.DMA_BufferSize         = 1024;
  DMA_InitStructure.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc          = DMA_MemoryInc_Enable;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
  DMA_InitStructure.DMA_MemoryDataSize     = DMA_MemoryDataSize_Word;
  DMA_InitStructure.DMA_Mode               = DMA_Mode_Circular;
  DMA_InitStructure.DMA_Priority           = DMA_Priority_High;
  DMA_InitStructure.DMA_FIFOMode           = DMA_FIFOMode_Disable;
  DMA_InitStructure.DMA_FIFOThreshold      = DMA_FIFOThreshold_HalfFull;
  DMA_InitStructure.DMA_MemoryBurst        = DMA_MemoryBurst_Single;
  DMA_InitStructure.DMA_PeripheralBurst    = DMA_PeripheralBurst_Single;
  DMA_Init(DMA2_Stream0, &DMA_InitStructure);
  DMA_Cmd(DMA2_Stream0, ENABLE);

  /* ADC1 & ADC 2 configuration ***********************************************/
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
  GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_2 | GPIO_Pin_3;
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2,  ENABLE);
  ADC_CommonInitStructure.ADC_Mode             = ADC_DualMode_RegSimult;
  ADC_CommonInitStructure.ADC_Prescaler        = ADC_Prescaler_Div4;
  ADC_CommonInitStructure.ADC_DMAAccessMode    = ADC_DMAAccessMode_2;
  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
  ADC_CommonInit(&ADC_CommonInitStructure);
   
  ADC_InitStructure.ADC_Resolution             = ADC_Resolution_12b;
  ADC_InitStructure.ADC_ScanConvMode           = DISABLE;
  ADC_InitStructure.ADC_ContinuousConvMode     = ENABLE;
  ADC_InitStructure.ADC_ExternalTrigConvEdge   = ADC_ExternalTrigConvEdge_None;
  ADC_InitStructure.ADC_ExternalTrigConv       = ADC_ExternalTrigConv_T1_CC1;
  ADC_InitStructure.ADC_DataAlign              = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_NbrOfConversion        = 1;
 
  ADC_Init(ADC1, &ADC_InitStructure);
  ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 1, ADC_SampleTime_3Cycles);
  ADC_Init(ADC2, &ADC_InitStructure);
  ADC_RegularChannelConfig(ADC2, ADC_Channel_3, 1, ADC_SampleTime_3Cycles);

  ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);
 
  ADC_Cmd(ADC1, ENABLE);
  ADC_Cmd(ADC2, ENABLE);

  /* Timer 2 configuration ***************************/
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,  ENABLE);
  TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInitStructure.TIM_Period = 840;
  TIM_TimeBaseInitStructure.TIM_Prescaler = 0;
  TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
  TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
  NVIC_EnableIRQ(TIM2_IRQn);    
  TIM_Cmd(TIM2, ENABLE);

  ADC_SoftwareStartConv(ADC1);

  while (1) {
    GPIOE->BSRRL = BIT_8;  // to confirm the execution
    GPIOE->BSRRL = BIT_8;
    GPIOE->BSRRH = BIT_8;
    GPIOE->BSRRH = BIT_8;
  };
}

/* Timer IRQ function ************************************/
void TIM2_IRQHandler(void) // preliminary, to check circular buffer 
{
  GPIOE->BSRRL = BIT_12;        
  TIM_ClearFlag(TIM2, TIM_FLAG_Update);
  int BytesLeft = DMA_GetCurrDataCounter(DMA2_Stream0);
  if (BytesLeft > 512) GPIOE->BSRRL = BIT_14;
  else                 GPIOE->BSRRH = BIT_14; 
  GPIOE->BSRRH = BIT_12;        
}

 

Outcomes