Skip to main content
Sgowd.1
Associate III
November 10, 2021
Question

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

  • November 10, 2021
  • 6 replies
  • 1921 views
  • 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.
This topic has been closed for replies.

6 replies

TDK
November 10, 2021

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""."
Sgowd.1
Sgowd.1Author
Associate III
November 11, 2021

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
November 11, 2021

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""."
Sgowd.1
Sgowd.1Author
Associate III
November 11, 2021

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??

TDK
November 11, 2021
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""."