cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4 ADC Triple Mode DMA Interrupt problem

pant
Associate II
Posted on June 24, 2015 at 19:34

The original post was too long to process during our migration. Please click on the attachment to read the original post.
18 REPLIES 18
pant
Associate II
Posted on June 24, 2015 at 19:41

Hi again!

I'm sorry I found the problem. In case anyone is interested in using the code, what was missing was to enable the flag! Sorry for that! The missing lines are while configuring the interrupt to add:

      /* Clear update interrupt bit*/

      DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);

      /* TIM IT enable */

      DMA_ITConfig(DMA2_Stream0, DMA_IT_TC, ENABLE);

Regards,

Pantelis

Posted on June 24, 2015 at 19:51

I hope it is not a problem opening two threads with similar subjectconsecutively(but actually different :D ).

 

It does seem a little pointless. If it's a continuing narrative stay in the one thread.

You don't get an interrupt for the DMA, because DMA is not occurring, either at all, or sufficiently.I'm not sure how you're going to sustain the interrupt rate that's likely to occur either.

In Triple mode where you've tied THREE ADC together, the point would be to use a single DMA, reading the COMMON ADC register, and have a sufficiently deep buffer that the processor isn't saturated with interrupts.

See the Triple Six example in

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/ADC%20trigger%20on%20timer%20update&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B&currentviews=1867

.

I suspect there's a single channel version too.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on June 24, 2015 at 19:57

A quick blind mod of my previous example

// STM32 ADC Triple Sample @ 40 KHz (PA.0, PA.1, PA.2) STM32F4 - sourcer32@gmail.com
// Assumptions per system_stm32f4xx.c CPU @ 168 MHz, APB2 @ 84 MHz (/2), APB1 @ 42 MHz (/4)
// Pin conflicts on Discovery, using as a test vehicle
#include ''stm32f4_discovery.h''
/**************************************************************************************/
void RCC_Configuration(void)
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2 | RCC_APB2Periph_ADC3, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
}
/**************************************************************************************/
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* ADC Channel 0 -> PA0 ADC123_IN0
ADC Channel 1 -> PA1 ADC123_IN1
ADC Channel 2 -> PA2 ADC123_IN2
*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
/**************************************************************************************/
void ADC_Configuration(void)
{
ADC_CommonInitTypeDef ADC_CommonInitStructure;
ADC_InitTypeDef ADC_InitStructure;
/* ADC Common Init */
ADC_CommonInitStructure.ADC_Mode = ADC_TripleMode_RegSimult;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1; // 3 half-words one by one, 1 then 2 then 3
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&ADC_CommonInitStructure);
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 1 Channel, no scan
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;
ADC_Init(ADC1, &ADC_InitStructure);
ADC_Init(ADC2, &ADC_InitStructure); // Mirror on ADC2
ADC_Init(ADC3, &ADC_InitStructure); // Mirror on ADC3
/* ADC1 regular channel 0 configuration */
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_15Cycles); // PA0
/* ADC2 regular channel 1 configuration */
ADC_RegularChannelConfig(ADC2, ADC_Channel_1, 1, ADC_SampleTime_15Cycles); // PA1
/* ADC3 regular channel 2 configuration */
ADC_RegularChannelConfig(ADC3, ADC_Channel_2, 1, ADC_SampleTime_15Cycles); // PA2
/* Enable DMA request after last transfer (Multi-ADC mode) */
ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);
/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
/* Enable ADC2 */
ADC_Cmd(ADC2, ENABLE);
/* Enable ADC3 */
ADC_Cmd(ADC3, ENABLE);
}
/**************************************************************************************/
#define BUFFERSIZE (40 * 3 * 2) // 40KHz x3 x2 HT/TC at 1KHz
__IO uint16_t ADCTripleConvertedValues[BUFFERSIZE]; // Filled as pairs ADC1, ADC2, ADC3
static void DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCTripleConvertedValues[0];
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)0x40012308; // CDR_ADDRESS; Packed ADC1, ADC2
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 TIM2_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
/* Time base configuration */
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = ((SystemCoreClock / 2) / 40000) - 1; // 40 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);
}
/**************************************************************************************/
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) // Called at 1 KHz for 40 KHz sample rate, LED Toggles at 500 Hz
{
/* 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();
TIM2_Configuration();
DMA_Configuration();
ADC_Configuration();
STM_EVAL_LEDInit(LED3); /* Configure LEDs to monitor program status */
STM_EVAL_LEDOn(LED3); /* Turn LED3 on, 500 Hz means it working */
/* 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..
pant
Associate II
Posted on June 24, 2015 at 20:28

The original post was too long to process during our migration. Please click on the provided URL to read the original post. https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006I6hf&d=%2Fa%2F0X0000000btZ%2FKjoiXWYFQW3zTXepaoVlDsGi65FmKbe8U3yLDr4kPPk&asPdf=false
pant
Associate II
Posted on June 24, 2015 at 21:12

Dear Mr Clive,

The first code I wrote on the post was working, however I would like to manage and do it the right way as you proposed. However I am studying the Ref Manual along with your code to understand how to do it precisely, but unfortunately nothing seems to work. Below you may see my code's present form:


#include ''ADC_DMA.h''


ADCinputs AnlgInput;

__IO uint16_t ADCTripleConvertedValues[ADC_BUFFERSIZE];



int test=0;


void ADC_Config(void)

{


/* Enable ADC1, ADC2, ADC3 and GPIO clocks */

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2 | RCC_APB2Periph_ADC3, ENABLE);


/* Configure ADC1 Channel10, ADC2 Channel 11 and ADC3 Channel 12 pins as analog inputs (Correspond to PC0, PC1 and PC2)*/

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;

GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;

GPIO_Init(GPIOC, &GPIO_InitStructure);



/* ADC Common Init (ADC_CCR register) */

ADC_CommonInitStructure.ADC_Mode = ADC_TripleMode_RegSimult; // ADC_Mode_Independent for 1 ADC. For ADC123, it will change to ADC_TripleMode_RegSimult!

ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;

ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1; //ADC_DMAAccessMode_1; Enable it in mode 2 or 3 with multi input

ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;

ADC_CommonInit(&ADC_CommonInitStructure);


/* ADC1 Init (ADC_CR1 & ADC_CR2 registers)*/

ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;

ADC_InitStructure.ADC_ScanConvMode = DISABLE; // Each ADC Scans one channel so I think that even in triple mode it won't be used

ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;

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; // One signal scanning

ADC_Init(ADC1, &ADC_InitStructure);

ADC_Init(ADC2, &ADC_InitStructure);

ADC_Init(ADC3, &ADC_InitStructure);


/* ADC1 regular channel10 configuration*/

ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_3Cycles);

ADC_RegularChannelConfig(ADC2, ADC_Channel_11, 1, ADC_SampleTime_3Cycles);

ADC_RegularChannelConfig(ADC3, ADC_Channel_12, 1, ADC_SampleTime_3Cycles);


/* Enable ADC1 */

ADC_Cmd(ADC1, ENABLE);

ADC_Cmd(ADC2, ENABLE);

ADC_Cmd(ADC3, ENABLE);


}



void DMA_Config(void)

{

// Enable DMA clocks

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);



// DMA2 Stream0 channe0 configuration for ADC1

DMA_InitStructure.DMA_Channel = DMA_Channel_0; // Represents the channel of DMA2 Used by ADC1(RM0090 Table 43)

DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC->CDR; // Address of ADC Common Data register &ADC1->DR; &ADC->CDR; RM0090 Table.72

DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCTripleConvertedValues[0]; //Measuredvalues or AnlgInput.A

DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;

DMA_InitStructure.DMA_BufferSize = ADC_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_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);



/*

// DMA2 Stream2 channe1 configuration for ADC2

DMA_InitStructure.DMA_Channel = DMA_Channel_1;

DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC2->DR; // Address of ADC2 Data register RM0090 Table.72

DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&AnlgInput.B;

DMA_Init(DMA2_Stream2, &DMA_InitStructure);

DMA_Cmd(DMA2_Stream2, ENABLE);


// DMA2 Stream1 channe2 configuration for ADC3

DMA_InitStructure.DMA_Channel = DMA_Channel_2;

DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC3->DR; // Address of ADC3 Data register RM0090 Table.72

DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&AnlgInput.C;

DMA_Init(DMA2_Stream1, &DMA_InitStructure);

DMA_Cmd(DMA2_Stream1, ENABLE);

*/



/* Enable DMA request after last transfer (Multi-ADC mode) */

ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);


/*

// Enable DMA request after last transfer (Single-ADC mode)

ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);

ADC_DMARequestAfterLastTransferCmd(ADC2, ENABLE);

ADC_DMARequestAfterLastTransferCmd(ADC3, ENABLE);

*/



// Enable ADC1 DMA since it is the master

ADC_DMACmd(ADC1, ENABLE);

//ADC_DMACmd(ADC2, ENABLE);

//ADC_DMACmd(ADC3, ENABLE);




// Start ADC1 Software Conversions

ADC_SoftwareStartConv(ADC1);

ADC_SoftwareStartConv(ADC2);

ADC_SoftwareStartConv(ADC3);


// Clear update interrupt bit*/

DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);

// TIM IT enable */

DMA_ITConfig(DMA2_Stream0, DMA_IT_TC, ENABLE);


DMA_Cmd(DMA2_Stream0, ENABLE);


//Once transfer of ADC1 is done, generate interrupt

NVIC_InitStructure2.NVIC_IRQChannel = DMA2_Stream0_IRQn;

NVIC_InitStructure2.NVIC_IRQChannelPreemptionPriority = 0;

NVIC_InitStructure2.NVIC_IRQChannelSubPriority = 0;

NVIC_InitStructure2.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure2);


/*

// Clear update interrupt bit

DMA_ClearITPendingBit(DMA2_Stream2, DMA_IT_TCIF2);

// TIM IT enable

DMA_ITConfig(DMA2_Stream2, DMA_IT_TC, ENABLE);


//Once transfer of ADC2 is done, generate interrupt

NVIC_InitStructure2.NVIC_IRQChannel = DMA2_Stream2_IRQn;

NVIC_Init(&NVIC_InitStructure2);


// Clear update interrupt bit

DMA_ClearITPendingBit(DMA2_Stream1, DMA_IT_TCIF1);

// TIM IT enable

DMA_ITConfig(DMA2_Stream1, DMA_IT_TC, ENABLE);


//Once transfer of ADC3 is done, generate interrupt

NVIC_InitStructure2.NVIC_IRQChannel = DMA2_Stream1_IRQn;

NVIC_Init(&NVIC_InitStructure2);


DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);

DMA_ClearITPendingBit(DMA2_Stream2, DMA_IT_TCIF2);

DMA_ClearITPendingBit(DMA2_Stream1, DMA_IT_TCIF1);

*/


}



void TIM2_Configuration(void)

{

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure2;


/* Time base configuration */

TIM_TimeBaseStructInit(&TIM_TimeBaseStructure2);

TIM_TimeBaseStructure2.TIM_Period = ((SystemCoreClock / 2) / 40000) - 1; // 40 KHz, from 84 MHz TIM2CLK (ie APB1 = HCLK/4, TIM2CLK = HCLK/2)

TIM_TimeBaseStructure2.TIM_Prescaler = 0;

TIM_TimeBaseStructure2.TIM_ClockDivision = 0;

TIM_TimeBaseStructure2.TIM_CounterMode = TIM_CounterMode_Up;

TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure2);


/* TIM2 TRGO selection */

TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update); // ADC_ExternalTrigConv_T2_TRGO


/* TIM2 enable counter */

TIM_Cmd(TIM2, ENABLE);

}



void DMA2_Stream0_IRQHandler(void)

{



if(DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0)!=RESET)

{

test++;


if (test%2==1)

{

GPIOC->BSRRH = GPIO_Pin_13;

}

else

{

GPIOC->BSRRL = GPIO_Pin_13;

}


if (test>=100) test=0;


DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);

}


}


/*

void DMA2_Stream2_IRQHandler(void)

{

if(DMA_GetITStatus(DMA2_Stream2, DMA_IT_TCIF2)!=RESET)

{



DMA_ClearITPendingBit(DMA2_Stream2, DMA_IT_TCIF2);

}


}


void DMA2_Stream1_IRQHandler(void)

{


if(DMA_GetITStatus(DMA2_Stream1, DMA_IT_TCIF1)!=RESET)

{



DMA_ClearITPendingBit(DMA2_Stream1, DMA_IT_TCIF1);

}

}

*/


void LED_Config(void)

{


GPIO_InitTypeDef GPIO_InitStructure;


// Enable clock

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);


// Configure GPIO

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;

GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

GPIO_Init(GPIOC, &GPIO_InitStructure);

}

pant
Associate II
Posted on June 24, 2015 at 21:58

Dear Mr Clive,

Excuse me for my many messages. I understood how it works and changed some stuff and now seems to be working properly. If you could please I would like you to have a look at it and tell me if you find it ok. And I have one last question. I would like to ask you how exactly the FIFO will work in that case. I checked the Ref Manual, but I am not really sure about the result. Moreover when will the code enter DMA Interrupt? I guess in order to answer that question I should first understand how the FIFO works precisely, since once the FIFO is filled and the data is ready to be sent, then the interrupt will be generated. Thank you once again! Below you will find my final code. Regards, Pantelis

#include ''ADC_DMA.h''
ADCinputs AnlgInput;
__IO uint16_t ADCTripleConvertedValues[ADC_BUFFERSIZE];
int test=0;
void ADC_Config(void)
{
/* Enable ADC1, ADC2, ADC3 and GPIO clocks */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2 | RCC_APB2Periph_ADC3, ENABLE);
/* Configure ADC1 Channel10, ADC2 Channel 11 and ADC3 Channel 12 pins as analog inputs (Correspond to PC0, PC1 and PC2)*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOC, &GPIO_InitStructure);
/* ADC Common Init (ADC_CCR register) */
ADC_CommonInitStructure.ADC_Mode = ADC_TripleMode_RegSimult; // ADC_Mode_Independent for 1 ADC. For ADC123, it will change to ADC_TripleMode_RegSimult!
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1; //ADC_DMAAccessMode_1; Enable it in mode 2 or 3 with multi input
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&ADC_CommonInitStructure);
/* ADC1 Init (ADC_CR1 & ADC_CR2 registers)*/
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = DISABLE; // Each ADC Scans one channel so I think that even in triple mode it won't be used
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
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; // One signal scanning
ADC_Init(ADC1, &ADC_InitStructure);
ADC_Init(ADC2, &ADC_InitStructure);
ADC_Init(ADC3, &ADC_InitStructure);
/* ADC1 regular channel10 configuration*/
ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_15Cycles);
ADC_RegularChannelConfig(ADC2, ADC_Channel_11, 1, ADC_SampleTime_15Cycles);
ADC_RegularChannelConfig(ADC3, ADC_Channel_12, 1, ADC_SampleTime_15Cycles);
/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
ADC_Cmd(ADC2, ENABLE);
ADC_Cmd(ADC3, ENABLE);
}
void DMA_Config(void)
{
// Enable DMA clocks
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
// DMA2 Stream0 channe0 configuration for ADC1
DMA_InitStructure.DMA_Channel = DMA_Channel_0; // Represents the channel of DMA2 Used by ADC1(RM0090 Table 43)
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC->CDR; // Address of ADC Common Data register &ADC1->DR; &ADC->CDR; RM0090 Table.72
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCTripleConvertedValues[0]; //Measuredvalues or AnlgInput.A
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = ADC_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_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 request after last transfer (Multi-ADC mode) */
ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);
// Enable ADC1 DMA since it is the master
ADC_DMACmd(ADC1, ENABLE);
//ADC_DMACmd(ADC2, ENABLE);
//ADC_DMACmd(ADC3, ENABLE);
// Start ADC1 Software Conversions
ADC_SoftwareStartConv(ADC1);
ADC_SoftwareStartConv(ADC2);
ADC_SoftwareStartConv(ADC3);
// Clear update interrupt bit*/
DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);
// TIM IT enable */
DMA_ITConfig(DMA2_Stream0, DMA_IT_TC, ENABLE);
//Once transfer of ADC1 is done, generate interrupt
NVIC_InitStructure2.NVIC_IRQChannel = DMA2_Stream0_IRQn;
NVIC_InitStructure2.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure2.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure2.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure2);
DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);
DMA_Cmd(DMA2_Stream0, ENABLE);
}
void TIM2_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure2;
/* Time base configuration */
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure2);
TIM_TimeBaseStructure2.TIM_Period = ((SystemCoreClock / 2) / 40000) - 1; // 40 KHz, from 84 MHz TIM2CLK (ie APB1 = HCLK/4, TIM2CLK = HCLK/2)
TIM_TimeBaseStructure2.TIM_Prescaler = 0;
TIM_TimeBaseStructure2.TIM_ClockDivision = 0;
TIM_TimeBaseStructure2.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure2);
/* TIM2 TRGO selection */
TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update); // ADC_ExternalTrigConv_T2_TRGO
/* TIM2 enable counter */
TIM_Cmd(TIM2, ENABLE);
}
void DMA2_Stream0_IRQHandler(void)
{
if(DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0)!=RESET)
{
test++;
if (test%2==1)
{
GPIOC->BSRRH = GPIO_Pin_13;
}
else
{
GPIOC->BSRRL = GPIO_Pin_13;
}
if (test>=100) test=0;
DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);
}
}
void LED_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// Enable clock
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
// Configure GPIO
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOC, &GPIO_InitStructure);
}

Posted on June 24, 2015 at 22:12

Ok, I'm not going to try to unbreak your code.

You would want to configure the NVIC earlier. No particular value to enabling interrupts on all 3 DMA channels. Any latency in the DMA to memory will be eaten by the interrupt latency.

You can use a single DMA channel, when triggered by the ADC (EOC) it will read THREE 16-bit values from the common register in sequence. These three samples will have the same sample time.

The DMA array looks like

ADC1 Sample 1

ADC2 Sample 1

ADC3 Sample 1

ADC1 Sample 2

ADC2 Sample 2

ADC3 Sample 2

..

You can read them from the array, using the HT or TC DMA interrupts
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on June 24, 2015 at 22:20

Running the ADC in saturation,

// STM32 ADC Triple Sample (PA.0, PA.1, PA.2) STM32F4 - sourcer32@gmail.com
#include ''stm32f4_discovery.h''
/**************************************************************************************/
void RCC_Configuration(void)
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2 | RCC_APB2Periph_ADC3, ENABLE);
}
/**************************************************************************************/
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* ADC Channel 0 -> PA0 ADC123_IN0
ADC Channel 1 -> PA1 ADC123_IN1
ADC Channel 2 -> PA2 ADC123_IN2
*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
/**************************************************************************************/
void ADC_Configuration(void)
{
ADC_CommonInitTypeDef ADC_CommonInitStructure;
ADC_InitTypeDef ADC_InitStructure;
/* ADC Common Init */
ADC_CommonInitStructure.ADC_Mode = ADC_TripleMode_RegSimult;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1; // 3 half-words one by one, 1 then 2 then 3
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&ADC_CommonInitStructure);
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 1 Channel, no scan
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // Saturate Conversions
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO; // Ignored, but valid
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_Init(ADC1, &ADC_InitStructure);
ADC_Init(ADC2, &ADC_InitStructure); // Mirror on ADC2
ADC_Init(ADC3, &ADC_InitStructure); // Mirror on ADC3
/* ADC1 regular channel 0 configuration */
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_15Cycles); // PA0
/* ADC2 regular channel 1 configuration */
ADC_RegularChannelConfig(ADC2, ADC_Channel_1, 1, ADC_SampleTime_15Cycles); // PA1
/* ADC3 regular channel 2 configuration */
ADC_RegularChannelConfig(ADC3, ADC_Channel_2, 1, ADC_SampleTime_15Cycles); // PA2
/* Enable DMA request after last transfer (Multi-ADC mode) */
ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);
/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
/* Enable ADC2 */
ADC_Cmd(ADC2, ENABLE);
/* Enable ADC3 */
ADC_Cmd(ADC3, ENABLE);
}
/**************************************************************************************/
#define BUFFERSIZE (40 * 3 * 2) // x3 x2 HT/TC
__IO uint16_t ADCTripleConvertedValues[BUFFERSIZE]; // Filled as pairs ADC1, ADC2, ADC3
static void DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCTripleConvertedValues[0];
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)0x40012308; // CDR_ADDRESS; Packed ADC1, ADC2
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, toggling means it working */
/* 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..
pant
Associate II
Posted on June 24, 2015 at 23:45

Dear Mr Clive,

Thank you very much for your response.

About the NVIC as you suggest I will configure it earlier and regarding the other DMA interrupts I think I disabled them in my last code (Unless I missed something).

My question is this. Is it going to give an interrupts once the three samples are gathered, or once the FIFO is filled? And in case the answer is the second, could you please explain me how will the FIFO be filled in that case?

Finally, concerning the ADC saturation, I saw that you didn't use ContinuousConvMode in your code, however in my code, unless I enable the continuous mode nothing works. I would expect that without using the continuous mode, I should get a measurement everytime the TIM2 triggers my ADC, however it doesn't work.

Once again thank you for your reply.

Regards,

Pantelis