ADC Range seems to switch

  • I'm using an ADC input to measure a 12V battery using some resistors to make a basic voltage divider. Since power consumption is key I'm doing 1000 measurements, averaging them (the only way I can seem to smooth out the worst of the noise), sending the result out to an Influx database and then going into deepsleep for 60 seconds. What I have found is that when hard power cycling the board, very occasionally the ADC seems to be switching it's range - I go from getting steady values in the 1050 range to values in the 3000s. The system then works stably with these values over a good number of power systems and then all of a sudden at a power cycle will switch to numbers in the other range. I'm using 0DB attenuation. It's almost like the reference voltage is changing somehow, but clearly not floating, toggling between two values - perhaps 1.1 and 3.3V. Has anyone seen anything like this? I could in theory compensate in software by detecting the lower range and shifting it, but it's very ugly and I'm concerned this may be a symptom of something else I have done.

  • @guyadams99
    Simple mistakes are always harder to find..

  • @robert-hh - I think I found the answer and posting here in case others hit the same issue. I was close - it wasn't a Vref problem, it was a GND problem. I realised that the difference in the two cases was where I had the USB connected for debugging as well as the 5V power which I think was creating a different ground ref causing the erroneous readings.

  • @guyadams99 That looks quite inconsistent. A reading or .34V would calculate back to a battery of 7.14 V, which is good for a 6V battery while being charged, but a 12 lead battery would be considered as dead. .28V would be even worse. Besides being noisy, at a reading in the range of 1000 the ADC is quite linear. Since the ADC has the 0-value at 70 mV, you may add that to the calculated voltage, which makes the values of .28V + 0.07V and .34V more consistent. And the device I tested once had the full range at 1.045V. So you have to do some testing of the range on your own.
    The voltage divider has a relatively low impedance of 40k, so the internal impedance of the voltage meter and the ESP32 input should not have a large effect. Since you're aiming at slow transition, you could add a capacitor parallel to the 42 k resistor, like 100nF ceramic. That might reduce the noise a little bit, but does not explain the large transitions.
    As far as I know, there is nor way to change Vref, and even if, it had to be lower that 1.1 V to achieve higher readings.
    For P16 (GPIO39), the chip supports an built-in preamplifier. But in micropython there is not way to control if. To sort that out, you could try using "P15" instead, which has no preamp support. But I do not expect a change. It looks more like a more trivial problem, which I just do not see.
    Edit: Are you sure everything is OK with the voltage divider?

    B.t.w: If you talk about pin 16, do you mean "P16"?

  • @robert-hh - I'm using 0db attenuation, pin 16. Definately nothing else connected to that pin. Resistors are 840k and 42k so I'm dividing the voltage down ~21 times. This isn't perfect i.e. if I assume that the battery can get up to 14.1 while charging (reasonable) then I'm still only up to ~0.67V of a 1.1V range and I do plan to tweak these values to get close to the whole range. Currently I'm seeing .34V across the small resistor (measured with a decent volt meter) and seeing:

    Sep 8 10:35:24 Wipy2: raw adc val is 1031
    Sep 8 10:35:24 Wipy2: raw adc val is 1040
    Sep 8 10:35:24 Wipy2: raw adc val is 1010
    Sep 8 10:35:24 Wipy2: raw adc val is 1044
    Sep 8 10:35:24 Wipy2: raw adc val is 1088
    Sep 8 10:35:24 Wipy2: raw adc val is 964
    Sep 8 10:35:24 Wipy2: raw adc val is 1026
    Sep 8 10:35:24 Wipy2: raw adc val is 1004
    Sep 8 10:35:24 Wipy2: raw adc val is 1026

    Average over 1000 samples was 1031. 1.1V * 1031/4096 = 0.28V and I'm expecting 0.34V so a bit off, but I can calibrate for that, but values in the 3000 range would mean a voltage of >0.8V which shouldn't even be possible with my setup. I'm assuming I've done something wrong somewhere!

    Agree that it can't be the attenuation as that would result in lower not higher readings. Is there any way the internal Vref for the ADC can be overridden that I could accidentally be doing?

    Many thanks!

  • @guyadams99 Could you add more details to you explanation:

    1. Which reading do you have at 0db Attenuation, 1050 or 3000?
    2. Which ADC pin are you using?
    3. Do you init the ADC every time again before taking the series?
    4. Are you sure nothing else is connected to that pin and not other setting is made for it?
    5. What are the values of the resistor voltage divider?

    From you description it seems that at 0dB you have a reading of 1050, and then sometimes you get a reading of 3000. That is not possible by changing the attenuation, because that would result in lower reading.

Log in to reply

Pycom on Twitter