AnsweredAssumed Answered

STM32F411 ADC DMA Interrupt, StdPeriphLib

Question asked by tom.abel on Mar 24, 2018
Latest reply on Mar 25, 2018 by tom.abel

Hi Folks,

 

I am trying to read a potentiometer over one ADC channel of the only available ADC1 peripheral on my STM32F4 board. It works fantastic, when i configure ADC without DMA and when i set only the End of Conversion Interrupt, that works fine!

However, when i try to do it via DMA, it enters the Interrupt triggered by "Transmission complete" just once  and i cannot figure out why it does not keep going. I tried initializing the DMA again once interrupt is triggered but still does not help. I have got DMA working in another project with USART, and that works fine though.

 

Anyway heres my code:


int main(void)
{
     SysTick_Init();
     SystemInit();

     init_led_gpios();

     init_usart2_comm_module();
     init_usart2_gpio();

     init_adc_dma();
     init_adc_dma_irq();

     init_adc_module();
     init_gpio_adc();

     GPIO_SetBits( GPIOD, GPIO_Pin_15);
     USART_TX_string("Hello\r\n");

     while (1)
     {

          if (DMA2_TxCplt_Occured == TRUE)
          {
               memcpy(ADC_VAL_Buffer, DMA_ADC_Buffer, DMA_BUFF_SIZE-1);

               init_adc_dma();

               USART_TX_string("DMA Txfer Completto!");
              USART_TX_string("\r\n");

               DMA2_TxCplt_Occured = FALSE;

          }

     }
}


void DMA2_Stream4_IRQHandler()
{

     if (DMA_GetITStatus(ADC1_DMA_Stream, DMA_IT_TCIF4) != RESET)
     {
               DMA2_TxCplt_Occured = TRUE;

               GPIO_ToggleBits(GPIOD, GPIO_Pin_14);


               DMA_ClearITPendingBit(ADC1_DMA_Stream, DMA_IT_TCIF4);
               DMA_ClearITPendingBit(ADC1_DMA_Stream, DMA_IT_HTIF4);
               DMA_ClearITPendingBit(ADC1_DMA_Stream, DMA_IT_FEIF4);
               DMA_ClearITPendingBit(ADC1_DMA_Stream, DMA_IT_DMEIF4);
               DMA_ClearITPendingBit(ADC1_DMA_Stream, DMA_IT_TEIF4);

     }
}

void SysTick_Handler(void)
{ /* SysTick interrupt Handler. */

}

 

 

ADC Module Init routines:

void init_adc_module(void)
{
     ADC_InitTypeDef ADC1_moduleInitStruct;

     ADC_CommonInitTypeDef ADC1_CommonInitStruct;

     /* Enable ADC1 Clock */
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
     /* Enable ADC1 Clock */



     ADC_CommonStructInit(&ADC1_CommonInitStruct);
     ADC1_CommonInitStruct.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
     ADC1_CommonInitStruct.ADC_Mode = ADC_Mode_Independent;
     ADC1_CommonInitStruct.ADC_Prescaler = ADC_Prescaler_Div8;
     ADC1_CommonInitStruct.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
     ADC_CommonInit(&ADC1_CommonInitStruct);

     ADC_StructInit(&ADC1_moduleInitStruct);
     ADC1_moduleInitStruct.ADC_ScanConvMode = DISABLE;
     ADC1_moduleInitStruct.ADC_ContinuousConvMode = ENABLE;
     ADC1_moduleInitStruct.ADC_DataAlign = ADC_DataAlign_Right;
     ADC1_moduleInitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConvEdge_None;
     ADC1_moduleInitStruct.ADC_NbrOfConversion = 1;
     ADC1_moduleInitStruct.ADC_Resolution = ADC_Resolution_12b;

     ADC_Init(ADC1, &ADC1_moduleInitStruct);

     ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_3Cycles);

     ADC_Cmd(ADC1, ENABLE);

     ADC_DMACmd(ADC1,ENABLE);
     ADC_SoftwareStartConv(ADC1);

}

void init_gpio_adc(void)
{

     GPIO_InitTypeDef ADCGPIO_InitStruct;

     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

     /*PA1-ADC1_Ch1*/
     ADCGPIO_InitStruct.GPIO_Mode = GPIO_Mode_AN;
     ADCGPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
     ADCGPIO_InitStruct.GPIO_Pin = GPIO_Pin_1;
     ADCGPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
     ADCGPIO_InitStruct.GPIO_Speed = GPIO_Medium_Speed; //25MHz

     GPIO_Init(GPIOA, &ADCGPIO_InitStruct);

}

 

ADC DMA Routine:

 

/* ADC1 --> DMA2 Channel0 Stream4 */


void init_adc_dma(void)
{

  DMA_InitTypeDef DMA_ADC1_InitStruct;

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);

  DMA_StructInit(&DMA_ADC1_InitStruct);
  DMA_ADC1_InitStruct.DMA_Channel           = DMA_Channel_0;
  DMA_ADC1_InitStruct.DMA_BufferSize        = DMA_BUFF_SIZE;
  DMA_ADC1_InitStruct.DMA_DIR               = DMA_DIR_PeripheralToMemory;
  DMA_ADC1_InitStruct.DMA_PeripheralBaseAddr =(uint32_t)&(ADC1->DR) ;
  DMA_ADC1_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
  DMA_ADC1_InitStruct.DMA_MemoryInc          = DMA_MemoryInc_Enable;
  DMA_ADC1_InitStruct.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;
  DMA_ADC1_InitStruct.DMA_MemoryDataSize     = DMA_MemoryDataSize_Word;
  DMA_ADC1_InitStruct.DMA_Memory0BaseAddr    = (uint32_t)DMA_ADC_Buffer;
  DMA_ADC1_InitStruct.DMA_Priority           = DMA_Priority_Low;

  DMA_Init(ADC1_DMA_Stream, &DMA_ADC1_InitStruct);
  DMA_ITConfig(ADC1_DMA_Stream, DMA_IT_TC , ENABLE);


  DMA_Cmd(ADC1_DMA_Stream,ENABLE);

}


void init_adc_dma_irq(void)
{
    NVIC_InitTypeDef ADC_DMA_IRQStruct;

    ADC_DMA_IRQStruct.NVIC_IRQChannel = DMA2_Stream4_IRQn;
    ADC_DMA_IRQStruct.NVIC_IRQChannelCmd = ENABLE ;
    ADC_DMA_IRQStruct.NVIC_IRQChannelPreemptionPriority = 0x00 ;
    ADC_DMA_IRQStruct.NVIC_IRQChannelSubPriority = 0x00;


    NVIC_Init(&ADC_DMA_IRQStruct);

}

 

Like i mentioned earlier, ADC module is working fine without DMA, its receiving values when Poti is turned.

With DMA it ends just once inside the interrupt routine.

Any help would be appreciated.

Outcomes