cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F407 - Multi-ADC mode with DMA

dibs
Associate II
Posted on January 09, 2014 at 15:19

How is the DMA supposed to work with Triple-ADC Regulare mode? The documentation shows an ADC stream for each ADC, but it also seems to indicate that it will be working with a single DMA stream for this process.

#adc #stm32f4 #dma
10 REPLIES 10
Posted on January 09, 2014 at 15:35

It uses a register CDR (Common Data Register) outside of the 3 ADC which sequences the data from a single register, at a single address, using a single DMA stream

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
dibs
Associate II
Posted on January 09, 2014 at 16:21

So if I choose any of the ADC DMA streams, and point it to the address of the CDR, it will receive a transfer request at the EOC? Assuming that the rest of the ADC is configured correctly.

Posted on January 09, 2014 at 17:01

I'm not sure it works that way, with the Dual/Triple mode one ADC (1) acts as the master, and the other(s) operate in lock step. And you chose a CDR address, and DMA Access Mode to reflect the way the data gets accessed. The data goes to a single buffer, and multiple sequential DMA requests are sent to clear all the pending samples.

You could, I would imagine, also use all three ADC, with their own DMA stream, to their own memory buffer, and tied them together with a common trigger source.

I posted a triple ADC example

https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Problem%20with%20ADC%20DMA%20and%20timer&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B&currentviews=9...

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
dibs
Associate II
Posted on January 09, 2014 at 17:54

I see. I want to be using the DMA stream from ADC1 because it is the master.

The problem that I see with trying to get 3 ADCs working with 3 DMA requests (not in multi-adc mode) is that you will need to trigger all three such that you can guarantee no conflicts. If 3 DMA triggers went out at the same time, could you gaurantee that they would always grab the same data? In that case, would they not all be grabbing from the same ADC-DR?

Posted on January 09, 2014 at 18:17

You'd trigger the start of conversion using a common TIM trigger, the EOC and the order in which the DMA service should be pretty much irrelevant as each ADC has it's own ADCx->DR and each DMA unit is servicing a different memory buffer.

Pretty sure I've posted an example with multiple ADC firing from the same TIM.

The Dual/Triple are different, use a common register (with multiple states), and a single DMA

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
dibs
Associate II
Posted on January 09, 2014 at 21:23

Talking specifically about the STM32F407xx series, I am now rather confused as to how the ADCx-DR setup works. 

If you look at the

http://www.st.com/st-web-ui/static/active/en/resource/technical/document/reference_manual/DM00031020.pdf

, in Section 13.13.18, It indicates that there is:

1 ADC->DR

4 ADC->JDRx

1 ADC->CDR

Which, to me, indicates that you can only actually pull from a single ADC->DR if you are using multiple ADCs that are converting at the same time.

On the other hand, if you look at the

http://www.st.com/web/en/catalog/tools/PF257853

, sm32f4xx_adc.c, and stm32f4xx.h, they seem to indicate that there are 3 different data registers.

Which is it? 

Posted on January 09, 2014 at 22:58

There is ONE ADCx->DR for each of the THREE ADC. Your may use these INDEPENDENTLY.

-- OR --

There is a COMMON area when you COMBINE TWO or THREE ADC in a DUAL and TRIPLE mode respectively.

0690X0000060539QAA.png

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
dibs
Associate II
Posted on January 09, 2014 at 23:07

Ahh, Okay. This actually makes sense. I couldn't understand why they would design a system without independent data registers.

Ehsan Daneshvar
Associate II
Posted on August 17, 2015 at 14:42

Hi dear friend ... it's not true

every ADC has it's own independent data register

and you can have different DMA stream and three different buffer with various buffer sizes that can trig by one trigger source

as an example :

you can sent timer 2 in  1 MHz and as a trigger source like this:

  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

  

  /* Time base configuration */

  TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);

  TIM_TimeBaseStructure.TIM_Period = (84000000 / 1000000) - 1; // 200 KHz, from 84 MHz TIM2CLK (ie APB1 = HCLK/4, TIM2CLK = HCLK/2)

  TIM_TimeBaseStructure.TIM_Prescaler = 0;

  TIM_TimeBaseStructure.TIM_ClockDivision = 0;

  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

  

  /* TIM2 TRGO selection */

  TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update); // ADC_ExternalTrigConv_T2_TRGO

  

  /* TIM2 enable counter */

TIM_Cmd(TIM2, ENABLE);

and then config your 3 ADCs with DMA like this:

  ADC_CommonInitTypeDef ADC_CommonInitStructure;

  ADC_InitTypeDef ADC_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_15Cycles;

  ADC_CommonInit(&ADC_CommonInitStructure);

   

  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;

  ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 1 Channel

  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; // Conversions Triggered

  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;

  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO;

  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

  ADC_InitStructure.ADC_NbrOfConversion = 1;

  

  //ADC1

  ADC_Init(ADC1, &ADC_InitStructure);

  ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 1, ADC_SampleTime_15Cycles); // PC1

  ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);

  ADC_DMACmd(ADC1, ENABLE);

  ADC_Cmd(ADC1, ENABLE);

  for(int i=55000;i--;);

  //ADC2*//*

  ADC_Init(ADC2, &ADC_InitStructure); 

  ADC_RegularChannelConfig(ADC2, ADC_Channel_12, 1, ADC_SampleTime_15Cycles); // PC2 

  ADC_DMARequestAfterLastTransferCmd(ADC2, ENABLE);

  ADC_DMACmd(ADC2, ENABLE);

  ADC_Cmd(ADC2, ENABLE);

  //ADC3

   for(int i=55000;i--;);

  ADC_Init(ADC3, &ADC_InitStructure);

  ADC_RegularChannelConfig(ADC3, ADC_Channel_13, 1, ADC_SampleTime_15Cycles); // PC3

  ADC_DMARequestAfterLastTransferCmd(ADC3, ENABLE);

  ADC_DMACmd(ADC3, ENABLE);

  ADC_Cmd(ADC3, ENABLE);

don't forget you only can set corresponding stream for each ADC.

 DMA2->STREAM0->CH0 for ADC1     

 DMA2->STREAM2->CH1 for ADC2

 DMA2->STREAM1->CH2 for ADC3

.............. its completely tested and OK ... now i captured 3*2 Milion sample per second from 3 different channels with 10kB /channel buffer

----

Good luck

Ehsan Dan