cancel
Showing results for 
Search instead for 
Did you mean: 

ADC reads wrong values

rene2399
Associate II
Posted on July 27, 2009 at 07:06

ADC reads wrong values

13 REPLIES 13
rene2399
Associate II
Posted on May 17, 2011 at 13:18

Hello,

I have a problem with the ADC, if I read static values everything is fine, but dynamic values are wrong.

parameter:

µC: STM32F103RBT6 IAR KickStart Kit

VDDA: 3,3 V

VSSA: 0 V

samplerate: 25,6 kHz

signal: 1 V peak-to-peak 3kHz

offset: 1,65 V

at Pin PA5 = ADC5

correct values:

Vmax: 2,15 V = 2668

Vmin: 1.15 V = 1427

my values:

Vmax: 2200

Vmin: 1919

Code:

Clocks:

/* RCC system reset(for debug purpose) -------------------------------------*/

RCC_DeInit();

/* Enable HSE --------------------------------------------------------------*/

RCC_HSEConfig(RCC_HSE_ON);

/* Wait till HSE is ready --------------------------------------------------*/

HSEStartUpStatus = RCC_WaitForHSEStartUp();

if(HSEStartUpStatus == SUCCESS)

{

/* Enable Prefetch Buffer ------------------------------------------------*/

FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

/* Flash 2 wait state ----------------------------------------------------*/

FLASH_SetLatency(FLASH_Latency_2);

/* HCLK = SYSCLK ^= 72 MHz -----------------------------------------------*/

RCC_HCLKConfig(RCC_SYSCLK_Div1);

/* PCLK2 = HCLK ^= 72 MHz ------------------------------------------------*/

RCC_PCLK2Config(RCC_HCLK_Div1);

/* PCLK1 = HCLK/2 ^= 36 MHz ----------------------------------------------*/

RCC_PCLK1Config(RCC_HCLK_Div2);

/* Configure ADCCLK such as ADCCLK = PCLK2/8 ^= 9 MHz -------------------*/

RCC_ADCCLKConfig(RCC_PCLK2_Div8);

/* PLLCLK = 8MHz * 9 = 72 MHz --------------------------------------------*/

RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);

/* Enable PLL ------------------------------------------------------------*/

RCC_PLLCmd(ENABLE);

/* Wait till PLL is ready ------------------------------------------------*/

while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)

{

}

/* Select PLL as system clock source -------------------------------------*/

RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

/* Wait till PLL is used as system clock source --------------------------*/

while(RCC_GetSYSCLKSource() != 0x08)

{

}

}

GPIO:

/* GPIO Configuration ------------------------------------------------------*/

GPIO_InitTypeDef GPIO_InitStructure;

/* Configure PA.05 (ADC Channel 5) as analog input -------------------------*/

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;

GPIO_InitStructure.GPIO_Speed = (GPIOSpeed_TypeDef)0;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;

GPIO_Init(GPIOA, &GPIO_InitStructure);

ADC:

ADC_InitTypeDef ADC_InitStructure;

/* System clocks configuration ---------------------------------------------*/

/* Enable peripheral clocks ------------------------------------------------*/

/* Enable ADC1 and GPIOA clock ---------------------------------------------*/

RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA , ENABLE);

/* Reset the ADC register to their default reset values --------------------*/

ADC_DeInit(ADC1);

/* ADC1 configuration ------------------------------------------------------*/

ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;

ADC_InitStructure.ADC_ScanConvMode = DISABLE;

ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;

ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;

ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

ADC_InitStructure.ADC_NbrOfChannel = 1;

ADC_Init(ADC1, &ADC_InitStructure);

/* Enable ADC1 -------------------------------------------------------------*/

ADC_Cmd(ADC1, ENABLE);

/* Enable ADC1 reset calibaration register ---------------------------------*/

ADC_ResetCalibration(ADC1);

/* Check the end of ADC1 reset calibration register ------------------------*/

while(ADC_GetResetCalibrationStatus(ADC1) == SET);

/* Start ADC1 calibaration -------------------------------------------------*/

ADC_StartCalibration(ADC1);

/* Check the end of ADC1 calibration ---------------------------------------*/

while(ADC_GetCalibrationStatus(ADC1) == SET);

Int16U GetADC1Channel(Int8U channel)

{

// Configure channel

ADC_RegularChannelConfig(ADC1, channel, 1, ADC_SampleTime_55Cycles5);

// Start the conversion

ADC_SoftwareStartConvCmd(ADC1, ENABLE);

// Wait until conversion completion

while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);

// Get the conversion value

return ADC_GetConversionValue(ADC1);

}

st3
Associate II
Posted on May 17, 2011 at 13:18

What do you mean by ''dynamic values'' ?

sofiene
Associate III
Posted on May 17, 2011 at 13:18

Hi rene,

I think you mean by ''dynamic values'' that the signal you mesured is a variable signal. Please refer to this application note that describes methods to get the best ADC accuracy: ''How to get the best ADC accuracy in STM32F10xxx devices''

http://www.st.com/stonline/products/literature/an/15067.pdf

B.R.

M3allem

rene2399
Associate II
Posted on May 17, 2011 at 13:18

''Variable'' signal this is what I mean, thx. ^^

@M3allem: I have read the application note, but I can't find anything wrong. As I wrote, I use the KickStart Kit and connected a frequenz generator directly to the Pin. I also use an oscilloscope to check the signal at the Pin, and the signal is okay.

kutnickg
Associate II
Posted on May 17, 2011 at 13:18

What is your board exactly? If it's the KickStart board STM3210E-SK/IAR then PA.05 is connected to an LCD controller chip which could be interfering with your signal. If this is the board you have, have you been sure to disconnect this chip or take some other measures to ensure that this isn't happening?

The other issue I see is that there's nothing in your code that shows you're really sampling at 25.6KHz. The rate you supply to ADC_RegularChannelConfig (which you should only need to do once, by the way) determines how long a single conversion will take, but the actual sample rate will depend on how often you call this function.

Of course, if you're calling it repeatedly in a loop without any delays in between then the result will be almost the same as continuous conversion, in which case you should probably just use that instead. If this is what you're doing then your effective sample rate would be close to 9MHz / (55.5 + 12.5) = 132.353KHz, which is not what you said the sample rate is. So it's important that we know the details of when and how you're calling this function. However, it'll still be better for you to either use continuous conversion (if your desired sample rate is high enough) or external trigger on the ADC supplied by a timer.

cosmapa
Associate II
Posted on May 17, 2011 at 13:18

I dont know if this is related but I am observing a strange problem at the time a new ADC channel is selected.

I am running continuous captures on 12 Channels (including the 2 internal channels vref, temp) with DMA, using the ST provided examples.

The 4 analog inputs are each connected to an external 30K resistor pulling to ground and nothing else. With a voltmeters, I read around 40mV on the input pin. With the oscilloscope, I see a 100 to 300mV spike on the input pin.

The spike IS GENERATED BY MCU.

It is output at precisely the time that Analog input channel is selected. By putting the probe on the next input channel, I see a similar pulse that is precisely when the next channel is selected. In this case 3us later(36MHz + using ADC prescaller 2/4, and 5 cycles). See capture attached. Changing the ADC prescaller changes the period of the pulses.

As a result, the ADC doesnt read exactly 0 on these inputs even though they are only connected to ground via a resistor. Connecting to ground with a wire causes the ADC to read 0.

Has anyone else seen this?

Is there a way to make the ADC wait a moment before starting the conversion?

Thanks

andreas2
Associate II
Posted on May 17, 2011 at 13:18

That behavior is mentioned in the errata.

cosmapa
Associate II
Posted on May 17, 2011 at 13:18

Thanks for the input. The errata I was able to find talks about a 10ns pulse of 150mV max on ADC0 only. What I see is much longer (almost 5us) and is on every channel with a 30K resistor to ground at the input.

See capture of ADC Ch2 input. In this case, I configured the ADC to capture Ch2 twice in a row. The spike can be seen at the start of both conversions. It is tied to conversion start and not channel switching, which makes workaround that much more difficult.

Hopefully it is because of something I'm doing wrong but I fail to see what it could possibly be.

aled
Associate II
Posted on May 17, 2011 at 13:18

I'm seeing exactly the same problem:

// Sample Channel 11

ConversionComplete = FALSE;

ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 1, ADC_SampleTime_13Cycles5); // Select the channel

ADC_SoftwareStartConvCmd(ADC1, ENABLE); // Start a conversion

while(ConversionComplete == FALSE); // Block until the ISR has fired

// Sample Channel 10

ConversionComplete = FALSE;

ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_13Cycles5); // Select channel 10

ADC_SoftwareStartConvCmd(ADC1, ENABLE); // Start a conversion

while(ConversionComplete == FALSE); // Block until the ISR has fired

AmbientAverage += ConversionResult; // Add the result to the averageing variable

There seems to be a similar spike to what you're seeing when I sample channel 10. The amplitude of the spike is a higher voltage when channel 11 is higher. It seems to me that the channels are shorting during the channel switching in the multiplexer.

Any ideas how to resolve this?