cancel
Showing results for 
Search instead for 
Did you mean: 

ADC conversion question

bee2
Associate II
Posted on April 13, 2013 at 17:39

I have a potential divider circuit set up using the 3V and GND pins on the discovery board and two 100ohm pots, I measure a constant divided voltage of 1.25 (from ground to the ADC input) but when I debug in Uvision my converted voltage drifts between 1.08-1.13 V.

Below is the ADC/DMA setup I'm using plus my voltage calculation. 

I'm wondering if input impedance could cause the difference in my measured value and the ADC converted value?

Also any ideas why the drifting occurs, is it down to junction temperatures?

Calculation used in main:

//convert the ADC value (from 0 to 0xFFF) to a voltage value (from 0V to 2.5V)

  ADC3ConvertedVoltage = ADC3ConvertedValue *(float)2.5/4096;

ADC/DMA setup

/* Includes ------------------------------------------------------------------*/

#include <stdio.h>

#include ''stm32f4xx.h''

#include ''stm32f4_discovery.h''

/* Private define ------------------------------------------------------------*/

#define ADC3_DR_ADDRESS     ((uint32_t)0x4001224C)

/* Private variables ---------------------------------------------------------*/

volatile uint16_t ADC3ConvertedValue=0;

/*************************************************************************************************

  * @brief  ADC3 channel12 with DMA configuration

  * @param  None

  * @retval None

  */

void ADC3_CH12_DMA_Config(void)

{

  ADC_InitTypeDef       ADC_InitStructure;

  ADC_CommonInitTypeDef ADC_CommonInitStructure;

  DMA_InitTypeDef       DMA_InitStructure;

  GPIO_InitTypeDef      GPIO_InitStructure;

  /* Enable ADC3, DMA2 and GPIO clocks ****************************************/

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOC, ENABLE);

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);

  /* DMA2 Stream0 channel0 configuration **************************************/

  DMA_InitStructure.DMA_Channel = DMA_Channel_2;  

  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC3_DR_ADDRESS;

  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC3ConvertedValue;

  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;

  DMA_InitStructure.DMA_BufferSize = 1;

  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;

  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_Disable;         

  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);

  DMA_Cmd(DMA2_Stream0, ENABLE);

  /* Configure ADC3 Channel12 pin as analog input ******************************/

  GPIO_InitStructure.GPIO_Pin = 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_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);

  /* ADC3 Init ****************************************************************/

  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;

  ADC_InitStructure.ADC_ScanConvMode = DISABLE;

  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;

  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;

  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

  ADC_InitStructure.ADC_NbrOfConversion = 1;

  ADC_Init(ADC3, &ADC_InitStructure);

  /* ADC3 regular channel12 configuration *************************************/

  ADC_RegularChannelConfig(ADC3, ADC_Channel_12, 1, ADC_SampleTime_3Cycles);

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

  ADC_DMARequestAfterLastTransferCmd(ADC3, ENABLE);

  /* Enable ADC3 DMA */

  ADC_DMACmd(ADC3, ENABLE);

  /* Enable ADC3 */

  ADC_Cmd(ADC3, ENABLE);

}

10 REPLIES 10
Posted on April 13, 2013 at 18:52

ADC_SampleTime_3Cycles, yeah that's going to suck

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
bee2
Associate II
Posted on April 14, 2013 at 00:58

I can't see any improvement if sample time is increased to more cycles.....same issues

raptorhal2
Lead
Posted on April 14, 2013 at 02:15

I presume you tried the maximum sampling time. Two 100 ohm pots are probably pushing the 3V reference to its capability. Try an external supply for the signal. If you are just experimenting, even a NiCd battery would do.

Add the following to ADC init in order to completely initialize the structure:

ADC_InitStructure.ADC_ExternalTrigConv = 0;

This may not solve this problem, but can solve future problems.

Cheers, Hal

bee2
Associate II
Posted on April 17, 2013 at 07:43

Hi Hal

thanks for reply, been a busy few days but I have managed to get in the lab and check ADC voltages etc and my problem seems to be down to the fact that the ADC Ref voltage is drifting just below 3 volts which is causing my ADC value at a fixed input voltage to drift.

I've tried maximum sampling time of 480 and also an external supply to the potential divider circuit but is there any way to put an external 3V signal on to a pin for the ADC to use as a reference so I can ensure the reference voltage the ADC is using is fixed?

Cheers

zzdz2
Associate II
Posted on April 17, 2013 at 08:50

High pin count versions have separate ADC supply voltage so you could use it.

Generally you can use ADC to sample known reference voltage (e.g. STM32 internal reference) and use it to calculate the measured voltage:

Vin = ADCin*Vref/ADCref

raptorhal2
Lead
Posted on April 17, 2013 at 14:35

As provided, the F4 Discovery board ADC reference uses the 3V reference and filters it with an RCL network to get VREF+. You would have to cut the VREF+ trace and jumper in your 3V, and that may not be as noise free as the provided reference.

I believe you need to offload the board 3V reference by not using it to feed the two pots. Reconsider my battery advice. Or as suggested by Knik, read the reference voltage also and apply a correction factor.

Cheers, Hal

dthedens23
Associate II
Posted on April 17, 2013 at 15:51

Did you read section 5.3.20 ADC characteristics, such as the 50K input impedance?  equation 1 shows the effects.

you might want a simple unity gain rail-to-rail op amp between the resistor divider and ADC input to match impedance.

bee2
Associate II
Posted on April 18, 2013 at 10:14

Thanks for replys.

I did try your suggestion of an external battery supply Hal and I also tried a precision regulator but no difference. I have also tried Knik's idea of setting up two ADC inputs and used a correction factor, but from using the debugger in Uvision it seems that both the ADC vref input and the ADC input readings are floating by different amounts, so not correcting.

When I tie either input to the Discovery board ground or VDD the drift is still there, around 30 bits when tied to ground and upto 100 bits when tied to VDD. Have a missed something basic like the the ground or VDD need to be tied to other pins/gounds etc, I can't understand why the drift is there when tie to ground or VDD surely it should be steady?

I have also looked at the impedance calculation, thanks for pointer.

zzdz2
Associate II
Posted on April 18, 2013 at 16:44

You can check if the ADC pin is configured as analog input.

Maybe pin configured as input floating or pull-down cause such drift.