cancel
Showing results for 
Search instead for 
Did you mean: 

2channels ADC + DMA + TIMER

tom23
Associate II
Posted on January 04, 2014 at 22:51

Hello,

I would like to sample 2 analog channels with 100kHz (STM32F429 disco). I found examples only with one channel. I tryed to edit it, but my code dont work. If I placed breakpoint into DMA2_Stream4_IRQHandler() , program never break there. thanks for help

#include ''stm32f4xx.h''
#define BUFFERSIZE 100 // What size is neccesarry?
__IO uint16_t ADCConvertedValue[BUFFERSIZE];
void
GPIO_config(
void
)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_StructInit(&GPIO_InitStructure);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOC, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; 
// ADC channel 5
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; 
// ADC channel 13
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOC, &GPIO_InitStructure);
}
void
ADC_config(
void
)
{
ADC_InitTypeDef ADC_InitStructure;
ADC_StructInit(&ADC_InitStructure);
ADC_CommonInitTypeDef ADC_CommonInitStructure;
ADC_CommonStructInit(&ADC_CommonInitStructure);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInit(&ADC_CommonInitStructure);
ADC_InitStructure.ADC_ScanConvMode = ENABLE; 
// more then 1 channel in group
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; 
// conversions triggered
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;
ADC_InitStructure.ADC_NbrOfConversion = 2;
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_Init(ADC1,&ADC_InitStructure);
ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 1, ADC_SampleTime_112Cycles);
ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 2, ADC_SampleTime_112Cycles);
// 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);
}
void
DMA_config()
{
DMA_InitTypeDef DMA_InitStructure;
DMA_StructInit(&DMA_InitStructure);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);
//==Configure DMA2 - Stream 4
DMA_DeInit(DMA2_Stream4); 
//Set DMA registers to default values
DMA_InitStructure.DMA_Channel = DMA_Channel_4;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; 
//Source address
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCConvertedValue[0]; 
//Destination address
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = BUFFERSIZE;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; 
//source size - 16bit
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; 
// destination size = 16b
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_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream4, &DMA_InitStructure); 
/* Enable DMA - Transfer Complete interrupt */
DMA_ITConfig(DMA2_Stream4, DMA_IT_TC, ENABLE);
/* DMA2_Stream4 enable */
DMA_Cmd(DMA2_Stream4, ENABLE);
}
void
TIM2_config()
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
/* Time base configuration */
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = (180000000 / 100000) - 1; 
// 180M/100k = 1800tick = 10us - Is correct?
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);
/* TIM2 enable counter */
TIM_Cmd(TIM2, ENABLE);
}
void
NVIC_config()
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable the DMA Stream IRQ Channel */
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure); 
}
void
DMA2_Stream4_IRQHandler(
void
)
{
/* Test on DMA Stream Transfer Complete interrupt */
if
(DMA_GetITStatus(DMA2_Stream4, DMA_IT_TCIF0))
{
/* Clear DMA Stream Transfer Complete interrupt pending bit */
DMA_ClearITPendingBit(DMA2_Stream4, DMA_IT_TCIF0);
}
}
int
main(
void
)
{
GPIO_config();
NVIC_config();
TIM2_config();
DMA_config();
ADC_config();
// I need SysTick_Handler() per 1ms
if
(SysTick_Config(SystemCoreClock / 1000))
{
/* Capture error */
while
(1);
} 
// start ADC conversion
ADC_SoftwareStartConv(ADC1);
while
(1)
{
}
}

#adc #dma #timer-2channels
11 REPLIES 11
Posted on January 05, 2014 at 02:14

For C++ make sure the IRQHandler's name isn't mangled (check .MAP, and vector linkage)

Also

if
(DMA_GetITStatus(DMA2_Stream4, DMA_IT_TCIF0))

That should be DMA_IT_TCIF4 shouldn't it? Is it even Stream 4? I'd have to check the manual, but my other 2 Channel (same sample point) example used Stream 0.

/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/ADC%20in%20Dual%20Mode%20Simultaneously&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B&currentviews=404

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
raptorhal2
Lead
Posted on January 05, 2014 at 02:14

ADC1 is on Channel 0, Stream 0 or 4. See RM00090 Rev 5 Reference Manual, Table 44.

Cheers, Hal

Posted on January 05, 2014 at 02:19

Yeah, Stream4 should be fine.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
raptorhal2
Lead
Posted on January 05, 2014 at 03:08

Just to clarify - Tomas' code is attempting to use Channel 4.

Cheers, Hal

Posted on January 05, 2014 at 03:33

0690X00000605WfQAI.png
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
tom23
Associate II
Posted on January 05, 2014 at 07:36

I am using C. You can see a part of file startup_stm32f429_439xx.S with

DMA2_Stream4.

The file system_stm32f4xx.it.cdoes not contain

DMA2_Stream4_IRQHandler.

It placed

in main.c

file

.

Is it correct?

* must be placed on this to ensure that it ends up at physical address
* 0x0000.0000.
*
*******************************************************************************/
.section .isr_vector,''a'',%progbits
.type g_pfnVectors, %object
.size g_pfnVectors, .-g_pfnVectors
g_pfnVectors:
.word _estack
.word Reset_Handler
...
/* External Interrupts */
.word DMA2_Stream4_IRQHandler /* DMA2 Stream 4 */
/*******************************************************************************
*
* Provide weak aliases for each Exception handler to the Default_Handler.
* As they are weak aliases, any function with the same name will override
* this definition.
*
*******************************************************************************/
.weak DMA2_Stream4_IRQHandler
.thumb_set DMA2_Stream4_IRQHandler,Default_Handler

Posted on January 05, 2014 at 08:11

You mix variable definitions, with function calls, this is a very C++ construct, so just checking.

As Hal highlighted, and I diagrammed your real problem is the Channel4 is not usable as it has NO connectivity to ADC1

Further if you use Stream4 then you need to be examining the TC4 flags, as they are interrelated.

You can define the body for the IRQHandler functions in any source/objects files you choose, the linker resolves that.

C++ mangles names based on parameters, so the linkage would not occur, and the weak definition would prevail.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
tom23
Associate II
Posted on January 05, 2014 at 09:08

I mixed up ''stream'' and ''channel in stream''. I fixed it, but the code still doesnt work. Program never break on breakpoint in DMA2_Stream4_IRQHandler.

I am not sure of size of ADCConvertedValuetoo.

void DMA2_Stream4_IRQHandler(void)
{
// Test on DMA Stream Transfer Complete interrupt
if(DMA_GetITStatus(DMA2_Stream4, DMA_IT_TCIF4))
{
// Clear DMA Stream Transfer Complete interrupt pending bit
DMA_ClearITPendingBit(DMA2_Stream4, DMA_IT_TCIF4);
}
}
void ADC_config(void)
{
ADC_InitTypeDef ADC_InitStructure;
ADC_StructInit(&ADC_InitStructure);
ADC_CommonInitTypeDef ADC_CommonInitStructure;
ADC_CommonStructInit(&ADC_CommonInitStructure);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInit(&ADC_CommonInitStructure);
ADC_InitStructure.ADC_ScanConvMode = ENABLE; // more then 1 channel in group
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; // conversions triggered
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;
ADC_InitStructure.ADC_NbrOfConversion = 2;
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_Init(ADC1,&ADC_InitStructure);
ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 1, ADC_SampleTime_112Cycles);
ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 2, ADC_SampleTime_112Cycles);
// 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);
}
void DMA_config()
{
DMA_InitTypeDef DMA_InitStructure;
DMA_StructInit(&DMA_InitStructure);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);
//==Configure DMA2
DMA_DeInit(DMA2_Stream4); //Set DMA registers to default values
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; //Source address
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCConvertedValue[0]; //Destination address
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = BUFFERSIZE;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //source size - 16bit
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; // destination size = 16b
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_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream4, &DMA_InitStructure); //Initialize the DMA
/* Enable DMA - Transfer Complete interrupt */
DMA_ITConfig(DMA2_Stream4, DMA_IT_TC, ENABLE);
/* DMA2_Stream4 enable */
DMA_Cmd(DMA2_Stream4, ENABLE);
}
void TIM2_config()
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
/* Time base configuration */
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = (180000000 / 100000) - 1; // 180M/100k = 1800tick = 10us
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);
/* TIM2 enable counter */
TIM_Cmd(TIM2, ENABLE);
}
void NVIC_config()
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable the DMA Stream IRQ Channel */
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}

Posted on January 05, 2014 at 14:09

Size appears correct, it's in units of transfers, not bytes

DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;

No, don't do that you want it to remain pointing at ADR1->DR, the timer triggers the ADC start, the ADC EOC triggers the DMA
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..