SAR ADC
Today I tried something I've wanted to do for a long time: Use the built-in comparator for an ADC according to the SAR principle.
The level comparator has its own DAC which seems to be quite accurate and monotonic. If you control the DAC in a suitable way, you can get an 8 bit analog value in 8 steps. The Wikipedia article describes this in detail with pictures and animations:
https://en.wikipedia.org/wiki/Successive-approximation_ADC
^ VIO .---[Poti]---' | ^ = | P_LEVEL_A pin mode: | ___ [P]in / | | .-----< DAC|--- D7..D0 | | \___| ------- \ + - / \ / Comparator \ / | '------> IN
What the P2 lacks is an S&H at the input, so you are limited to slow signals. But for potentiometers for example this is no problem.
The result was much better than I expected, so I wanted to present it here. The code is extremely compact, and needs neither smartpins nor initialization and especially no calibration, like the Sigma-Delta ADC.
First I tried a spin program, that took about 33 us for one conversion. After that I optimized it with inline PASM, so now one conversion needs only about 10 us.
Attached is an object that can be used with the following test program:
CON _clkfreq = 180_000_000 OBJ adc : "as_sar_adc" PUB main() | val repeat val := adc.analogRead(10) ' Poti at pin 10 debug(sdec(val)) waitms(750)
Andy
Comments
Very nice, Andy! You could try making a simple S&H with a back-to-back pMOSFET pair and a cap.
-Phil
Handy for reading midi controller pots, that mostly only need 7 or 8 bits anyway.
I could imagine it could easily be extended to read multiple control potentiometers in some defined pin group using a couple of mask longs for identifying the port A and B pins to read (using encod and bitl to iterate through) and then automatically fill an array in HUB RAM with a short write burst at the end of all these conversions etc (if there is sufficient scratch space in COG/LUT for the inline pasm). That could help reduce the total conversion time over all the pots in a group, and get a bunch of readings loaded in one single call to an API. Alternatively you might make use of the settling time interval to do useful conversion work on other pins (currently waitx just burns those clocks).
Nice educational exercise for sure. Tidy example and lets students practise the theory.
Not sure I could find a real use over the dedicated sigma-delta hardware though. Chop that down to 8 bits and it'll be stable too.
Thank you all for the feedback.
Other applications may be: Supplyvoltage monitor, Overtemperature measurement. Anything that needs not much resolution and changes slow.
The sigma-delta needs recalibration from time to time, this makes it more complicated to use.
Phil:
I tried a Sample and Hold with a CD4066 analog switch, but it distorted the measurement, and it needs an additional pin to control the switch. But maybe a CD4051 would be a good idea, so you can have 7 channels with 4 pins and get the S&H for free.
Rogloh:
Yes, reading a lot of Potis for a Synth or MIDI controller was also my application idea. There is certainly room for improvement of the timing for many channels.
Not at 8 bits it doesn't.
Really neat, Ariba. Congratulations
If you use a pair of pins in A>B comparator mode, where the A pin is the analog input and the B pin is a fast DAC output using 16-bit oversampling (which would analog-average in the relatively slow comparator), you could maybe do fast successive approximation conversions without routine recalibration.
If you were measuring a slow signal, like a potentiometer, you could do simple up/down tracking on the DAC side.
That is exactly what I tried yesterday. It's good for a 11..12 bits resolution SAR ADC. If you go higher, the lower bits are very noisy. I found the settling time is about the same as with the slow DAC, so eighter the Comparator is the limiting factor, or it's the dithering of the DAC.
The biggest drawback is that you need two pins for one ADC.
Edit: And with this configuration you can't go down to zero, the comparator seems not to work near zero, while it does in the Level_A mode.
I also tried to get more resolution from the Level DAC with software dithering. But that seems not to work. I could get a 9th bit if I slowely ramp it up and down by 1 LSB, and read the comparator at the right time. But it's not really reliable.
Andy
Now what if we make a noise shaping filter using opamps? The comparator can also be external. 2 DACs needed, one for SAR, the second for a noise shaper.... I have to rethink the schematic of such a contraption...
How close to zero ? There may be offset voltage effects, but they should be 10mV ballparks ?
I wonder if a filter-cap on the DAC-dither pin would help average the DAC to finer levels and so give more bits ?
The internal DAC is an R-2R circuit that has big spikes between some steps, the biggest spikes going between $7F and $80 output values. The fast DACs have almost no stepping spikes, and therefore might disrupt the comparator less.
Yes, its about 6 mV, no wonder that I don't see it with the 8 bit version. So it's just the higher resolution that shows this little offset, not the different wiring of the comparator. If I do an 8 bit version with the fast DAC, it goes also to zero.
Now I don't understand - what is "the internal DAC" and what is "the fast DAC"?
The comparator has its own dedicated DAC. That'll be the "internal" one. So Chip is highlighting that because it is constructed as R-2R it therefore is a little glitchy when set value is changed.
Which makes the "Fast DAC" the well known main output DAC.
Huh, the silicon doc has changed its naming of the fields in the WRPIN mode word. When did that happen? P field has changed to M and M field has changed to S.
PS: I approve, btw. Eliminated the dual naming and potential confusion with P for Pin. Just I've been talking about these not long ago and no-one mentioned anything then.