cancel
Showing results for 
Search instead for 
Did you mean: 

How to allocate different Buffersize in DMA for multiple ADC's which are running in continuous conversion mode.

Sgowd.1
Associate II
  • I am using a STM32F4 microcontroller, I have to read the ADC values from 3 gpio pins so i am using ADC1, ADC2, ADC3, with DMA and all ADC's is configured in a continuous mode, because i have to collect the ADC values from all ADC's during pulse time period, then have to find the mean value of each ADC for the data collected during the pulse time.

So, with ADC1 i enabled and disabled the ADC1 with Capture Compare interrupt, and the found the mean of the data collected in the buffer of DMA, this is all good. But, when i use ADC2 and ADC3, how can I allocate the different Buffersize for each ADC's?? so that i can collect the data stored in each buffer to find the mean value of the data stored in each ADC.

Below code is the initialization of DMA and ADC's (however for single ADC's DMA initialization is working, but if i enable ADC2 and ADC3 which has different channel's how can i initialize different buffersize for each ADC's so that i can take each buffer to process it), what approach is suitable to do that.

Below code is for initializing the ADC's channel and stream.

                 cADCReadout::sADCInitStruct adc1;
	         adc1.ADCChannel = ADC1;
	    	 adc1.DMAChannel = DMA_Channel_0;
	    	 adc1.DMAStream = DMA2_Stream0; 										
	    	 adc1.DMATRSFCompleteFlag = DMA_FLAG_TEIF0;
 
	    	 cADCReadout::sADCInitStruct adc2;
	    	 adc2.ADCChannel = ADC2;
	    	 adc2.DMAChannel = DMA_Channel_1;
	    	 adc2.DMAStream = DMA2_Stream3;
	    	 adc2.DMATRSFCompleteFlag = DMA_FLAG_TEIF0;
 
	        cADCReadout::sADCInitStruct adc3;
	    	 adc3.ADCChannel = ADC3;
	    	 adc3.DMAChannel = DMA_Channel_2;
	    	 adc3.DMAStream = DMA2_Stream1;
	    	 adc3.DMATRSFCompleteFlag = DMA_FLAG_TEIF0;
 
	    	 m_oADC1.initialize(adc1);
	    	 m_oADC1.addChannel(GPIOA,  GPIO_Pin_1,ADC_Channel_1,ADC_SampleTime_112Cycles);
 
	    	 m_oADC1.initialize(adc2);
	    	 m_oADC1.addChannel(GPIOA, GPIO_Pin_2,ADC_Channel_2,ADC_SampleTime_112Cycles);
 
	    	 m_oADC1.initialize(adc3);
	    	 m_oADC1.addChannel(GPIOA, GPIO_Pin_3,ADC_Channel_3,ADC_SampleTime_112Cycles);

Below is the function for DMA and ADC initialization.

void cADCReadout::initialize(sADCInitStruct init)
{
	m_sInitStruct = init;
 
	ADC_InitTypeDef       ADC_InitStructure;
	ADC_CommonInitTypeDef ADC_CommonInitStructure;
	DMA_InitTypeDef       DMA_InitStructure;
 
	//DMA
	DMA_InitStructure.DMA_Channel = init.DMAChannel;
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(init.ADCChannel->DR);
	DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)(&m_aRecBuffer);
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
	DMA_InitStructure.DMA_BufferSize = BUFFERSIZE;						
	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_Byte;		
	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_1QuarterFull;		
	DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
	DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
	DMA_Init(init.DMAStream, &DMA_InitStructure);
	DMA_Cmd(init.DMAStream, ENABLE);
 
	//ADC
	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_5Cycles;
	ADC_CommonInit(&ADC_CommonInitStructure);
 
	ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
	ADC_InitStructure.ADC_ScanConvMode = ENABLE;								
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;							
	ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;	           
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
	ADC_InitStructure.ADC_NbrOfConversion =3;
	ADC_Init(init.ADCChannel, &ADC_InitStructure);
 
	ADC_EOCOnEachRegularChannelCmd(init.ADCChannel, ENABLE);							
 
	/* Enable DMA request after last transfer (Single-ADC mode) */
	ADC_DMARequestAfterLastTransferCmd(init.ADCChannel, DISABLE);						
 
//	 ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);
}
  • My next question is, I know the formula to find the conversion time of the ADC and also the parameters, but I am bit confused in finding the ADC clock for the stm32f4 chip, i also checked in the datasheet but couldnot figure out what exactly is the ADC clock for the stm32f4 chip if i am using "ADC_Prescaler_Div2". It would really helpfull if any one could also let me know the ADC clock value for the stm32f4 chip with ADC prescaler 2.
6 REPLIES 6
TDK
Guru

If the ADCs are independent, you can choose whatever buffer size you want. Looks like you're running in triple mode, but it appears the hardware can still support different buffer sizes for each ADC. I doubt this is configurable within CubeMX.

uint16_t adc1_buffer[256];
uint16_t adc2_buffer[512];
uint16_t adc3_buffer[1024];

> It would really helpfull if any one could also let me know the ADC clock value for the stm32f4 chip with ADC prescaler 2.

The ADC clock comes from the AHB2 clock, PCLK2. With a /2 prescaler, the clock would be PCLK2/2. You can use CubeMX to see a visualization of this, or consult the reference manual. The reference manual has much more technical information than the datasheet which contains only device-specific information.

If you feel a post has answered your question, please click "Accept as Solution".

Yes, i am running in triple mode, i tried the way you suggested before, but the problem is whichever ADC i initialize last only that ADC buffer is getting filled, the first 2 ADC buffer is still empty, that is the problem i am facing.

For example:

 cADCReadout::sADCInitStruct adc1;
			 adc1.ADCChannel = ADC1;
	    	 adc1.DMAChannel = DMA_Channel_0;
	    	 adc1.DMAStream = DMA2_Stream0; 										
	    	 adc1.DMATRSFCompleteFlag = DMA_FLAG_TEIF0;
	    	 adc1.buffer = m_aRecBufferADC1;
	    	 adc1.buffersize = c_uiBufferSizeADC1;
 
	    	 m_oADC1.addChannel(GPIOA, GPIO_Pin_1,ADC_Channel_1,ADC_SampleTime_112Cycles);
	    	 m_oADC1.initialize(adc1);
 
	    	 cADCReadout::sADCInitStruct adc2;
	    	 adc2.ADCChannel = ADC2;
	    	 adc2.DMAChannel = DMA_Channel_1;
	    	 adc2.DMAStream = DMA2_Stream3;
	    	 adc2.DMATRSFCompleteFlag = DMA_FLAG_TEIF0;
	    	 adc2.buffer = m_aRecBufferADC2;
	    	 adc2.buffersize = c_uiBufferSizeADC2;
 
	    	 m_oADC1.initialize(adc2);
	    	 m_oADC1.addChannel(GPIOA, GPIO_Pin_2,ADC_Channel_2,ADC_SampleTime_112Cycles);
 
	         cADCReadout::sADCInitStruct adc3;
	    	 adc3.ADCChannel = ADC3;
	    	 adc3.DMAChannel = DMA_Channel_2;
	    	 adc3.DMAStream = DMA2_Stream1;
	    	 adc3.DMATRSFCompleteFlag = DMA_FLAG_TEIF0;
	    	 adc3.buffer = m_aRecBufferADC3;
	    	 adc3.buffersize = c_uiBufferSizeADC3;
 
	    	 m_oADC1.addChannel(GPIOA, GPIO_Pin_3,ADC_Channel_3,ADC_SampleTime_112Cycles);
	    	 m_oADC1.initialize(adc3);

In the above code only last initialized ADC's buffer is getting filled, i.e., ADC3 is getting filled and the other ADC's (ADC1, and ADC2) buffer not. If I interchange the order by putting ADC3 in ADC2 place then only ADC2 buffer is getting filled. Inside the 'initialize' function i am configuring ADC and DMA, however each ADC has its own buffer, as you can see in the above code.

TDK
Guru

One option would be to run them in independent mode and use a timer for the trigger.

There may be another solution, but I can't invest the time to find it.

If you feel a post has answered your question, please click "Accept as Solution".

Tried running in independent mode, but still its not working, still same problem. from the above code of ADc and DMA configuration is there anything i have to change other than independent mode??

You’re not using standard HAL functions and you didn’t include your code that actually starts the ADCs and specifies where to put the data. Presumably the issue is there.
If you feel a post has answered your question, please click "Accept as Solution".

I solved it thank you for your help. However i have some other confusions, it would be really helpfull if you could kindly help.

  1. In determining the ADC clock i am bit confused, i am using STM32F4 so according to data sheet below the APB2 clock for ADC is 84Mhz, and i am using prescaler 2, so does the ADC clock will be 42Mhz in my case?0693W00000GXjyzQAD.png

2, I read the below statement in some forum, can you please confirm if it is right??

"if you want ADC conversions to be started each time on specific trigger event you should not use continuous mode. In other words, change:''

      hadc1.Init.ContinuousConvMode = ENABLE;

to

      hadc1.Init.ContinuousConvMode = DISABLE;

is this statement true?

if yes, then will i still be able to use the triggering of ADC during the rising edge of the pulse in continuous mode? Does yes mean i cannot use the below statement "rising edge triggering" with contniuous mode enabled for triggering the ADC?

Because when i use it with conintuous mode it is all working fine with me, i mean in continuous mode enabled and with rising edge triggering i am able to trigger and get the ADC value and my buffer is also full since it is in continuous mode. So, i am bit afraid if it is a right method to do.

ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising ;