Take the 2-minute tour ×
Electrical Engineering Stack Exchange is a question and answer site for electronics and electrical engineering professionals, students, and enthusiasts. It's 100% free, no registration required.

I've got an STM32 with a straightforward voltage divider bringing in a battery level line to an ADC. The problem is that I'm getting a value that doesn't make a ton of sense to me. According to my scope, B_LEV (which is the divided line, going to GPIOC pin 1 / ADC1 channel 11) is 2.49V, with a VREF of 3.3V. The value I'm getting is 2148 (12bit adc), which should translate to 2148 / 4096 * 3.3 = 1.78V, which is obviously not true..

Am I screwing up on the math, or my ADC setting?

Here's the initialization and reading code:

void InitADC() {
  ADC_InitTypeDef ADC_InitStructure;

  RCC_ADCCLKConfig(RCC_PCLK2_Div4);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

  GPIO_InitTypeDef GPIO_InitStructure;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  GPIO_Init(GPIOC, &GPIO_InitStructure);

  ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_NbrOfChannel = 1;
  ADC_Init(ADC1, &ADC_InitStructure);

  ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 1, ADC_SampleTime_239Cycles5);    
  ADC_Cmd(ADC1, ENABLE);
  ADC_ResetCalibration(ADC1);

  while(ADC_GetResetCalibrationStatus(ADC1));
  ADC_StartCalibration(ADC1);

  while(ADC_GetCalibrationStatus(ADC1));
  ADC_SoftwareStartConvCmd(ADC1, ENABLE);  
}

int ReadBatteryValue() {
  // Make sure we have conversion completion
  if(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET)
    return 500;
  // Reset the flag
  ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
  // Get the conversion value
  return ADC_GetConversionValue(ADC1);
}
share|improve this question
    
Why are you shifting the conversion result twice to the right? –  dext0rb Jan 4 '13 at 5:37
    
i'll take that out of the post - it's not really salient here. this is sent over the wire, and the consumer expects it to be a 10 bit value, not 12 bit. –  kolosy Jan 4 '13 at 5:52
    
do you have a common ground between your scope, the micro and the adc? –  Stacey Anne Jan 4 '13 at 6:03
    
yes. it's all packed up on a third-party module, but i do. –  kolosy Jan 4 '13 at 6:08
2  
Out of curiosity (since your sampling time appears to be large), what are resistor values in your divider? –  Thorn Jan 4 '13 at 7:24
show 8 more comments

2 Answers

Take a peek at the input impedance of the device vs the values of the resistors in your divider. You might be pullng down your input.

You say that you've got a "straightforward voltage divider" going into your ADC. I'm suggesting that it might be a bit less straightforward than you think.

In an ideal world, you assume that the resistance of an analog input (or any amplifier) is infinite. In fact, the input should be considered to be a finite resistance. On a very good ADC, like the type you would expect to see on a National Instruments card, the input impedance is in the MegaOhm range. On typical microcontrollers, though, its much lower, usually around 10 kiloohms.

Let's assume, your straightforward voltage divider is 5v going through a 10K resistor in series with a 20K resistor, and your voltage at the ADC would be 5V*20Kohms/30Kohms, or 5V*0.66=3.35V. In reality, because the input impedance of your device is 10K, that 20K resistor is really 20K in parallel with the device's 10K, or 6.7K!!! Now what the ADC actually sees is 5V*(6.7k/16.7K), or 5V*0.40, or 2V.

Easiest way to tell what's going on: with the circuit on, use a multimeter to measure the voltage at the ADC, instead of assuming the simple voltage divider is acting the way you think it is.

In fact, an STM32 datasheet on page 124 says the input impedance of the ADC is 50K, suggesting that your voltage divider is in the neighborhood of a 50K in series with a 100K from the numbers you've given, if this is in fact the issue.

Try to keep your voltage divider resistors on the order of 1k to 2k to avoid this problem, or buffer your analog input with an op amp configured as a voltage follower.

Correction: looks like the actual input impedance, at least of the device in the datasheet I randomly chose, is 6K, or maybe even a funky function of sampling frequency (like a switched cap function) -- use the numbers at your own risk, but I think you're having a low input impedance problem.

share|improve this answer
    
This comment exhausts my EE knowledge. I know the concept of impedance, but not enough to be able to check what you're suggesting. Can you provide a bit more detail? –  kolosy Jan 4 '13 at 21:35
    
Sure. I'll edit my answer –  Scott Seidman Jan 4 '13 at 22:06
    
Sorry for the cryptic original post –  Scott Seidman Jan 4 '13 at 22:17
    
thanks for clarifying! that said, a few things - the 2.49V coming in is measured between ground and the adc pin, not the actual battery voltage. second - the divider is a 5.4k and a 3.4k resistor, which seems to be in the range you're suggesting... –  kolosy Jan 4 '13 at 22:46
    
I see now, you do have a scope measurement. Is that measurement taken with the whole circuit on, or with your divider disconnected from the ADC? Since the \$ R_{in} \$ is less than I thought it was, so are the guidelines for the suggested resistors. Hundreds of ohms would be better, or a voltage follower as a buffer is even better. Of course, if your scope measurement was in the full functioning circuit, this can't be the problem. –  Scott Seidman Jan 4 '13 at 22:56
show 1 more comment
up vote 1 down vote accepted

So - after digging around some more, I realized that the problem is far simpler - I'm writing code for a third-party module that's based on an STM32 chip, and they had their GPIOs remapped. I was looking at the wrong ADC channel (sigh).

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.