the A/D rabbit hole #13598
Replies: 3 comments 3 replies
-
The ADC of the RP2040 has some limitations. If you look at the rp2040 data sheet there is a section about it's errors. Folliwing that, the effective resolution of the ADC is 8-9 bit, meaning that you can discard the lower 8 bits of a read_u16() result. There is another hidden property in the RP2's implementation of machine.ADC(). If you use the raw channel numer 0-4 of the Pin number 26-29 as argument, the pin will not be initialized. That has to be done by the user code. When using a Pin object like Pin(28) or a Pin name like "GP28" as argument, the pin will be initialized to high impedance. When not initialized after reset, Pin's of the RP2040 seem connected to an internal current sink of 50-60µA, with that current having a large temperature drift. Since you use ADC(28) in your code, you will have that problem. So either use ADC(Pin(28)) or set Pin 28 to input mode before calling ADC(28). |
Beta Was this translation helpful? Give feedback.
-
Tnx for heads up on the ADC Rob, but after reading #10947
I'm confused, Damien seems to say that ADC(28) and ADC(Pin(28)) are equivalent. You're sure that's not the case? Also re your comment on ADC conversion time. I noticed if I reduced sleep from 2ms to 0 in the ADC loop the readings steadily increased during the run instead of being more or less random. Wondering if you have any insight on why that might be? |
Beta Was this translation helpful? Give feedback.
-
That may have been the intention, but the code is different, and it works different. I just made again a test with a RPI Pico, 1.23.0 preview and a DC source of 1.65 V, connected through a 47k resistor to Pin 28. The expected reading for read_u16() should be in the range of 32000. Using ADC(28), read_u16() returns 10946, using ADC(Pin(28)), read_16() returns 31783. Once the Pin has been switched e.g. to Input mode, the reading with ADC(28) is fine too.
The internal resistance of an non-initialized Pin is highly temperature dependent and and increases with the temperature. So the reading do. That will go away if you use ADC(Pin(28)). About the difference between ADC(28) and ADC(Pin(28)): I made a PR #13509 to close this gap and to document the behavior using raw channels numbers. Maybe it will be merged sometime. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
When I read this I was not surprised to see him do what we all do when confronted with piss poor hardware, over sample & hope for the best. It's a great technique, I ran his Pico program 10 times and got readings that ranged from 10883.1 1818.504 to 10765.28 1133.918 a spread of (10883-10765)/10824=1% which is OK considering the massive standard deviations (the second number) in the raw readings. But 100 readings at 50ms intervals takes 5s and that's a long time to wait for a battery voltage. I wondered if optimising the number of readings & their spacing might give a better result in less time.
What followed was a 2 day odyssey full of counter intuitive results, take more readings more widely spaced & get a worse spread. You can go a bit crazy staring at 10x10 arrays of numbers, imagining patterns that aren't really there. But I'm pretty sure there is some aliasing between noise & sampling frequency that made 2ms the sweet spot for the sampling interval. I have no explanation for why 39 is a good number of samples but try changing n to the 38 or 40 in the program below & presumably you'll see what I saw, a spread increase.
Herewith my testing program
and a sample set of results
Which is either less spread in less time or I've goofed off somewhere. Curious to see if this is reproducible on another Pico if someone has the time & the inclination to try it out. If the results are legit & you want to use the mean/median technique in your own program, just use the core of the testing program.
Beta Was this translation helpful? Give feedback.
All reactions