ADC resolution
jaspast
Posts: 12
In this quick byte (https://www.parallax.com/simple-analog-input/) @"Ken Gracey" described how to use a smart pin as an ADC--described as a 14-bit ADC.
However, I only get 8-bit resolution out of the same setup: counts range from 600~900 for a voltage of 0-3.3 V. (It will display values as low as 200, but only when the voltage is changing.)
How can I get more resolution out of a smart pin ADC? I'm teaching quantization, so it's important for a 14-bit sensor to register as 4096 (edit) 16384 counts.
Comments
Floating at over 8000 reading for me. Try a different pin on another header. It's a little too easy to short the 5 volts and blow up pins.
I think you need to use the SINC2 filtering mode to get 14 bits.
Ken's code appears to be SINC2 sampling mode...
I'm trying to remember how to do it... Maybe change
pinstart(_pin, p_adc_1x | p_adc, 13, 0) 'init ADC pin
to
pinstart(_pin, p_adc_1x | p_adc, %1_1111, 0) 'init ADC pin
The value of 13 sets the mode correctly, and provides a full numerical range of 16385 (0 .. 16384).
The SInc2 "filtering" mode with 13 (%01_1101) would produce the max 27 bits and need trimmed down. Err: Maybe it would roll over badly when near 3.3 volts since it is really producing 28 bits I think. The hardware accumulators are limited to 27 bits. That might be a problem with 13 in Sinc2 "sampling" mode too ...
Ok, think it should be %1_1101 after looking at docs, for SINC2 filtering mode...
But that doesn't change the range, I don't think... just the accuracy...
BTW: Somebody messed up the font in the silicon hardware docs.
Hope they can fix it:
https://docs.google.com/document/d/1gn6oaT5Ib7CytvlZHacmrSbVBJsD9t_-kmvjd7nUR6o/edit#heading=h.3aif7i997trh
Huh, I guess that figures. After some testing ... The filter mode diff'ing never exceeds 16384. Man, that means trimming down to 27 bits is superior to scaling up to 32 bits since trimming can't roll over. So I now have to fix my own decimation programs.
Doh! Compiling the wrong program ....
EDIT: Okay, interesting. Chip has done something odd with the X parameter for the "filtering" modes. Its mode of operation is not the same as when specifying a Y parameter. With a Y parameter, readings behaviour is like "sampling" mode but at greater resolution and obviously needs diff'ing to convert the decimations into samples..
When Y = 0 however, eg:
pinstart(_pin, p_adc_1x | p_adc, %1_1100, 0)
, things get weird. It looks like there is a signed offset or something. And there is the discovered, by Vons I think, a roll-over problem as well. Whereas none of that happens when specifying a Y value.EDIT2: Uh-no, Vons discovered there is another roll-over when trying to use full range of all 27 bits via Sinc3 with decimation period of 512 clocks. The fix for that case is to use Y = 511 instead.
I tried again on a different header, and now I get 3000~7700. That's certainly more reasonable. Thanks!
It should be double that still. 8192 is the ideal centre reading at 1.65 Volts.
Using Ken's code I get range 2_300 to 13_300 from gnd to +3.3 and 7_800 when floating
@jaspast Maybe you didn't connect to 3.3?
Your range looks close to what I get from GND to floating...
There's this thread that discussed the modes:
https://forums.parallax.com/discussion/173364/p2-adc-timing/p1
Also, there's a Prop Tool example called jm_ez_analog_demo.spin2 that makes calibrated ADC measurements.
(you might need to change "field" to "fieldX" or something in jm_serial.spin2 for it to compile.
The filtered mode is a bit more complicated...
There's an assembly example in the P2 "Hardware Manual" though.
Just make sure the Y (WYPIN) parameter is used in the "filter" modes.
Just remembered that I made a C adc driver for all the modes for the P2C code generator project...
Not finding a Spin2 example that does filtering...
Tried to make one from the assembly example, but doesn't work with inline assembly for some reason...
The P2's ADC is unusual in that its range extends above VDD and below VSS, theoretically about -0.85v to 4.15v (though body diodes prevent getting the whole way). So if you need 16384 discrete levels in the 0 to 3v3 range, you need to aim for 24824 count buckets
This causes confusion and results in issues like described in the comments on the quick byte
I think these basics need to be described on that same page and/or in the example code comments
I was connecting to the extra pin on the header- I thought that was 3.3, but I now realize I should have put a multimeter on it.
I did a modified version of Simple_ADC.spin2 from this Quick Bytes for Chip to examine - https://forums.parallax.com/discussion/comment/1551209/#Comment_1551209
It's using an extra cog to deal with the needed decimation timing. So not really a worthwhile real use case since better to do that in pasm and allow it to cover greater configurable decimation rates.
EDIT: Doh! I hadn't tested that code in Pnut and had a syntax bug. Sorted now.
Using the 3x gain on the analogue frontend is a way to test out the full numerical scale behaviour. I used that today to verify there is no roll-over effect as long as full range fits within 27 bits.