Interesting.
I don't think I've ever seen this anomaly before.
It's often convenient to think of a SAR ADC as if it samples the input analog voltage at some instant in time.
In practice, there is a narrow window of time where changes in the input analog voltage --
or noise on the analog voltage reference, or noise on the GND or other power pins of the ADC --
can affect the output digital value.
If the input voltage is slowly rising during that window, then the less-significant bits of the SAR output will be all-ones.
If the input voltage is slowly falling during that window, then the less-significant bits of the SAR output will be all-zeros.
A very narrow noise pulse at the "wrong" time during conversion can have a similar effect.
Right now my best guess is that you're using some sort of analog switches or op amps that don't work quite as well (higher resistance or something) near the high and low power rails as they do near mid-scale, somehow letting in one of the above kinds of noise, which causes the less-significant bits to be all-ones or all-zeros.
I've seen some sigma-delta ADCs and sigma-delta DACs that have good resolution at mid-scale, but worse resolution near the rails -- but the effect looks different than what you show.
The "plot of the difference between one sample and the next sample over the entire full scale range" is fascinating.
If I were you, I would make a similar plot that, instead making the X value the difference between one sample and the next, make the X value the least-significant 6 bits of the raw ADC output sample.
That would quickly show if the "stuck" values are mostly lots of 1s in the least-significant bits (maybe input is slowly rising?) or lots of 0s in the least-significant bits (maybe input is slowly falling?).
I am sampling "pulsed" DC voltages. That means that for each
measurement I put a voltage on the DAC, let it settle for at least 100
times it's settle time, then tell the ADC to convert - and when
conversion is finished, I put the DAC back to 0 V.
My understanding is that when ADC manufacturers say "no missing codes",
the test they use involves several capacitors adding up to a huge capacitance directly connected to the ADC input,
and some system driving a large resistor connected to that capacitance that very slowly charged or discharged that capacitor,
slowly enough that the ADC is expected to see exactly "the same" voltage (within 1/2 LSB) for several conversion cycles before it sees "the next" voltage (incremented by 1 going up, decremented by 1 going down).
If I were you, I would see if such a "continuous slope" test gives the same weird "stuck code" symptoms as the "pulsed test".
Perhaps that would give more clues as to exactly what component(s) are causing this problem.
Please tell us if you ever figure out what caused these symptoms.
Your signal chain is quite complex, and you can have problems at every step, or even multiple problems. You have analog circuitry, into external ADC, through a PIC, into SRAM, back through the PIC, at some point employing a highly nonlinear filter, out through UART and into hyperterminal. Debugging this involves baby steps, which pretty much means you need to eliminate all the shortcuts you took getting to this point.
Where I would start would be to verify everything one step at a time. Start by sampling a CONSTANT voltage, then a sine wave out of a function generator, and make sure you understand what you see.
Once that makes sense to you, LOOK at your analog input with an oscilloscope, and make sure you understand what you see with that. There is no substitute for this. There are reasons why we use bench instrumentation, and this is one of them.
Next, find a way to get rid of all your post-sampling processing, and look at the data in as raw a state as you can. You are doing highly nonlinear processing. When you do this sort of stuff, when it doesn't work you go back and look at the whole process with a microscope.
I suspect you might have an extremely noisy signal, you're aliasing it down by not sampling fast enough, and the non-linear processing is confusing the issue.
Best Answer
Here is an analysis, using HFI, EFI, PSI and GPI interferers. These are Magnetic field, inducing deterministic trash into the loop of Signal Trace above Plane; Electric field inducing displacement currents into impedance of circuit nodes; Power supply ripple/switching noise/LC ringing where the circuit / ADC PSRR is inadequate; Ground noise, where ground_impedance * ground_currents are computed. The total of these 4 interferers is 14 milliVolts.
I configured the tool --- Signal Chain Explorer --- for 20 volts PP into the ADC; edited the Master Sampling Specs for 18 bits and 10KHz sample rate; the ADC internal sample-hold is 50 ohms and 48 pF default values. Many of these specs can be edited.
Resultant SNR with NO interferers is 109 dB.
Resultant SNR with interferers (I added additional interferers from the Gargoyle tables, to be realistic in a Arduino system), is only 54 dB.
Conclusion: blindly building such a system will produce a 9 bit measurement with 9 extra bits of deterministic noise.
Here, below, are results of injecting the 4 types of interferers, with the system frequency response used to model the deterministic trash upset to the Code Spread (the noise floor, or the SNR). Note the Magnetic Field of the way-too-close MCU clock is the biggest problem.
Here is the HFI (magnetic field) table; the 10MHz Switch Reg is default active; you can turn it off. You can edit any of the parameters, including Distance, to explore how close or how far away some field generators may be placed yet still achieve your SNR goals.
Here is the EFI (electric field) table;
What can you do, to greatly reduce the deterministic noise floor from the 4 types of interferers? (Note the thermal noise floor, with KT sources only being the sensor 50 ohms and the ADC 50 ohms ---- both editable ---- only contribute 9 microVolts RMS in the system bandwidth; if you want 20 bits, you'll need to reduce this 9uV; but first lets improve on the existing 14 milliVolts of deterministic trash.
The primary issue is the too-close location of switching power supplies and of the MicroController CLock/IO lines.
The switching power is only 10 milliMeters away, with an assumed Switching Frequency and dI/dT. Move that away, and shield it.
How accurate is the HFI number? We use a loop area, defined by trace length and trace height-above-gnd (both editable); we state the Distance from Wire-to-Loop; we state the dI/dT in the wire; we assume worst-case (maximum induced voltage).
The MCU clock/IO line is 1 millimeter away from the ADC input trace; who would be so cramped for PCB area they would route a high-slew-rate clock/data trace only 1mm from a 18bit (or 24 bit) analog trace?
How accurate is the EFI number? We assume parallel-plate coupling in the absence of any other mechanical geometry. We know the slew-rate, and the embedded simulator of Signal Chain Explore computes the node impedance.