AnsweredAssumed Answered

ADC1 -> DMA2 works first time then stops

Question asked by barber.mark on Sep 22, 2016
Latest reply on Nov 27, 2017 by jason wang

Hi all,
I have a most frustrating problem. I am using the ADC1 to sample 5 ADC inputs in sequence, I am also using the DMA2 Sequence 0 to transfer the results to a memory location.
I am using a timer to ensure this occurs at precise times as the samples are then “FFT’ed” to get the frequency domain components.   This works perfectly the first time through. The ADC results are as expected and the results are in the right location. The second time this executes the results are not appearing in the memory locations. In fact the ADC1 reports that the conversion has resulted in an overrun, so clearly the DMA is not servicing the ADC. The question is why. I am sure I have some setting wrong or in the incorrect sequence. The CPU is a STM32F427

This is the initialization code for the ADC

// set  up adc

    /* *ADC1 GPIO Configuration

    PC0     ------> Radar 1 ADC1_IN10

    PC1     ------> Radar 2 ADC1_IN11

    PA3     ------> Vbatt   ADC1_IN03

    PA4     ------> LDR     ADC1_IN04

    PA5     ------> Thermistor ADC1_IN05

    */

  // adc clock enable

  RCC->APB2ENR|=RCC_APB2ENR_ADC1EN;

 

    // setup CR1

  ADC1->CR1&=~(ADC_CR1_RES_1|ADC_CR1_RES_0);                     // set to 12 bit

  ADC1->CR1&=~ADC_CR1_DISCEN;        // enable disconinuios mode on regular channels

  ADC1->CR1&=~ADC_CR1_EOCIE;         // disable end of conversion

  ADC1->CR1|=ADC_CR1_DISCNUM_2;     // set for five channels

  ADC1->CR1&=~ADC_CR1_JDISCEN;      // disable injected mode

  ADC1->CR1|=ADC_CR1_SCAN;          // enable scan mode

 

 

// setup CR2

    ADC1->CR2|=ADC_CR2_ADON;

    ADC1->CR2&=~ADC_CR2_ALIGN;

// set up CCR register

    // set clock prescalaer to 2

    ADC->CCR&=~ADC_CCR_ADCPRE;

    ADC->CCR&=~ADC_CCR_ADCPRE_0;

    ADC->CCR&=~ADC_CCR_ADCPRE_1;

 

     /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.

    we are doing 5 conversion with sample time of 480 cycles

    channel 10 11 3 4 5

    */

    ADC1->SQR1&=~ADC_SQR1_L;        // clear L[3:0] for 5 conversions

    ADC1->SQR1|=ADC_SQR1_L_2;

 

    // set up 1st conversion on channel 10 Radar 1

    ADC1->SQR3|=0x000a;

    ADC1->SMPR2|=0b0111;             // 480 cycles

    // set up 2nd conversion on channel 11 Radar 2

    ADC1->SQR3|=(0x000b)<<5;

    ADC1->SMPR2|=(0b0111<<3);          // 480 cycles

    // set up 3rd

    ADC1->SQR3|=(0x0003)<<10;

    ADC1->SMPR2|=0b0111<<6;          // 480 cycles

    // set up 4th

    ADC1->SQR3|=(0x0004)<<15;

    ADC1->SMPR2|=0b0111<<9;          // 480 cycles

    // set up 5th

    ADC1->SQR3|=(0x0005)<<20;

    ADC1->SMPR2|=0b0111<<12;          // 480 cycles

 

This is the initialization code for the DMA

    RCC->AHB1ENR|=RCC_AHB1ENR_DMA2EN;

 

    DMA2_Stream0 ->CR&=~DMA_SxCR_CHSEL;          // clear all channels by default set to channel 0

    DMA2_Stream0 ->CR&=~DMA_SxCR_CT;             // set target memory to memory 0

    DMA2_Stream0 ->CR&=~DMA_SxCR_MSIZE_1;

    DMA2_Stream0 ->CR|=DMA_SxCR_MSIZE_0;        // set to 16 bits

    DMA2_Stream0 ->CR&=~DMA_SxCR_PSIZE_1;

    DMA2_Stream0 ->CR|=DMA_SxCR_PSIZE_0;        // set to 16 bits

    DMA2_Stream0 ->CR|=DMA_SxCR_MINC;          // increment memory location

    DMA2_Stream0 ->CR&=~DMA_SxCR_PINC;

    DMA2_Stream0 ->CR|=DMA_SxCR_PL_1;

    DMA2_Stream0 ->CR&=~DMA_SxCR_DIR_0;         // set direction peripheral to memory

    DMA2_Stream0 ->CR&=~DMA_SxCR_DIR_1;

    DMA2_Stream0 ->CR|=DMA_SxCR_PFCTRL;        // peripheral is the flow control

 

The timer interrupts on a regular basis and this is the code to start another conversion.

   DMA2_Stream0 ->CR&=~DMA_SxCR_EN;

    while((DMA2_Stream0->CR&DMA_SxCR_EN)!=0);   // wait for DMA sequence to complete

    ADC1->CR2&=~ADC_CR2_DMA;                    // disable ADC DMA interface

    DMA2_Stream0 ->PAR=(int32_t)&ADC1->DR;          // set source

    DMA2_Stream0 ->M0AR=(int32_t)&adc_values[0];    // set destination

    DMA2_Stream0 ->NDTR=5;                          // set number of transfers

    DMA2->LISR&=~(DMA_LISR_TEIF0|DMA_LISR_TCIF0);   // clear flags

    DMA2_Stream0 ->CR|=DMA_SxCR_EN;                 // enable DMA sequence

    ADC1->CR2|=ADC_CR2_DMA;                         // enable ADC DMA interface

    ADC1->CR2|=ADC_CR2_SWSTART;                     // start next conversion

 

    // clear interrupt

    TIM2->SR &=~TIM_SR_UIF;

Any help appreciated.

Thanks

Mark

Outcomes