I have a pressure sensor that outputs voltage up to 4.5 volts, so before connecting this to my Pico W ADC pin, I apply a voltage divider, consisting of a couple resistors… 12K on top of 33K, which should reduce the voltage seen by the ADC by around 73% (33/45)… and bring the signal below 3.3 V.
Tested the circuit before connecting to my PIco… works as expected. Connect to Pico, and what I see on the ADC (and also as measured with DVM), is much less. A 3V input should reduce to around 2.2V… but I get about 1.6V.
I’ve read the datasheet notes… its not about ripple. If I connect my sensor ground to AGND instead of GND, it doesn’t make much difference. I am only sampling once a second, and my signal voltage is fairly static, or should be (That said, I have yet to connecta CRO to it) but bench tests with fixed voltage inputs show much the same result.
What is going on here? Why the huge diffeence between voltage division expected and actual? It behaves as though connecting to the ADC pin provides a significant alternative path to ground, thereby altering my divider ratio.
Next option is to run the signal through an Op Amp… i was hoping to keep it simple.
Hi Trevor
There are a couple of dependencies here. One is the input resistance of the ADC as this is effectively in parallel with your 33K of the voltage divider. This “should” be fairly high and have little consequence BUT you don’t know and is just another thing that is not published or very hard to find. As a general rule it is wise to keep a potentiometer or total resistance of any divider below 10kΩ because of this. Keeping the bottom leg of any divider as low as practicable will minimise this effect. You have already flagged this possibility in your post.
Another item worth mentioning here is the 10MΩ resistance of your DMM which will play the same part if your divider resistances are too high. You should be aware of all these little things about your test equipment so you can evaluate actual measurements correctly (your oscilloscope will have the same effect)
The other is really an offshoot of the divider resistance. It is the ability of the source (in this case your sensor) to supply the extra current a lower resistance divider will use.
If this is your problem the only alternative is to interface an OpAmp configured as a voltage follower. Between sensor and divider to supply any extra current caused by reducing your divider resistance OR between divider and ADC so the very high input resistance of a voltage follower will not affect the divider action.
NOTE: This OpAmp has to be a “rail to rail” type. A “normal” op amp will only output between about 1V and 3.5V with a 5V supply. A “rail to rail” OpAmp will swing to within a few mV of the supply voltage. A good choice would be the LM6482 Dual Amp. Ground the unused inputs.
Cheers Bob
PS. Reducing the divider resistance (by at least a factor of 10) would be the simplest way out but you would have to check that your sensor will provide the extra current.
It is published and it’s not hard to find.
“The ADC input is capacitive, and when sampling, it places about 1pF across the input (there will be additional capacitance from outside the ADC, such as packaging and PCB routing, to add to this). The effective impedance, even when sampling at 500ksps, is over 100kΩ, and for DC measurements there should be no need to buffer.” RP2040 Datasheet: A microcontroller by Raspberry Pi.
Hi Jef
Found that bit of info. What I was getting at is that we mortals would normally purchase a built up module with that chip on board (or I would anyway) and a few things such as input resistance would be handy things to know in situations like Trevor’s. Sure this info can be found in the Chip data sheet, all 600 pages of it but a bit of info in the built up module specs would not hurt I don’t think.
Anyway back to this one. Compared to other inputs 100kΩ seems a bit low and across 33k makes a bit of difference. The 33k effectively becomes about 25k which is going to make a difference but not to the extent that Trevor is seeing. 3V input goes from 2.16V to 2.02V which is probably unacceptable but not as bad as Trevor measured. I have not looked but I would think that somewhere in the text re the module Trevor is using would be a recommendation to keep voltage divider resistance as low as possible and below total of 10k. I think from memory Arduino does that.
Just a bit of pertinent trivia…
Quite some time ago I did attempt (with some approximation) to measure the input resistance of a UNO R3. Was a bit difficult as the highest resistor I could lay my hands on was 22MΩ and as the 10MΩ of my DMM is significant across the high ADC resistance I used the actual ADC readings as an approximate measurement. Anyway the outcome was that this ADC resistance approximated up into the GΩ values.
Anyway there may be some other factor at work here. Sight unseen I don’t know what. If Trevor lowered his divider values by a factor of 10 or more and provided his sensor can provide the extra current this might solve his problem.
Cheers Bob
Add on
Dan might be onto something here too. See above.
Checked resistor values… they are quite close to spec, but even so, this does not explain the behaviour I see, ie the divider ratio changing markedly when the Pico ADC pin is connected. That is the crux of the matter… I think Bob is on the money
I’ve shown my calibration code… very basic stuff.
I will try reducing my divider resistors by a factor of 10 ASAP, that seems likely to substantially reduce the effect, notwithstanding the comment above that ‘… for DC measurements there should be no need to buffer…’
And failing that, I will wire up an op amp, I already have one on my board, so not too much hassle.
Cheers,
T.
from umachine import ADC
import utime
adc = ADC(2) # tried ADC(0)... lets see if ADC(2) is any different
MIN_V = 0.5 # sensor returns voltage between 0.5 and 4.5 volts
MAX_V = 4.5
DV = MAX_V - MIN_V
MAX_P = 800 # full scale is 800 kPa
MIN_P = 0
DP = MAX_P - MIN_P
SLOPE = DP / DV
INTERCEPT = SLOPE * MIN_V
def v_to_kpa(ADC_val:float)->int:
sensor_V = ADC_val * 4.5 / 3.3 # undo the voltage divider compression
return max(0, int(SLOPE * sensor_V - INTERCEPT)) # apply device characteristic to get pressure
def main():
while True:
raw_value = adc.read_u16()
# raw_int = input("Enter ADC value: ")
reduced_V = 3.3 * float(int(raw_value) / 65535)
# strv = input("Enter voltage: ")
# reduced_V = float(strv)
pressure_val = v_to_kpa(reduced_V)
print(f"{raw_value=:5>} {reduced_V=:2f} {pressure_val=}")
utime.sleep(1)
if __name__ == "__main__":
main()
Hi Trevor
Found this on page 558 of the data sheet linked by Jeff. Enclosed in a red box with a red “Note” heading so might be important.
Quote
When using an ADC input shared with a GPIO pin, the pin’s digital functions must be disabled by setting IE low and OD high in the pin’s pad control register. See Section 2.19.6.3, “Pad Control - User Bank” for details. The maximum ADC input voltage is determined by the digital IO supply voltage (IOVDD), not the ADC supply voltage (ADC_AVDD). For example, if IOVDD is powered at 1.8V, the voltage on the ADC inputs should not exceed 1.8V even if ADC_AVDD is powered at 3.3V. Voltages greater than IOVDD will result in leakage currents through the ESD protection diodes. See Section 5.5.3, “Pin Specifications” for details.
End quote.
If lowering your divider resistance values does nothing what might be worth a try would be apply a voltage that will keep the actual input below 1.8V and see if that gives you the correct voltage. That might indicate whether or not the condition as outlined above is the cause or not.
Any OpAmp you use has to be “rail to rail” as I said above. That LMC6482 I mentioned above (I mistakenly left out the “C” above) will work with an operating voltage down to 2V so is quite happy at 3.3V. If you only wanted up to about 3V you might get away with an “ordinary” Amp with a 5V supply but you won’t get any where near 0V.
Cheers Bob
The Pico ADC is not very good compared to an ATMega328P ADC.
I experienced similar conditions when first using the Pico ADC. After reading the Pico documentation from Raspberry and playing with different resistor divider values I came to the conclusion it was not worth using the Pico ADC for any real work.
Whatever I setup had to be trial and error to get valid readings. You also have to cater for the varying readings which are not related to the input signal changing. If the voltage level does not change the readings should not. i measured these over a long period of time.
When trying to use the LiPo battery voltage monitor of the Pico the same thing happened. Readings vary too much. In the end I used a op amp to compare when the battery voltage was too low. Worked much better.
In my opinion the ADC on the Pico was an after thought and is very poor design. Considering it is the first Raspberry Pi to have an ADC built in, not surprising. AMD have been designing ADC for the micos for a long time hence the quality of the ATMega328P ADC.
Thanks for the useful comments re ADC, Jim… noted.
It’s a little late for me to change horses at this stage, .things are certainly working much better with a voltage divider using 2K/5K rather than 12k/33K, there is still a small difference when I connect to the ADC, but it is tolerable for my purposes. Thanks Bob for your help with this!
Re LiPo monitoring… I am referring to WL_GPIO2 to monitor VBUS (on/off only), how do you monitor LiPo (which is connected to Core’s LiPo dev board)? I probably should be doing that… but it was not a high priority…so many other issues I’ve needed to focus on ;-(
I really need a board that includes WiFi, I2C, and (ideally) LiPo support
My project is critically dependant on the Piicodev VL53L1X and Piicodev Transceiver also. Other aspects could be converted over to say Arduino Nano… but that has no I2C, AFAIK.
I’m in the final stages of what has turned into a fairly significant project… will likely persist with Pico for now, maybe review the platform once I get this in operation.
Hi Trevor
You say you are still getting a slight error with the lower resistor values. The input resistance even as low as 100k should not influence 5k much. i just had a thought, I don’t suppose there might be a pull down resistor connected to this pin somewhere would there. That might have been done to make sure that the ADC red 0V with nothing connected. Just a chance that this has inadvertently happened. Check with a multimeter with power ova and nothing connected see if you can measure a resistance to ground from the ADC pin. I am not familiar with RPi but this could also been in software with some sort of “PullDown” set up.
With a 100k ADC input resistance and 3V to divider input the error between ADC connected and not connected would be 30mV. Is that what you are seeing?
Cheers Bob
Add on:
That would be true if you were inputting a “raw” DC voltage with a low source resistance. But when you are going via a voltage divider the game changes somewhat as you are finding out.
I haven’t tried measuring the ADC pin to ground resistance directly. I figure, it is what it is, Don’t think I can change it. I did do some voltage drop measurements, and by my calcs, it looks like connecting the ADC pin to my voltage divided input presents about 16.6K in parallel with the existing 5K bottom half of the divider.
I am content to just leave it like this… as I have bigger fish to fry… like, running out of memory on the Pico, which brought my development to a complete halt for a couple days.
Have ordered a couple of Pico 2’s, which should help a lot. I have over 2,000 lines of code… plus some related modules that I have created for implementing a multi-level menu system. I hit a hard fail (memory shortfall) on trying to open an SMTP connection, due to fragmentation, but this is getting off-topic. Maybe I’ll post something later in a different thread if/when I confirm the Pico 2 resolves it. It has been “instructive” delving into microPython’s memory management internals…
Regarding Jim’s comment re the advantages of the ATmega… I might consider swapping platforms… but would need an Arduino that runs microPython. Spent way too many hours building my code to ditch it and start over in C… not to mention the lack of (?) drivers for the Piicodev VL53L1X and Piicodev Transceiver … WiFi and inbuilt LiPo charger on the PicoDev board. All things considered, I reckon my best path forward is to stick with Pico, but always happy to receive advice from those with more experience!
H Trevor
The main reason for checking the ADC pin to ground is to check there is no phantom “pull down”" resistor or something which should not be there. I don’t think you will be able to measure anything if there is no phantom resistor. The input resistance should be too high for any DMM. If you somehow have a software “pull down” it will not show up with a resistance measurement.
You haven’t said what the exact discrepancy is so it is pretty hard to check if your estimate of 16k6 is correct or not. That is pretty low and if correct is very suspicious in itself. That is suggesting something seriously wrong if the ADC input resistance is that low.
Cheers Bob
OK… next time I have the LiPo disconnected I’ll check it. Its actually a bit difficult to get to…
As for my calculation… I’ll summarise.
With the ADC connected, I have a voltage divider consisting of a 2K resistor on top of a 5K resistor… which is then effectively in parallel with the ADC/GND impedence, call that Rx, as in this:
o '<------ Vin = 2.74V
|
R1 = 2K
|
o------------------o Vout = 1.8V (to ADC pin on Pico W)
| |
R2 = 5K Rx
| |
'==================== ADC Ground (and ref for all voltage measurements)
The ratio of in to out voltages measured is 0.6577 ( Vout / Vin = 1.8 / 2.74)
Solving for the total (parallel) resistance Rp of the R2:Rx pair, I get 3842 ohms. This is:
Rp = (2000 * 0.6577) / (1 - 0.6577) = 3842 ohms
So now focussing on the 2 R’s in parallel, one is known… 5K… we have
Sorry for labouring over basic DC theory, but I wanted to be sure I was not screwing up somehow. Writing it out forced me to check my math
And that (I hope) confirms my claim that the ADC-GND impedance is about 16.6K.
The Pico reference docs make no mention I can see of applying a soft pulldown, like you can on the other GPIO Pins… but the bottom line is (unless I find a spurious phantom resistance), this works well enough. I have calibrated my pressure sensor, checked against an analog guage on the same pipe… it is giving accurate enough readings for my purposes. So… I’m pressing ahead with other aspects of the project!
Hi Trevor
Thanks for that. Doing this a bit differently I come up with 16.37k which allowing for a bit of rounding is very close.
After all of this it still turns out to be a ridiculously low figure for an ADC input. That is an enormous error, almost 50%. Wrong!!! see Edit below.
Another way to find out would be to use the actual ADC numbers. Record the number without R2 connected and with R2 connected and work with this. That will remove any funnies with DMM measurement. Should be able to calculate the relationship between Vin and Vout without any other influence. Absolute accuracy will be determined by the ADC resolution but should be adequate for the exercise.
Cheers Bob
Edit: Must have had a brain snap. Please revise that error of 50% down to 7%. Not so enormous but still pretty wild.
Pulled my Pico to pieces, as I just received Pico 2 W. Woohooo… solves my ENOMEM issue !
With NOTHING connected I see about 4M between the ADC pin and AGND. So, I now ask myself… that being the case, why did my original divider, having 12K over 33K, behave as it did?
Other connections to my Pico include: , Piicodev Transceiver and VL53L1X on I2C bus via 4-pin thingy… an LCD1602 connected directly to pins 8 & 9 (SDA/SCL)… and a rotary encoder via some GPIO pins… and a couple pushbutton switches to other GPIOs. Plus the LiPo connected via the PiicoDev LiPo Expanson board.
Maybe I’ll do some more tests, disconnecting these other bits, to see if they are having an impact. That said… not sure what I will do if I find the culprit… I really need all of these devices for my project to work!
Oh… my bench test results have been done applying a fixed voltage from an independant power supply… one of those little guys that sit on a breadboard. I am assuming it can provide adequate current. What I am saying is, the ability of my pressure sensor to source current is NOT an issue, on the bench, anyway. I put the 3.3V rail through a pot to generate variable vinput voltages into my divider. Not sure if that changes anything, but that is the full monty picture of my bench setup!
Hi Trevor
Firstly I apologise about the massive GOOF I pulled in the last post.
It certainly does. That is one divider in series with another divider.
This effectively changes the source resistance. The top half of the pot is now in series with the 2K upper resistor in your original divider. And the bottom part of the pot is in parallel with the 2k and 5K. To figure out what this is actually doing you would have to draw it out and sit contemplating for a while to sort out what is happening.
That is a bit more like it. My Arduino UNO varies all over the place between 4MΩ and 7MΩ unpowered.
Good question. But that 45K was a bit high in the first place. The 2k/5k combination should have had negligible error.
Let’s have a few confirmations here. This Pico that reads 4MΩ is the same one as the original is it not. Or is it the new one. The Pico should be unpowered to measure this. If powered little bits of volts floating around will play merry hell with a resistance measurement.
Secondly when did you introduce the intermediate potentiometer. Until you get this sorted you should use a fixed or variable supply with a low source resistance.
By the way that passive resistance check was just to make sure there was not anything funny connected like a resistor and on board LED or something like that. The actual input resistance can do anything when powered as it depends on the actual input circuit. If dealing with high value resistors the 10MΩ of your DMM will affect actual voltages but this should have almost no affect on 5k. The real input resistance should be measured while powered. There is a way of doing this but can be a bit messy and you would need some high value resistors.
Cheers Bob
I have the original Pico W now sitting on my bench, not connnected to ANYTHING, and it reads 4Meg… as did the new Pico 2 W.
Thanks Michael… I’ll try adding a capacitor as suggested in that article. I will only be sampling like 1Hz…maybe 2Hz if I get ambitious!
Bob… I will draw out a full circuit including my PS divider… see if I can follow your point. I did contemplate connecting the 3.3V (currently powering my LCD1602) supply pin on the Pico to my divider input, but that sounded more risky than the approach I took… so I didn’t In theory, I should then see a little over 2V on the ADC. Any comments on the advisability of that?
Turns out I seem to have another problem with the Pico 2… lots of memory, but my rotary encoder “rotary” bit no longer works… the push button interupt does. But I digress… will follow this up if required in a new thread. Why is there “always something…” ??