cancel
Showing results for 
Search instead for 
Did you mean: 

Circular DMA does not circle for ADC (STM32L1xx)

stmburns
Associate II
Posted on October 19, 2012 at 17:49

I'm trying to use the ADC on an STM32L1xx to read a single channel with a sample rate based on TIM2.  I plan to use a double-buffering scheme, so I want to set it up to DMA into a buffer with half-complete and fully-complete interrupts.  I think I have this working for the first pass, but it appears not to circle.  In other words, when I enable everything, I get a 1/2 transfer interrupt, and a transfer complete interrupt, but no more.  The buffer appears to have been written to, and while it is a bit hard to tell, I don't think the buffer is being written to more than once.  I see no overflow bits set.  Any ideas?  Here is the initialization code:

     

DMA_StructInit(&DMA_InitStructure);

      DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->DR);         // Set DMA channel Peripheral base address to ADC Data register

      DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)buffer;  // Set DMA channel Memeory base addr to ADC_ConvertedValueBuff address

      DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                         // Set DMA channel direction to peripheral to memory

      DMA_InitStructure.DMA_BufferSize = bufLength*2;

      DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;         // Disable DMA channel Peripheral address auto increment

      DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                    // Enable Memory increment

      DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;// set Peripheral data size to 16bit

      DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;         // set Memeory data size to 16bit

      DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

      DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;

      DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                               // Disable memory to memory option

      DMA_Init(DMA1_Channel1, &DMA_InitStructure);

      /* Setup NVIC for DMA channel 1 interrupt request */

      NVIC_InitStructure.NVIC_IRQChannel =   DMA1_Channel1_IRQn;

      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 13;

      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

      NVIC_Init(&NVIC_InitStructure);

      GPIO_StructInit(&GPIO_InitStructure);

      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4  ;

      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;

      GPIO_Init( GPIOA, &GPIO_InitStructure);

      /* Enable ADC clock */

      RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

      ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div1;

      ADC_CommonInit(&ADC_CommonInitStructure);

      /* Initialize the ADC1 by using its init structure */

      ADC_StructInit(&ADC_InitStructure);

      ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;              // Set conversion resolution to 12bit

      ADC_InitStructure.ADC_ScanConvMode = DISABLE;

      ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;              // Disable Continuous conversion

      ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO; // Use same trigger as D/A-timer 2

      ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;

      ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;                  // Set conversion data alignement to right

      ADC_InitStructure.ADC_NbrOfConversion = 1; // Only one conversion per trigger

      ADC_Init(ADC1, &ADC_InitStructure);

      ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 1, ADC_SampleTime_16Cycles);

    /* Enable DMA1 Channel1 */

    DMA_ITConfig(DMA1_Channel1, DMA_IT_HT | DMA_IT_TC, ENABLE);

    DMA_Cmd(DMA1_Channel1, ENABLE);

    /* Enable DMA for ADC */

    ADC_DMACmd(ADC1, ENABLE);

    /* Enable ADC Channel2 */

    ADC_Cmd(ADC1, ENABLE);

#stm32l-adc-dma
4 REPLIES 4
stmburns
Associate II
Posted on October 19, 2012 at 21:36

I just realized how difficult it is to read the code in my first post with all the wrapping.  Here it is with the comments removed.  If anyone has ideas about why I'm only getting one buffer-full of data, that would be great.  I'd also appreciate it if anyone who has been successful at sampling audio on a timer (rather than continuous) and with a circular buffer.  Thanks again, and here is the cleaned up code:

      DMA_StructInit(&DMA_InitStructure);

      DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->DR);

      DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)buffer; 

      DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;  

      DMA_InitStructure.DMA_BufferSize = bufLength*2;

      DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

      DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  

      DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;

      DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; 

      DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

      DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;

      DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;    

      DMA_Init(DMA1_Channel1, &DMA_InitStructure);

      /* Setup NVIC for DMA channel 1 interrupt request */

      NVIC_InitStructure.NVIC_IRQChannel =   DMA1_Channel1_IRQn;

      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 13;

      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

      NVIC_Init(&NVIC_InitStructure);

      GPIO_StructInit(&GPIO_InitStructure);

      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4  ;

      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;

      GPIO_Init( GPIOA, &GPIO_InitStructure);

      /* Enable ADC clock */

      RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

      ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div1;

      ADC_CommonInit(&ADC_CommonInitStructure);

      /* Initialize the ADC1 by using its init structure */

      ADC_StructInit(&ADC_InitStructure);

      ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; 

      ADC_InitStructure.ADC_ScanConvMode = DISABLE;

      ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;          

      ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO; 

      ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;

      ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;                  

      ADC_InitStructure.ADC_NbrOfConversion = 1; 

      ADC_Init(ADC1, &ADC_InitStructure);

      ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 1, ADC_SampleTime_16Cycles);

  

    DMA_ITConfig(DMA1_Channel1, DMA_IT_HT | DMA_IT_TC, ENABLE);

    DMA_Cmd(DMA1_Channel1, ENABLE);

    ADC_DMACmd(ADC1, ENABLE);

    ADC_Cmd(ADC1, ENABLE);

---------

Posted on October 19, 2012 at 22:25

The ''paintbrush [<>]'' icon, top left allows for code pasting.

The timer and interrupt code may also be helpful. I've done this on other F series parts, not the L.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on October 19, 2012 at 23:03

After ADC_RegularChannelConfig()

  /* Enable the request after last transfer for DMA Circular mode */

  ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
stmburns
Associate II
Posted on October 19, 2012 at 23:35

Clive,

I was just about to post the timer and interrupt code when you posted the ADC_DMARequestAfterLastTransferCmd.  THANK YOU!  That did it.  Gaaark!  This thing is really complex!