cancel
Showing results for 
Search instead for 
Did you mean: 

Triple ADC mode with DMA [STM32F4 discovery]

ronandouguet
Associate II
Posted on February 20, 2012 at 14:52

The original post was too long to process during our migration. Please click on the attachment to read the original post.
22 REPLIES 22
ronandouguet
Associate II
Posted on March 05, 2012 at 09:31

Thank you Hal for your reponse.

I used PA4 pin to DAC1_OUT but now this function isn't launch.

To the NumbreOfConversions usually is 3 but I tried differents solution and I forgot to reinitialize it.

I believe that I will not find this error !!

Thanks for your help.
hkamba
Associate II
Posted on February 20, 2014 at 17:39

Hi,

I was looking for a tutorial on how to use ADC in triple mode and came across your post. What I want to do is similar but I am not implementing the interrupt and I only need to convert 4 analog input. My four analog inputs are on Port C. While following you code, I came up with the following. Can you please tell me if it is correct? I have no board to run it on yet. I do not understand how you attributed each channel to an ADC. Why doing it in that order?

void AI_init(void)
{ 
ADC_InitTypeDef ADC_InitStructure;
uint32_t tmpreg1 = 0;
/********** Enable peripheral clocks ********************/
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN | RCC_AHB1ENR_DMA2EN;
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN | RCC_APB2ENR_ADC3EN; 
/********** Configure PC0 pin (ADC123_IN10), PC1 pin (ADC123_IN11), PC2 pin (ADC123_IN13), PC3 pin (ADC123_IN13) ********************/ 
GPIOC->MODER |= ( GPIO_MODER_MODER0 | GPIO_MODER_MODER1 | GPIO_MODER_MODER2 | GPIO_MODER_MODER3 ); // Set PC0 (IN10), PC1 (IN11), PC2 (IN12),and PC3 (IN13) as analog input
GPIOC->PUPDR &= ~(GPIO_PUPDR_PUPDR0 | GPIO_PUPDR_PUPDR1 | GPIO_PUPDR_PUPDR2 | GPIO_PUPDR_PUPDR3 ); // No pull
/**************DMA2_Stream0 channel0 configuration ********************/
tmpreg1 = DMA2_Stream0->CR; // Get DMA2_Stream0 CR value
tmpreg1 &= ((uint32_t)~(DMA_SxCR_CHSEL | DMA_SxCR_MBURST | DMA_SxCR_PBURST |
DMA_SxCR_PL | DMA_SxCR_MSIZE | DMA_SxCR_PSIZE | 
DMA_SxCR_MINC | DMA_SxCR_PINC | DMA_SxCR_CIRC |
DMA_SxCR_DIR));
// Select channel 0
// Select single memory burst transfer
// Select single peripheral burst transfer
// Select high priority level
// Select halfword memory data size
// Select halfword peripheral data size
// Select memory address pointer increment mode
// Select fixed peripheral address pointer
// Enable circular mode
// Select peripheral-to-memory data transfer direction
tmpreg1 |= ( DMA_SxCR_PL_1 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PSIZE_0 | DMA_SxCR_MINC | DMA_SxCR_CIRC );
DMA2_Stream0->CR = tmpreg1;
tmpreg1 = DMA2_Stream0->FCR; // Get DMA2_Stream0 FCR value
tmpreg1 &= (uint32_t)~(DMA_SxFCR_DMDIS | DMA_SxFCR_FTH); // Clear DMDIS and FTH bits 
tmpreg1 |= DMA_SxFCR_FTH_0; // Enable direct mode and set FIFO threshold to half-full
DMA2_Stream0->FCR = tmpreg1;
DMA2_Stream0->NDTR = 4; // Number of data items to transfer 
DMA2_Stream0->PAR = (uint32_t)&ADC->CDR; // Peripheral data address 
DMA2_Stream0->M0AR = (uint32_t)&aADCTripleConvertedValue; // Base address of Memory area 0 to which the data will be written
DMA2_Stream0->CR |= (uint32_t)DMA_SxCR_EN; // Enable DMA2 Stream0
/**************ADC Common Init ********************/ 
tmpreg1 = ADC->CCR; // Get the ADC CCR value
tmpreg1 &= ((uint32_t)0xFFFC30E0); // Clear MULTI, DELAY, DMA and ADCPRE bits 
tmpreg1 |= (ADC_CCR_ADCPRE_0 | // Divide PCLK2 by 4 (Maximum Flash memory access frequency no more than 30 MHz!)
ADC_CCR_DMA_0 | // DMA mode 1 (2/3 half-words one by one - 1 then 2 then 3)
(ADC_CCR_MULTI_4|ADC_CCR_MULTI_2|ADC_CCR_MULTI_1)); // Triple mode, Regular simultaneous mode only 
ADC->CCR = tmpreg1;
/************** ADC1 regular channel 13 configuration ******************/
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 3;
ADC_Init(ADC1, &ADC_InitStructure);
ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 1, ADC_SampleTime_3Cycles);
/****************** ADC2 regular channel 11 configuration*****************/
ADC_Init(ADC2, &ADC_InitStructure); 
ADC_RegularChannelConfig(ADC2, ADC_Channel_11, 1, ADC_SampleTime_3Cycles); // ADC2 regular channel11 configuration
ADC_RegularChannelConfig(ADC2, ADC_Channel_12, 2, ADC_SampleTime_3Cycles); // ADC2 regular channel12 configuration
/****************** ADC3 regular channel 10 configuration ***************/
ADC_Init(ADC3, &ADC_InitStructure); 
ADC_RegularChannelConfig(ADC3, ADC_Channel_10, 1, ADC_SampleTime_3Cycles); // ADC3 regular channel10 configuration
ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE); // Enable DMA request after last transfer (multi-ADC mode)
ADC_Cmd(ADC1, ENABLE); // Enable ADC1
ADC_Cmd(ADC2, ENABLE); // Enable ADC2
ADC_Cmd(ADC3, ENABLE); // Enable ADC3
ADC_DMACmd(ADC1, ENABLE); // Enable ADC1 DMA since ADC1 is the Master
}

Posted on February 20, 2014 at 17:50

There does appear to be some extreme confusion here.

If you want TRIPLE mode, ie 3 ADC synchronized in lock step, you are going to want ALL the ADC balanced unless you want to get some real bizarre sample sequencing issues. None of the ADC have 3 conversions associated with them.

ADC_InitStructure.ADC_NbrOfConversion

must reflect the NUMBER of conversions assigned to each ADC, in your tortured case 1, 2, 1 If you just need 4 conversions, in sequence, you could presumably just use one ADC (pins/channels permitting)
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
hkamba
Associate II
Posted on February 20, 2014 at 18:13

Thank you so much for your clarification clive1.

A few lines from you just make everything clearer! The pins and channels do not permit me to use a single ADC, I have to use all three ADCs. PC0, PC1, PC2 and PC3 only have ADC123_INx alternate functions. How would you suggest that I balance the three ADCs? I rectified the code as shown below is it better now? Also, will I be correct to say that the converted input of channel 10,11,12 and 13 will be inaADCTripleConvertedValue[0], aADCTripleConvertedValue[1],aADCTripleConvertedValue[2],aADCTripleConvertedValue[3]respectively as shown in ()AI_read_adc_input?

void AI_init(void)
{ 
ADC_InitTypeDef ADC_InitStructure;
uint32_t tmpreg1 = 0;
/********** Enable peripheral clocks ********************/
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN | RCC_AHB1ENR_DMA2EN;
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN | RCC_APB2ENR_ADC3EN; 
/********** Configure PC0 pin (ADC123_IN10), PC1 pin (ADC123_IN11), PC2 pin (ADC123_IN13),and PC3 pin (ADC123_IN13) ********************/ 
GPIOC->MODER |= ( GPIO_MODER_MODER0 | GPIO_MODER_MODER1 | GPIO_MODER_MODER2 | GPIO_MODER_MODER3 ); // Set PC0 (IN10), PC1 (IN11), PC2 (IN12),and PC3 (IN13) as analog input
GPIOC->PUPDR &= ~(GPIO_PUPDR_PUPDR0 | GPIO_PUPDR_PUPDR1 | GPIO_PUPDR_PUPDR2 | GPIO_PUPDR_PUPDR3 ); // No pull
/**************DMA2_Stream0 channel0 configuration ********************/
tmpreg1 = DMA2_Stream0->CR; // Get DMA2_Stream0 CR value
tmpreg1 &= ((uint32_t)~(DMA_SxCR_CHSEL | DMA_SxCR_MBURST | DMA_SxCR_PBURST |
DMA_SxCR_PL | DMA_SxCR_MSIZE | DMA_SxCR_PSIZE | 
DMA_SxCR_MINC | DMA_SxCR_PINC | DMA_SxCR_CIRC |
DMA_SxCR_DIR));
// Select channel 0
// Select single memory burst transfer
// Select single peripheral burst transfer
// Select high priority level
// Select halfword memory data size
// Select halfword peripheral data size
// Select memory address pointer increment mode
// Select fixed peripheral address pointer
// Enable circular mode
// Select peripheral-to-memory data transfer direction
tmpreg1 |= ( DMA_SxCR_PL_1 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PSIZE_0 | DMA_SxCR_MINC | DMA_SxCR_CIRC );
DMA2_Stream0->CR = tmpreg1;
tmpreg1 = DMA2_Stream0->FCR; // Get DMA2_Stream0 FCR value
tmpreg1 &= (uint32_t)~(DMA_SxFCR_DMDIS | DMA_SxFCR_FTH); // Clear DMDIS and FTH bits 
tmpreg1 |= DMA_SxFCR_FTH_0; // Enable direct mode and set FIFO threshold to half-full
DMA2_Stream0->FCR = tmpreg1;
DMA2_Stream0->NDTR = 4; // Number of data items to transfer 
DMA2_Stream0->PAR = (uint32_t)&ADC->CDR; // Peripheral data address 
DMA2_Stream0->M0AR = (uint32_t)&aADCTripleConvertedValue; // Base address of Memory area 0 to which the data will be written
DMA2_Stream0->CR |= (uint32_t)DMA_SxCR_EN; // Enable DMA2 Stream0
/**************ADC Common Init ********************/ 
tmpreg1 = ADC->CCR; // Get the ADC CCR value
tmpreg1 &= ((uint32_t)0xFFFC30E0); // Clear MULTI, DELAY, DMA and ADCPRE bits 
tmpreg1 |= (ADC_CCR_ADCPRE_0 | // Divide PCLK2 by 4 (Maximum Flash memory access frequency no more than 30 MHz!)
ADC_CCR_DMA_0 | // DMA mode 1 (2/3 half-words one by one - 1 then 2 then 3)
(ADC_CCR_MULTI_4|ADC_CCR_MULTI_2|ADC_CCR_MULTI_1)); // Triple mode, Regular simultaneous mode only 
ADC->CCR = tmpreg1;
/************** ADC1 regular channel 10 configuration ******************/
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 2;
ADC_Init(ADC1, &ADC_InitStructure);
ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_3Cycles); // ADC1 regular channel10 configuration

ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 2, ADC_SampleTime_3Cycles); // ADC3 regular channel13 configuration

/****************** ADC2 regular channel 11 configuration*****************/
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_Init(ADC2, &ADC_InitStructure); 
ADC_RegularChannelConfig(ADC2, ADC_Channel_11, 1, ADC_SampleTime_3Cycles); // ADC2 regular channel11 configuration
/****************** ADC3 regular channel 12 configuration ***************/
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_Init(ADC3, &ADC_InitStructure); 
ADC_RegularChannelConfig(ADC3, ADC_Channel_12, 1, ADC_SampleTime_3Cycles); // ADC3 regular channel12 configuration
ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE); // Enable DMA request after last transfer (multi-ADC mode)
ADC_Cmd(ADC1, ENABLE); // Enable ADC1
ADC_Cmd(ADC2, ENABLE); // Enable ADC2
ADC_Cmd(ADC3, ENABLE); // Enable ADC3
ADC_DMACmd(ADC1, ENABLE); // Enable ADC1 DMA since ADC1 is the Master
}
void AI_read_adc_input( uint16_t* buffer)
{
buffer[0] = aADCTripleConvertedValue[0]; // Converted Channel 10 input
buffer[1] = aADCTripleConvertedValue[1]; // Converted Channel 11 input
buffer[2] = aADCTripleConvertedValue[2]; // Converted Channel 12 input
buffer[3] = aADCTripleConvertedValue[3]; // Converted Channel 13 input
}

Posted on February 20, 2014 at 19:19

The pins and channels do not permit me to use a single ADC, I have to use all three ADCs. PC0, PC1, PC2 and PC3 only have ADC123_INx alternate functions. How would you suggest that I balance the three ADCs?

I'm not sure I follow the logic. PC[0..3] are available to all three ADC, one ADC could certainly handle all 4 samples, in sequence. The DOUBLE and TRIPLE modes permit you to sample multiple channels at the same point in time, there aren't sufficient resources to support four.

// STM32 ADC Sample 4x STM32F4 Discovery - sourcer32@gmail.com
#include ''stm32f4_discovery.h''
/**************************************************************************************/
void RCC_Configuration(void)
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_DMA2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
}
/**************************************************************************************/
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* ADC Channel 10 -> PC0 - Clashes USB PowerOn
ADC Channel 11 -> PC1
ADC Channel 12 -> PC2
ADC Channel 13 -> PC3 - Clashes DOUT
*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOC, &GPIO_InitStructure);
}
/**************************************************************************************/
void ADC_Configuration(void)
{
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; // 2,4,6,8
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; // 5-20 if interleave mode
ADC_CommonInit(&ADC_CommonInitStructure);
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = ENABLE; // 4 Channels
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // Back-to-Back, maximal rate
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 4;
ADC_Init(ADC1, &ADC_InitStructure);
/* ADC1 regular channel configuration */
ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_28Cycles); // 3,15,28,56,84,112,144,480
ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 2, ADC_SampleTime_28Cycles);
ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 3, ADC_SampleTime_28Cycles);
ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 4, ADC_SampleTime_28Cycles);
/* Enable DMA request after last transfer (Single-ADC mode) */
ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
/* Enable ADC1 DMA */
ADC_DMACmd(ADC1, ENABLE);
/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
}
/**************************************************************************************/
#define BUFFERSIZE 8 // Two Halves
__IO uint16_t ADCConvertedValues[BUFFERSIZE];
static void DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCConvertedValues[0];
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = BUFFERSIZE; // Count of 16-bit words
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_Enable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream0, &DMA_InitStructure);
/* Enable DMA Stream Half / Transfer Complete interrupt */
DMA_ITConfig(DMA2_Stream0, DMA_IT_TC | DMA_IT_HT, ENABLE);
/* DMA2_Stream0 enable */
DMA_Cmd(DMA2_Stream0, ENABLE);
}
/**************************************************************************************/
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable the DMA Stream IRQ Channel */
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/**************************************************************************************/
void DMA2_Stream0_IRQHandler(void)
{
/* Test on DMA Stream Half Transfer interrupt */
if(DMA_GetITStatus(DMA2_Stream0, DMA_IT_HTIF0))
{
/* Clear DMA Stream Half Transfer interrupt pending bit */
DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_HTIF0);
/* Turn LED3 off: Half Transfer */
STM_EVAL_LEDOff(LED3);
// Add code here to process first half of buffer (ping)
}
/* Test on DMA Stream Transfer Complete interrupt */
if(DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0))
{
/* Clear DMA Stream Transfer Complete interrupt pending bit */
DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);
/* Turn LED3 on: End of Transfer */
STM_EVAL_LEDOn(LED3);
// Add code here to process second half of buffer (pong)
}
}
/**************************************************************************************/
int main(void)
{
RCC_Configuration();
GPIO_Configuration();
NVIC_Configuration();
DMA_Configuration();
ADC_Configuration();
STM_EVAL_LEDInit(LED3); /* Configure LEDs to monitor program status */
STM_EVAL_LEDOn(LED3); /* Turn LED3 on */
/* Start ADC1 Software Conversion */
ADC_SoftwareStartConv(ADC1);
while(1); // Don't want to exit
}
/**************************************************************************************/
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf(''Wrong parameters value: file %s on line %d

'', file, line) */
/* Infinite loop */
while (1)
{
}
}
#endif
/**************************************************************************************/

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

Thank you for your reply again.

What I meant is when I look at the processor datasheet it shows Port C having only ADC123_INx as alternate function which I thought meant that if you use port C as analog input you have to use it in triple mode. Now that you say that you do not have to, I followed your sample code to use only one ADC.

With the setting you have seleted in your sample code, in which location will the converted input for each channel be in the ADCConvertedValues[] array? Channel 10 [0] and [1]?

Posted on February 21, 2014 at 11:44

It's a linear array, the DMA operates in a circular manner over it

ADCConvertedValues[0] = Channel 10 (Ping)

ADCConvertedValues[1] = Channel 11 (Ping)

ADCConvertedValues[2] = Channel 12 (Ping)

ADCConvertedValues[3] = Channel 13 (Ping)

ADCConvertedValues[4] = Channel 10 (Pong)

ADCConvertedValues[5] = Channel 11 (Pong)

ADCConvertedValues[6] = Channel 12 (Pong)

ADCConvertedValues[7] = Channel 13 (Pong)

The HT/TC interrupts for the DMA acting as a Group EOC
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
hkamba
Associate II
Posted on May 19, 2014 at 15:08

Can you please explain how I can actually retrieve the converted value for each channel from the ADCConvertedValues? Does it have to be done in the interrupt? If so, how and at what point? You do not have to show me how to retrieve all the converted values, please just show me how to retrieve the converted value for one of the channel, I'll figure out the rest.

Many thanks

Posted on May 19, 2014 at 15:30

No, you don't have to use interrupts, and no you don't need a double sized array, however to have clear access to the values without them changing underneath you would still need to determine when the conversion was complete.

The values are held as an array of 16-bit values, at the PING (HT) interrupt the FIRST HALF of the buffer is valid, ie samples [0..3] at the PONG (TC) interrupt the SECOND HALF of the buffer is valid, ie samples [4..7]. The ordering of the samples matches the sequenced programmed in to the ADC for collecting samples.

If you don't care about the sampling, and just want the values magically changing in the background, shrink the DMA transaction to 4 words, and turn off the interrupts. Then there will be a ONE-to-ONE correlation between the ordered coded for the ADC, and the order in the array.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
hkamba
Associate II
Posted on May 19, 2014 at 16:17

Thanks for your reply.

Is this the correct way to grab the values? Also why does some example projects in the standard library multiply the converted value by 3300 then divide it by 0xFF, some also shift the converted value by 8. This is all very confusing to me...Could you please recommend a good tutorial somewhere?

uint16_t DMA_GetADC(uint16_t Number)
{
return (ADCConvertedValues[Number] & 0x0FFF);
}
/*************************************//**
* \brief DMA2 Stream0 IRQ handler
******************************************/
void DMA2_Stream0_IRQHandler( void )
{
/* Test on DMA Stream Half Transfer interrupt */
if(DMA_GetITStatus(DMA2_Stream0, DMA_IT_HTIF0))
{
/* Clear DMA Stream Half Transfer interrupt pending bit */
DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_HTIF0);
// Add code here to process first half of buffer (ping)
// At the PING the first half of the buffer is valid
// Only 12-bits of the result are significant
uwAN0ConvertedValue = DMA_GetADC(0); 
uwAN1ConvertedValue = DMA_GetADC(1);
uwAN2ConvertedValue = DMA_GetADC(2);
uwAN3ConvertedValue = DMA_GetADC(3);
}
/* Test on DMA Stream Transfer Complete interrupt */
if(DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0))
{
/* Clear DMA Stream Transfer Complete interrupt pending bit */
DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);
// Add code here to process second half of buffer (pong)
// At the PONG the second half of the buffer is valid
// Only 12-bits of the result are significant
uwAN0ConvertedValue = DMA_GetADC(4);
uwAN1ConvertedValue = DMA_GetADC(5);
uwAN2ConvertedValue = DMA_GetADC(6);
uwAN3ConvertedValue = DMA_GetADC(7);
} 
NVIC_ClearPendingIRQ(DMA2_Stream0_IRQn); // Clear interrupt
}
/***********************************************//**
* \brief Get the four converted values
***************************************************/
void AI_readADC(uint16_t *buffer)
{
// Start ADC1 Software Conversion
ADC_SoftwareStartConv(ADC1);
// Wait until conversion completion
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
buffer[0] = uwAN0ConvertedValue;
buffer[1] = uwAN1ConvertedValue;
buffer[2] = uwAN2ConvertedValue;
buffer[3] = uwAN3ConvertedValue;
}

If the functions above are correct, how will (let's say) 1.356 volts be stored in (let's say)

uwAN0ConvertedValue? Will it be 0x054C?