AnsweredAssumed Answered

Problem DMA interrupt with ADC

Question asked by ronan on Jul 13, 2012
Latest reply on Apr 10, 2013 by abbasi.muhammad_umar
Hello everybody,

I 'm using the STM32F4 discovery board. I use the ADC in triple mode with DMA. I configure the ADC in scan mode and regular channel.

Here is my setup :

/**************************************************************************
  * @descr  Initialise ADC : Triple Mode avec DMA
  * @param  None
  * @retval None
  *************************************************************************/
void ADCInit(void)
{
      GPIO_InitTypeDef      GPIO_AdcInit;
      ADC_InitTypeDef       ADC1_InitStructure;
      ADC_InitTypeDef       ADC2_InitStructure;
      ADC_InitTypeDef       ADC3_InitStructure;
      ADC_CommonInitTypeDef ADC_CommonInitStructure;
 
      /* Deinitializes the ADC peripheral registers */
      ADC_DeInit();
 
      /* Enable the GPIOC Clock & ADC1 Periph Clock */
      RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC, ENABLE);
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2 | RCC_APB2Periph_ADC3, ENABLE);
 
      /* Configure the  PA0 pin (ADC123_IN0)
       *                PA3 pin (ADC123_IN3)
       *                PA4 pin (ADC12_IN4)
       *                PA5 pin (ADC12_IN5)
       *                PA6 pin (ADC12_IN6) */
      GPIO_AdcInit.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6;
      GPIO_AdcInit.GPIO_Mode = GPIO_Mode_AN;
      GPIO_AdcInit.GPIO_PuPd = GPIO_PuPd_NOPULL;
      GPIO_Init(GPIOA, &GPIO_AdcInit);
 
      /* Configure the  PB0 pin (ADC12_IN8)
       *                PB1 pin (ADC12_IN9) */
      GPIO_AdcInit.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
      GPIO_AdcInit.GPIO_Mode = GPIO_Mode_AN;
      GPIO_AdcInit.GPIO_PuPd = GPIO_PuPd_NOPULL;
      GPIO_Init(GPIOB, &GPIO_AdcInit);
 
      /* Configure the  PC0 pin (ADC123_IN10)
       *                PC2 pin (ADC123_IN12) */
      GPIO_AdcInit.GPIO_Pin = GPIO_Pin_0  |  GPIO_Pin_2;
      GPIO_AdcInit.GPIO_Mode = GPIO_Mode_AN;
      GPIO_AdcInit.GPIO_PuPd = GPIO_PuPd_NOPULL;
      GPIO_Init(GPIOC, &GPIO_AdcInit);
 
      /* ADC Common configuration -- ADC_CCR Register */
      ADC_CommonInitStructure.ADC_Mode = ADC_TripleMode_RegSimult ;
      ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;
      ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1  ;
      ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
      ADC_CommonInit(&ADC_CommonInitStructure);
 
 
      /* ADC1 regular channel 6 configuration -- ADC_CR1, ADC_CR2, ADC_SQR1 Register */
      ADC1_InitStructure.ADC_Resolution = ADC_Resolution_12b;
      ADC1_InitStructure.ADC_ScanConvMode = ENABLE;
      ADC1_InitStructure.ADC_ContinuousConvMode = DISABLE;
      ADC1_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
      ADC1_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
      ADC1_InitStructure.ADC_NbrOfConversion = 3;
      ADC_Init(ADC1, &ADC1_InitStructure);
 
      /* ADC1 regular channel6 configuration -- ADCx->SMPR1,SMPR2 et ADCx->SQR1,SQR2,SQR3
       *              channel8 */
      ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 1, ADC_SampleTime_15Cycles );
      ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 2, ADC_SampleTime_15Cycles );
      ADC_RegularChannelConfig(ADC1, ADC_Channel_9, 3, ADC_SampleTime_15Cycles );
 
 
      /* ADC2 regular channel 12 configuration -- ADC_CR1, ADC_CR2, ADC_SQR1 Register */
      ADC2_InitStructure.ADC_Resolution = ADC_Resolution_12b;
      ADC2_InitStructure.ADC_ScanConvMode = ENABLE;
      ADC2_InitStructure.ADC_ContinuousConvMode =  DISABLE;
      ADC2_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
      ADC2_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
      ADC2_InitStructure.ADC_NbrOfConversion = 3;
      ADC_Init(ADC2, &ADC2_InitStructure);
 
      /* ADC2 regular channel12 configuration -- ADCx->SMPR1,SMPR2 et ADCx->SQR1,SQR2,SQR3  */
      ADC_RegularChannelConfig(ADC2, ADC_Channel_12, 1, ADC_SampleTime_15Cycles );
      ADC_RegularChannelConfig(ADC2, ADC_Channel_4, 2, ADC_SampleTime_15Cycles );
      ADC_RegularChannelConfig(ADC2, ADC_Channel_5, 3, ADC_SampleTime_15Cycles );
 
 
      /* ADC3 regular channel 0 configuration -- ADC_CR1, ADC_CR2, ADC_SQR1 Register */
      ADC3_InitStructure.ADC_Resolution = ADC_Resolution_12b;
      ADC3_InitStructure.ADC_ScanConvMode = ENABLE;
      ADC3_InitStructure.ADC_ContinuousConvMode =  DISABLE;
      ADC3_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
      ADC3_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
      ADC3_InitStructure.ADC_NbrOfConversion = 3;
      ADC_Init(ADC3, &ADC3_InitStructure);
 
      /* ADC3 regular channel12 configuration -- ADCx->SMPR1,SMPR2 et ADCx->SQR1,SQR2,SQR3  */
      ADC_RegularChannelConfig(ADC3, ADC_Channel_0, 1, ADC_SampleTime_15Cycles );
      ADC_RegularChannelConfig(ADC3, ADC_Channel_3, 2, ADC_SampleTime_15Cycles );
      ADC_RegularChannelConfig(ADC3, ADC_Channel_10, 3, ADC_SampleTime_15Cycles );
 
      /* DMA2 Stream0 channel0 configuration */
      DMA_ADC_Config();
 
      /* Enable DMA request after last transfer (Multi-ADC mode)  */
      ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);
 
      /* Enable ADC1 -- ADC_CR2_ADON */
      ADC_Cmd(ADC1, ENABLE);
 
      /* Enable ADC2 */
      ADC_Cmd(ADC2, ENABLE);
 
      /* Enable ADC3 */
      ADC_Cmd(ADC3, ENABLE);
 
      /* Enable end of conversion interrupt */
      ADC_ITConfig(ADC1,ADC_IT_EOC, ENABLE);
 
      /* Enable DMA2 Stream0 Transfer complete interrupt */
      DMA_ITConfig(DMA2_Stream0, DMA_IT_TC, ENABLE);
 
      /* Enable ADC1 DMA since ADC1 is the Master*/
      ADC_DMACmd(ADC1, ENABLE);
}
 
 
/**************************************************************************
  * @descr  Configuration du DMA pour l'ADC
  * @param  None
  * @retval None
  *************************************************************************/
void DMA_ADC_Config(void)
{
  DMA_InitTypeDef DMA_InitStructure;
 
  DMA_InitStructure.DMA_Channel = DMA_Channel_0;                            // DMA channel 0
  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCValue;              // Adresse de depart de stockage
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC_CDR_ADDRESS;     // Adresse du registre du periph
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;                   // Direction : Periph vers memoire
  DMA_InitStructure.DMA_BufferSize = 9;                                     // Taille du buffer : 9 (x 4 octets)
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;          // Pas d'incrementation de l'adresse du periph
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                   // Incremente l'adresse de la memoire
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;   // Taille de la donnee du periph (32 bits)
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;           // Taille de la donnee memoire (32 bits)
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                           // Mode circulaire (remise à 0 de l'adresse mémoire après 9 increment)
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;                       // Pririte haute
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;                     // Mode fifo valide
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;     // Taille de la fifo : HalfFull (2 words, 8 octets)
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;               // Transfert en mémoire en un seul burst
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;       // Transfert du peripherique en 1 seul burst
 
  /* Configure le DMA2_stream0 */
  DMA_Init(DMA2_Stream0, &DMA_InitStructure);
 
  /* DMA2_Stream0 enable */
  DMA_Cmd(DMA2_Stream0, ENABLE);
}

To start a sequence of conversion I use ADC_SoftwareStartConv(ADC1). This function is called in the timer interrupt (every 10 ms).

void TIM2_IRQHandler(void)
{
    if (TIM_GetITStatus(TIM2, TIM_IT_Update ) != RESET)
    {
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update );    // Reset Flag
        GPIO_ToggleBits(GPIOD, GPIO_Pin_13);
 
        ADC_SoftwareStartConv(ADC1);
    }
}

Then I check that there is an DMA interrupt every 10 ms

void DMA2_IRQHANDLER(void)
{
    if(DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0) != RESET)
    {
        DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);      // Reset du Flag
 
        ADC1->SR = ADC1->SR & 0xFFED;
 
        /* Change l'etat de la LED4 */
        GPIO_ToggleBits(GPIOD, GPIO_Pin_12);
    }
}

The problem is that the operation is random.

Sometimes, there are many DMA interrupts every 10 ms but mostly there all the time of DMA interrupt (As if the ADC is in continuous conversion mode).

I don't know where does the problem. Is that it is a bad configuration of the ADC ?


Thank you for your response.

Ronan.

Outcomes