cancel
Showing results for 
Search instead for 
Did you mean: 

ADC with DMA problem getting values

fiulala
Associate II
Posted on September 18, 2015 at 17:02

Hi,

I was doing some work with ADC using DMA to store the data. So, I tried to configure my stm32f4-disco with an external interrupt. This works good. With the external interrupt I want that the micro takes values from ADC and stores them in a buffer. I watched with a scope the ADC input and i watched also the data stored in the buffer and there is no relation. So the ADC is not taking the values, I don't know what is happening. Made a lot of modifications with adc or dma and the problem is still there. This is the code:

// ADC Mesures a 200 KHz (PC.1) STM32F4 Discovery
// Assumptions per system_stm32f4xx.c CPU @ 168 MHz, APB2 @ 84 MHz (/2), APB1 @ 42 MHz (/4)
#include ''stm32f4xx.h''
#include ''stm32f4xx_rcc.h''
#include ''stm32f4xx_gpio.h''
#include ''stm32f4xx_adc.h''
#include ''stm32f4xx_dma.h''
#include ''stm32f4_discovery.h''
#include ''stm32f4xx_tim.h''
#include ''misc.h''
#include ''stdio.h''
void ClockSetUp(void) {
// Initialize system
SystemInit();
RCC_DeInit();
// PLL Setup
RCC_HSEConfig(RCC_HSE_ON);
RCC_WaitForHSEStartUp();
RCC_PLLConfig(RCC_PLLSource_HSE,5,210,2,4);
RCC_PLLCmd(ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) != SET);
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLK1Config(RCC_HCLK_Div4);
RCC_PCLK2Config(RCC_HCLK_Div2);
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
}
/**************************************************************************/
void RCC_Configuration(void)
{
/* GPIOA clock enable */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
}
/**************************************************************************/
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* ADC Channel 11 -> PC1 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOC, &GPIO_InitStructure);
}
/**************************************************************************/
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 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;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
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
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);
/* ADC1 regular channel 11 configuration */
ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 1, ADC_SampleTime_15Cycles); // PC1
}
/**************************************************************************************/
#define BUFFERSIZE 400
__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_Normal;
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_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 = (84000000 /200000) - 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);
}
/**************************************************************************************/
static void EXTILine0_Config(void);
void GPIO_Initialize(void);
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
static void EXTILine0_Config(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
/* Connect EXTI Line0 to PA0 pin */
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);
/* Configure EXTI Line0 */
EXTI_InitStructure.EXTI_Line = EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
/* Enable and set EXTI Line0 Interrupt to the lowest priority */
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void EXTI0_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line0) != RESET)
{
/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
/* Start ADC1 Software Conversion */
ADC_SoftwareStartConv(ADC1);
/* Disable ADC1 */
ADC_Cmd(ADC1, DISABLE);
}
/* Clear the EXTI line 0 pending bit */
EXTI_ClearITPendingBit(EXTI_Line0);
}
}
/**************************************************************************************/
int main(void)
{
ClockSetUp();
RCC_Configuration();
NVIC_Configuration();
GPIO_Configuration();
USART_Configuration();
TIM2_Configuration();
DMA_Configuration();
ADC_Configuration();
EXTILine0_Config();
while(1){
}
}

5 REPLIES 5
Posted on September 18, 2015 at 17:26

Made a lot of modifications with adc or dma and the problem is still there.

Ok, but making random modifications is not the same as thinking the problem through and understanding the documented function and interaction of the peripherals. The goal with the design in silicon is to come up with the least complicated solution.

Is the SYSCFG peripherals clock enabled anywhere? Do you get any EXTI interrupts?

Does enabling, and then nearly immediately disabling the ADC with no status checks seem like an effective way of doing this? Do you want one sample, or many? The ADC is currently paced by a timer, and the DMA is set up for a single set of transfers, you're going to need to reinitialize the DMA for each new set of transfers, as controlled by the transfer length/count. You'd want to wait for the DMA to complete before disabling the ADC.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
fiulala
Associate II
Posted on September 18, 2015 at 18:15

You are right, but I was lost and didn't know what to do.

I checked EXTI interrupt with a LED and blinks at the correct frequency. I'm doing more stuff with the EXTI interupt. Here's the complete exti interrupt function:

void EXTI0_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line0) != RESET)
{
/* Start ADC1 Software Conversion */
STM_EVAL_LEDToggle(LED4);
/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
ADC_SoftwareStartConv(ADC1);
int i=0;
int value;
int valueinmV;
char strvalue [20];
float time;
float distance;
USART_puts(USART1, ''Begin

'');
while (i<
BUFFERSIZE
){
value
=
ADCConvertedValues
[i];
valueinmV=(value*3000)/4095; //conversion a mV
if (valueinmV>2990){
time=i/200000.;
distance=time*340;
sprintf(strvalue, ''Distance is %f

'', distance);
USART_puts(USART1, strvalue);
STM_EVAL_LEDToggle(LED6);
break;
}
i=i+1;
}
/* Disable ADC1 */
ADC_Cmd(ADC1, DISABLE);
/* Clear the EXTI line 0 pending bit */
EXTI_ClearITPendingBit(EXTI_Line0);
}
}

I have all the usart configuration in the project. That works fine. I want many samples, so now I'll try what you have told me: Does enabling, and then nearly immediately disabling the ADC with no status checks seem like an effective way of doing this? The ADC is currently paced by a timer, and the DMA is set up for a single set of transfers, you're going to need to reinitialize the DMA for each new set of transfers, as controlled by the transfer length/count. You'd want to wait for the DMA to complete before disabling the ADC. Thanks in advance
matic
Associate III
Posted on September 18, 2015 at 18:15

Same as Clive said, but with few more straight forward words...

You can have ADC enabled all the time. As long as you have CONTINUOUS mode disabled, it will convert only once, on command. 

You have to wait for DMA Transfer Complete Flag (TCIF) to be sure all the data is transferred into buffer.

Then you should configure DMA as CIRCULAR. And enabled SCAN mode in ADC configuration.

I think you should also have to enable ''

ADC_DMAAccessMode

'' in ADC configuration.

matic
Associate III
Posted on September 18, 2015 at 18:16

Same as Clive said, but with few more straight forward words...

You can have ADC enabled all the time. As long as you have CONTINUOUS mode disabled, it will convert only once, on command. 

You have to wait for DMA Transfer Complete Flag (TCIF) to be sure all the data is transferred into buffer.

Then you should configure DMA as CIRCULAR. And enabled SCAN mode in ADC configuration.

I think you should also have to enable ''

ADC_DMAAccessMode

'' in ADC configuration.

matic
Associate III
Posted on September 18, 2015 at 18:17

Same as Clive said, but with few more straight forward words...

You can have ADC enabled all the time. As long as you have CONTINUOUS mode disabled, it will convert only once, on command. 

You have to wait for DMA Transfer Complete Flag (TCIF) to be sure all the data is transferred into buffer.

Then you should configure DMA as CIRCULAR. And enabled SCAN mode in ADC configuration.

I think you should also have to enable ''

ADC_DMAAccessMode

'' in ADC configuration.