AnsweredAssumed Answered

STM32L1 ADC Overrun with DMA

Question asked by moktor on Jul 2, 2014
Latest reply on Jul 7, 2014 by Scott Lee
Hello there,

I've been having trouble with the STM32L1 ADC when using it with the DMA with high sample rates.

Generally speaking, if I trigger the ADC conversion externally using a timer, I can achieve a sampling rate of about 500kHz without getting into trouble. If I configure the timer to trigger the ADC at higher rates, I'll get overrun errors. I can imagine this making sense as the manual states:
The interval between trigger events must be longer than the sequence for regular conversions.
So, to achieve the maximum stated sampling rate of 1MHz I tried to configure the ADC to convert continuously by setting the CONT bit. But as soon as the first conversion completes, an overrun error is reported. The same happens in SCAN mode which I plan to use for conversion of a limited amount of samples.

Does anyone have any idea as to what could be wrong? As far as I see, the HSI is running and none of the Buses have any prescaler configured. I'm sure I'm overlooking something trivial.

Here are the relevant portions of the code:

(note that I use IAR without the stdPeripheralLibrary, so the registers are addressed with this REGNAME_bit.BITNAME syntax)


startConversion()
{
  if (!ADC_SR_bit.ADONS)
  {
    /* ADC not running; power up the adc module */
    ADC_CR2_bit.ADON = 1;
 
    while (!ADC_SR_bit.ADONS)
    {
      /* wait until the adc is ready */
    }
  }
  while (ADC_SR_bit.RCNR);
  {
    /* Wait for regular channel ready */
  }
  IO_SET_OUTPUT_F(IO_SWT_PULL_UP, 1);
  ADC_CR2_bit.SWSTART = 1;
}

  /*********************************************************/
  /* DMA Config */
  /*********************************************************/
initDma()
{
  RCC_AHBENR_bit.DMA1EN = 1;

  /* map DMA to ADC Data Register */
  DMA_CPAR1 = (uint32_t) &ADC_DR;
  /* map memory to DMA */
  DMA_CMAR1 = (uint32_t) (m_aSampleBuffer);

  /* set number of data to actually sampled number of data */
  DMA_CNDTR1 = m_blockSize;
 
  /* Set DMA channel priority (0b00 == low, 0b11 == very high) */
  DMA_CCR1_bit.PL = 0x2;

  /* Set Memory size (0b00 = 8, 0b01 = 16, 0b10 = 32) */
  DMA_CCR1_bit.MSIZE = (sizeof(m_aSampleBuffer[0]) >> 1);
  /* Set Peripheral size (ADC_DR is 16bit) */
  DMA_CCR1_bit.PSIZE = 0x1;

  /* source is always at same address (ADC_DR) */
  DMA_CCR1_bit.PINC = 0;
  /* enable memory increment mode; writes next transfer to next address*/
  DMA_CCR1_bit.MINC = 1;
  /* enable circular mode */
  DMA_CCR1_bit.CIRC = 1;
  /* direction = read from peripheral */
  DMA_CCR1_bit.DIR = 0;
  /* Enable Transfer Error Interrupt */
  DMA_CCR1_bit.TEIE = 1;
  /* Enable full transfer interrupt */
  DMA_CCR1_bit.TCIE = 1;
  /* No Memory-to-memory mode */
  DMA_CCR1_bit.MEM2MEM = 0;
  /* Enable DMA Channel 1 */
  DMA_CCR1_bit.EN = 1;

  /* Enable DMA Ch.1 interrupt in NVIC */
  SETENA0_bit.DMA1_CHANNEL1 = 1;
}
 
  /*********************************************************/
  /* ADC Config */
  /*********************************************************/
initAdc()
{  
  startHsi();

  /* enable peripheral clock */
  RCC_APB2ENR_bit.ADC1EN = 1;

  /* prescaler for ADCCLK (0) */
  ADC_CCR_bit.ADCPRE = ADC_PRESCALE_1;
 
  /* set ADC Resolution (0) */
  ADC_CR1_bit.RES = ADC_RESOLUTION_12BIT;
 
  /* right alignment of result */
  ADC_CR2_bit.ALIGN = 0;

  /* set conversion time via cycles register (0) */
  configureConversionTime(ADC_CYCLES_4);

  /* delay after conversion => no delay */
  ADC_CR2_bit.DELS = 0;

  /* Configures the SQRx registers */
  configureSequencer(m_blockSize);

  /* scan mode */
  ADC_CR1_bit.SCAN = 1;

  /* overrun interrupt enable */
  ADC_CR1_bit.OVRIE = 1;
  SETENA0_bit.ADC1 = 1;
}

Outcomes