cancel
Showing results for 
Search instead for 
Did you mean: 

ADC and DMA double buffer

artuom
Associate II
Posted on April 24, 2013 at 15:59

Hi, all.

I working at ADC sampler implementation. ADCsamplerhas a next flow:
  1. Timer 1 generate sample rate at 200kHz.
  2. At every Timer 1 CC2 interrupt ADC1,ADC2,ADC3 take a sample.
  3. DMA is used to transfer sampled data to RAM.
  4. Every 50 usec sampled frame of 3 channels should be processed.

When I use DMA at normal mode, then sampled frame is OK.

But when I enable circular DMA mode i get garbage. Although when I enable DMA double feature I receive the same garbage. The final target is to use double buffer, so when one will be at sampling stage and the second one at processing stage. Is anyone faced this problem? Initiation code:

/* Enable DMA for ADC transfer */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
/* Enable ADC1,ADC2 for capacitor sensing */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2 | RCC_APB2Periph_ADC3, ENABLE);
/* Select DMA Channel 0 for ADC transfer */
DMA_InitStructure.DMA_Channel = DMA_Channel_0; 
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)AdcParams.AdcBuf1;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC->CDR;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = ADC_SAMLPER_BUFFER_SIZE;
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_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; 
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream0, &DMA_InitStructure);
/* DMA2_Stream0 enable */
DMA_Cmd(DMA2_Stream0, DISABLE);
/* Configure double DMA mode.
- Assign second ADC buffer.
- Set Memory 0 as current memory address 
- This function can be called only when the DMA Stream is disabled.
*/
DMA_DoubleBufferModeConfig(DMA2_Stream0,(uint32_t)AdcParams.AdcBuf2,DMA_Memory_0);
/* Enable DMA double mode. This function can be called only when the DMA Stream is disabled.*/
DMA_DoubleBufferModeCmd(DMA2_Stream0, ENABLE);
/* DMA2_Stream0 enable */
DMA_Cmd(DMA2_Stream0, ENABLE);
/* ADC Common Init */
ADC_CommonInitStructure.ADC_Mode = ADC_TripleMode_RegSimult;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_12Cycles;
ADC_CommonInit(&ADC_CommonInitStructure);
/* ADC1 Configuration */
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;//;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC2;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_RisingFalling;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_Init(ADC1, &ADC_InitStructure);
/* ADC1 regular channels 10-11 configuration */ 
ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_3Cycles);
/* Enable ADC1 DMA */
ADC_DMACmd(ADC1, ENABLE);
/* ADC2 Configuration */
ADC_InitStructure.ADC_NbrOfConversion = 1; /* Set ADC to single conversion */
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_Init(ADC2, &ADC_InitStructure);
/* ADC2 regular channels 0 configuration */ 
ADC_RegularChannelConfig(ADC2, ADC_Channel_11, 1, ADC_SampleTime_3Cycles);
ADC_Init(ADC3, &ADC_InitStructure);
ADC_RegularChannelConfig(ADC3, ADC_Channel_2, 1, ADC_SampleTime_3Cycles);
/* Enable ADC1,ADC2,ADC3 */
ADC_Cmd(ADC1, ENABLE);
ADC_Cmd(ADC2, ENABLE);
ADC_Cmd(ADC3, ENABLE);

3 REPLIES 3
Posted on April 24, 2013 at 16:55

Not sure why you'd need to use double buffer, frankly I think a sufficiently large circular sample buffer, with interrupts on the DMA HT and TC would be adequate. No idea from your presented code what the size of the buffer is.

Remember the DMA doesn't stop when you sit in a debugger, and you need to process the data quicker than it comes in.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
artuom
Associate II
Posted on April 25, 2013 at 07:02

The buffer size is 30 (3 channels * 10 samplers at  50 usec). The reason why I want use is simple, I do not want to perform addition calculation of start and end frame indexes in a circular buffer. With double buffer usage every 50 usec I'll have sampled frame. What I need to is to read CT from DMA register. Looks to me more sufficient solution for needs.

Any way, someone already deal with this kind of problem?

artuom
Associate II
Posted on April 25, 2013 at 09:32

I have found the problem. I didn't enable DDS at ADC->CCR.

After reading once again ADC manual : found at 11.8.1:

 - Requests can continue to be generated if the DDS bit is set to 1. This allows configuring the DMA in double-buffer circular mode.

Right now it is working exactly how I wan to.

Clive1 thanks to your example at [DEAD LINK /public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/stm32f207%20ADC%2bTIMER%2bDMA%20%20Poor%20Peripheral%20Library%20Examples&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B&currentviews=25]stm32f207 ADC+TIMER+DMA / Poor Peripheral Library Examples