cancel
Showing results for 
Search instead for 
Did you mean: 

ADC + DMA on STM32F4

neoirto
Associate II
Posted on February 04, 2013 at 23:19

Hi all,

This is my first implementation of DMA based ADC with the help of some code found on the web. Could you please tell me if I'm correct on my understanding : Timer4 overflow will trigger DMA : so for each Timer4 overflow, I'll get one call to DMA2 and one update ofADC3ConvertedValue, and only one ? I'm not sure because, there isDMA_Mode_Circular ENABLE ?

ADC_InitTypeDef ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
DMA_InitTypeDef DMA_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable ADC3, DMA2 and GPIO clocks ****************************************/
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);
#define ADC3_DR_ADDRESS ((uint32_t)0x4001224C)
/* DMA2 Stream1 channel2 configuration **************************************/
DMA_InitStructure.DMA_Channel = DMA_Channel_2; 
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC3_DR_ADDRESS;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC3ConvertedValue;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = 1;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; /// DMA_Mode_Normal /// DMA_Mode_Circular
DMA_InitStructure.DMA_Priority = DMA_Priority_Low; /// DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; 
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream1, &DMA_InitStructure);
DMA_Cmd(DMA2_Stream1, ENABLE);
/* Configure the PC0 pin (ADC123_IN10)*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOC, &GPIO_InitStructure);
/* ADC Common Init **********************************************************/
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; 
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&ADC_CommonInitStructure);
/* ADC3 Init ****************************************************************/
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; 
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T4_CC4;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_Init(ADC3, &ADC_InitStructure);
/* ADC3 regular channel7 configuration *************************************/
ADC_RegularChannelConfig(ADC3, ADC_Channel_10, 1, ADC_SampleTime_3Cycles);
/* Enable DMA request after last transfer (Single-ADC mode) */
ADC_DMARequestAfterLastTransferCmd(ADC3, ENABLE);
/* Enable ADC3 DMA */
ADC_DMACmd(ADC3, ENABLE);
/* Enable ADC3 */
ADC_Cmd(ADC3, ENABLE);

Thanks in advance for your help 😉
5 REPLIES 5
Posted on February 04, 2013 at 23:30

Circular in that you don't have to constantly reinitialize the DMA. In this case to the same one variable.

Want to see if when the DMA is working try filling the memory location with junk, or allocating a larger array for the values and set the memory location to increment.

3 cycles will probably give you a pretty inconsistent sample.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
neoirto
Associate II
Posted on February 05, 2013 at 11:42

Thank you Clive,

ADC_SampleTime_56Cycles gives better results, you're true. Very consistent results.

But could you please confirm : with 56Cycles, the DMA2 will be busy during :

56 + 12 = 68 cycles - > 68/30 = 2.26 us

Is that true ?

And so I understand from your answer that the DMA is triggered only on the Overflow event in my case.

Tell me if I'm wrong please !
Posted on February 05, 2013 at 17:43

And so I understand from your answer that the DMA is triggered only on the Overflow event in my case. Tell me if I'm wrong please !

I'm not hugely invested in this, but it looks to be TIM4 CC4 (Capture Compare Channel 4), so no that's not the Update event. If you have CH4 in PWM mode the pacing would be similar to the Update, just the phase/placement would be different.

The trigger is used to start the conversion, the DMA doesn't kick off until the conversion is complete some X cycles later, and occurs nearly instantaneously contention/memory aside.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
neoirto
Associate II
Posted on February 05, 2013 at 18:25

Tx again Clive,

About the DMA, it's clear now. Adc will not use a lot of CPU so, good news :).

About the CC on TIMER4 : I had the same thoughts as you : but it appears it works too with an Update event, because my TIMER4 is not driving any PWM and no Capture Compare too : just firing one TIM4_IRQn()...

Strange isn't it ? But it works, and this function is far to be critical for me, so I believe I won't investigate more thant that.

If anyone can confirm this is a normal behavior ?
Posted on February 22, 2013 at 11:00

ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;   indicates, that you DON'T have the ADC externally triggered (from the Timer4). You can confirm that by stopping (not running) the timer.   ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;

  indicates, that it's the ADC itself which performs continuous conversions (and firing the DMA transfer after each conversion). I don't see code starting the first conversion, but then you haven't posted the whole code...   JW