Measuring Small Voltages With Pi Pico ADC and Comparison With Microchip MCP3208 Using Cytron EDU PICO

by kevinjwalters in Circuits > Microcontrollers

303 Views, 1 Favorites, 0 Comments

Measuring Small Voltages With Pi Pico ADC and Comparison With Microchip MCP3208 Using Cytron EDU PICO

edupico-picow-vs-mcp3208-setup-5mv-65.JPG
stable-diffusion-ai-5-crop.jpg

This article takes a look at accurately measuring voltages below 50 millivolts using the RP2040 analogue-to-digital converter (ADC) on the Raspberry Pi Pico W and comparing that with an external Microchip Technology MCP3208-B ADC. A CircuitPython program was used to record multiple ADC samples of the voltage from a battery with some potential dividers on a breadboard. The voltage was manually set based on measurements from an (uncalibrated) Zoyi ZT703-S multimeter. A Cytron EDU PICO was used as it conveniently has a display and user buttons.

The Pi Pico boards provide a 3.3V reference voltage to the ADC in the RP2040 microcontroller allowing it to measure voltages between 0 and 3.3V. The same reference voltage was supplied to the external MCP3208 for an equivalent comparison. The testing was repeated with an inexpensive Texas Instruments LM385-1.2 voltage reference which can easily be introduced into the circuit to lower the reference voltage for both ADCs to 1.235V. The 1.235V voltage reference empirically works for one sample Pi Pico W/RP2040 but it is too low for the RP2040 microcontroller on the Pi Pico and Pi Pico W - reference voltages below 2.0V should not be used.

The 12bit resolution of both ADCs offers 4096 values which equates to voltage steps of 806uV and 302uV for voltage references (Vref) of 3.3V and 1.235V, respectively. An ideal ADC would return a single, repeatable value that matches the quantised input when measuring a constant voltage. This article graphically shows the error, the difference in the ADC value from the actual value and compares some software approaches for improving the accuracy of the RP2040 ADC samples.

This investigation overlaps a little with Instructables: Exploring and Reducing ADC Noise on Adafruit CLUE (Nordic NRF52840) which was a follow-up to analysis in Adafruit Learn: CLUE Metal Detector in CircuitPython: ADC Analysis. Mark Omo's in-depth look at the RP2040 ADC on the Pi Pico in Characterizing the Raspberry Pi Pico ADC is well worth reading too.

The EDU PICO board was for this article is a sample that Cytron kindly sent to me to evaluate.

The image accompanying the photograph is the handiwork of Stable Diffusion with the prompt: "A group of lego minifigures who look like academics with an rp2040 microcontroller pondering how to perform a methodical analysis of the low voltage capabilities in particular random and power supply related noise. One in the background looks on fretting about the resources wasted on frivolous use of so-called AI."

Supplies

  1. A Pi Pico or Pi Pico W.
  2. A breadboard, full-size or half-size for use with EDU PICO.
  3. Two potentiometers, one 10k and one between 1k or 100 ohms, the lower the better - 630ohm was used.
  4. A resistor between 100-560 ohms - 220 was used.
  5. Two low value resistors for a potential divider, 20 and 1 are ideal but higher values with similar ratio could be used.
  6. A 1.2V or 1.5V battery and battery holder - AA NiMH are great because they have a fairly constant voltage as they discharge.
  7. A push-to-make button or a Cytron EDU PICO which has a button and a display.
  8. An MCP3208 or MCP3204.
  9. An optional 16 way DIP socket.
  10. Two 0.1uF capacitors.
  11. Male-to-male jumper wires for breadboard connections.
  12. A multimeter with clip leads or extra crocodile (alligator) clip leads.

Increased Resolution for Small Voltages

adc-rp2040-mcp3208-lowvolt-v8-g10-ii.png

An ideal 12bit ADC changes value every 0.80586mV for a 3.3V reference voltage. For the range 0-5mV there are only 6 ADC values shown by the green line on the chart above. A small offset error or noise can limit the ability of an ADC to measure these tiny voltages.

Amplification

One common solution to this is to amplify the signal with an op-amp. Some ADCs feature a programmable gain amplifier (PGA) stage, e.g. the TI ADS1015 and ATtiny3226 microcontroller. A few have a general purpose op-amp and an external one can always be added. A 50x gain op-amp based amplifier takes a signal between 0-5mV to 0-250mV increasing the upper ADC value from 6 to 310 providing much finer resolution. An op-amp could also be used to accommodate ADC offset errors.

For a microcontroller without a PGA for the ADC, this involves extra circuitry per channel and careful selection of an appropriate op-amp which may involve its rail-to-rail characteristics.

Alternative Voltage Reference

The voltage reference (Vref) for the ADC can also be lowered to provide increased resolution. An ideal ADC would allow a voltage reference of 66mV to provide 50x gain but

  1. ADC performance can reduce with a lower Vref;
  2. few appear to be designed to work well with a Vref below about 1V;
  3. typically all inputs to the ADC must be below or equal to the voltage reference.

This means a 66mV reference voltage is extremely unviable.

The Pi Pico (W) has some further limitations.

  1. Its RP2040 microcontroller only has one pin, ADC_AVDD, to provide both the power to the ADC and the reference voltage which adds a further limitation.
  2. The Pico board measures its input voltage (up to 5.5V minus a schottky diode drop) with a 1/3 potential divider to the RP2040's GP29 pin. This means there's a lower limit of 1.85V for Vref.

The Pi Pico (W) datasheet states:

Note that the ADC on RP2040 has only been qualified at 3.0/3.3V, but should work down to about 2V.

The RP2040 datasheet states:

ADC_AVDD supplies the chip’s Analogue to Digital Converter (ADC). It can be powered at a nominal voltage between 1.8V and 3.3V, but the performance of the ADC will be compromised at voltages below 2.97V.


LM385-1.2

The Texas Instruments LM385-1.2 voltage reference which provides a low current 1.235V output was selected for this testing. It appears attractive as an easy way to achieve an effective gain of 2.67x increasing the ADC value from 6 to 16-17 for 5mV. This component was selected before the Pico/RP2040 limitations were fully understood. It appears to work from the tests but this does not mean this value should be used as the datasheets cited above have 2.0V as the combined lower limit for the Pico's RP2040 ADC voltage reference.

Most of the charts/plots in this article have the 1.235V value rounded to 1.24V.

The Microchip MCP3208

mcp3208-socketed-on-breadboard-65.jpg
mcp3208-dip-pinout.png

The Microchip MCP3xxx series is commonly used by hobbyists as

  1. it's available in Dual Inline Package (DIP) making it suitable for breadboards, perfboard and stripboard;
  2. the supply voltage range of 2.7V to 5.5V allows it to be used with both 3.3V and 5V microcontrollers and single-board computers like the Raspberry Pi;
  3. the SPI interface is common, fast and easy to connect;
  4. there are plenty of software libraries for it.

The MCP3208 is the 12bit 8 channel version. There are many other variants like the 13-bit 4-channel MCP3304 and the 10-bit 2 channel MCP3002. There are two grades of chip, B and C, the B is slightly more accurate - it has lower maximum Integral Non-Linearity (INL). The MCP3208-B was used for the testing in this article.

The datasheet states the input must be between 0V (Vss) and the reference voltage.

Measuring 0mV-33mV With an ADC

Comparing RP2040 ADC with Microchip MCP3208 for low voltages using Pi Pico W on Cytron EDU PICO

A real ADC differs from an ideal one due to

  1. noise;
  2. offset and gain errors;
  3. non-linearity which could include implementation errors and component tolerances/trimming;
  4. stability and magnitude of the voltage reference;
  5. input impedance/capacitance;
  6. cross channel effects;
  7. bandwidth (for varying signals).

The noise tends to be higher for ADCs that are part of a microcontroller compared to external ones.

For an example of serious offset errors, the Espressif ESP-32's notorious ADC only responds to voltages above approximately 150mV. The RP2040 assigns a value around 16 for 0mV meaning it can still measure the full range and a simple correction can adjust well for this small offset.

The RP2040 has a well publicised minor ADC flaw (Errata RP2040-E11 in datasheet) but the effect is actually rather minimal especially for measuring low voltage below, say, 100mV.

The RP2040 ADC has a DNL that is mostly flat, and below 1 LSB. However at four values — 512, 1,536, 2,560, and 3,584 — the ADC’s DNL error peaks above this value. The ENOB for the ADC has been reduced from 9-bits (simulated) to 8.7-bits (measured), see Section 4.9.3. The DNL errors will somewhat limit the performance of the ADC dependent on use case.

Low Voltage Testing

The following values are some samples from the video above of an EDU PICO being used for an initial comparison of the external Microchip MCP3208 ADC (left side of small white OLED display) with the RP2040's internal ADC (right side). Both are 12bit successive approximation ADCs (SAADC) with a feature for an external voltage reference. A relatively low-noise power bank was used for the USB power source.

The input voltage is provided by a used alkaline AAA battery (1.358V) going through a 470k and 2.2M resistor pair in parallel to a 10k linear potentiometer. The voltage is across a 0.1uF capacitor. For low sample rates the capacitor can counteract the high impedance of this source. The setup was largely determined by components conveniently nearby. It would be better to use a larger battery with less voltage drop during discharge with something like a 1 and 33 ohm potential divider and a 100ohm potentiometer. A soldered circuit would also be a good idea as the connectivity on a (cheap) breadboard won't be great.

The Pi Pico (W) boards have a buck-boost converter for the 3.3V supply. This potentially noisy voltage rail is also used as the ADC reference with a simple RC filter to smooth it. The datasheet recommends the use of a voltage reference like the LM4040 for better stability. A 1.235V LM385-1.2 was used for one of the tests shown here.

The RP2040 ADC is much noisier particularly with the lowered voltage reference. The values are just occasional samples and therefore aren't representative of the mean value over time. The RP2040 values shown below have been corrected by -48 and -16.

Surprisingly, the MCP3208 doesn't perform well below 2-3mV with a lowered reference voltage.

Texas Instruments LM385-1.2 Vref=1.24V

This voltage reference is too low for the RP2040 on the Pi Pico (W).

  1. 0mV ideal=0 MCP=0 RP2040=6
  2. 2mV ideal=7 MCP=0 RP2040=14
  3. 4mV ideal=13 MCP=6 RP2040=17
  4. 8mV ideal=26 MCP=19 RP2040=30
  5. 30mV ideal=99 MCP=94 RP2040=100

Default Vref=3.3V

  1. 0mV ideal=0 MCP=0 RP2040=0
  2. 2mV ideal=2 MCP=1 RP2040=1
  3. 4mV ideal=5 MCP=4 RP2040=4
  4. 8mV ideal=9 MCP= RP2040=9
  5. 30mV ideal=37 MCP=36 RP2040=36
This particular circuit doesn't present any issues but a battery connected to a GPIO pin should be disconnected when the microcontroller isn't turned on to remove the risk of back-powering.

MCP3208 Voltage Reference Detail From Datasheet

mcp3208-ds-offseterror-vs-vref.png
mcp3208-ds-dnl-vs-vref.png
mcp3208-ds-dnl-vs-vref-2.7.png
mcp3208-ds-enob-vs-vref.png
mcp3208-ds-gainerror-vs-vref.png

Microchip provide a detailed datasheet for the MCP3204/3208. This is helpful to explain the relatively poor performance below 2-3mV when the voltage reference is 1.235V. The Electrical Specifications section states the voltage reference (Vref) can range between 0.25V and the supply voltage (Vdd) and it recommends checking the graphs for linearity with respect to Vref.

The charts above which relate to performance variations by Vref are for a 5V supply and reference voltage, a 100ksps sample rate, a 2MHz clock rate at 25 degrees celsius ambient temperature unless otherwise noted.

The first chart for Offset Error (LSB) confirms the behaviour below 2-3mV is normal for this ADC. The others also show deterioration below around 1V and more dramatically below around 0.6V.

Improved Potential Divider

battery-potdivfinetune-fcs-2.png
edupico-picow-vs-mcp3208-setup-breadboard-65.jpg

This is an improved version of the potential divider circuit based on some further rummaging for spare components. The first potential divider is formed from a 20ohm and 1ohm resistor. The 10k potentiometer is now used with a 220 ohm resistor across the 1ohm resistor to offer fine tuning. A 630 ohm potentiometer provides the coarse control over the final output voltage. A lower value potentiometer would still be preferable for the output to provide a low impedance source for the ADCs to measure.

The battery has been upgraded to a fully-charged NiMH AA battery which measured 1.350V unloaded.

This circuit will flatten a battery if it is left connected in a day or two. This can damage rechargeable batteries. In general, it is also advisable to disconnect the battery if the microcontroller is not powered to remove the risk of back-powering.

Recording Measurements, RP2040 SPI and the EDU PICO's SD CARD

pipicow-pinout-gp16gp19spihighlight.png

The RP2040 has many groups of pins that are can be used for its hardware SPI feature to communicate with the MCP3280 ADC. The EDU PICO uses SPI to connect to the microSD card making it tempting to borrow these pins particularly if all the modules are still attached to the EDU PICO. The GP16 to GP19 group are highlighted in the pinout diagram above. This selection, however, does prevent the use of the microSD card slot.

The program used for this article writes to the CIRCUITPY drive based on the EDU PICO's enable/disable switch for "log data to pico's flash" connected to Pico's GP15 pin. Very frequent writes to this will eventually wear out the flash storage but in this case only four files were written for the ADC measurements (plus two during development) which is insignificant.

The modules can be detached from the EDU PICO and the connectivity can be rearranged by connected required ones via grove cables to other sockets. There might be another group of SPI capable pins that could be freed up this way to allow the use of a microSD card.

Installing CircuitPython and Program on Pi Pico W

circuitpy-fs-withbinfiles.png

If you are not familiar with CircuitPython then it's worth reading the Welcome to CircuitPython guide first.

  1. Install the latest version of CircuitPython (9.1.4 on September 2024) from https://circuitpython.org/ - this process is described for a similar RP2040-based board in Introducing Adafruit Feather RP2040: Installing CircuitPython.
  2. Verify the new installation by connecting to the serial console over USB. The REPL prompt shows the version number. The version can also be checked by inspecting the boot_out.txt file on the CIRCUITPY drive.
  3. Install this library from a recent bundle from https://circuitpython.org/libraries into the lib directory on CIRCUITPY:
  4. adafruit_display_text
  5. Install the forked adafruit_mcp3xxx library from GitHub: kevinjwalters/Adafruit_CircuitPython_MCP3xxx into the lib directory - this should eventually get merged into the Adafruit library and arrive in the library bundles.
  6. Download to CIRCUITPY
  7. the program by clicking Save link as... on servo-current-mcp3208.py;
  8. the short local file system write-enable program by clicking Save link as... on edo-pico-boot.py.
  9. Rename or delete any existing code.py file on CIRCUITPY, then rename the servo-current-mcp3208.py to code.py. This file is run when the CircuitPython interpreter starts or reloads.
  10. Rename or delete any existing boot.py file on CIRCUITPY, then rename the edu-pico-boot.py to boot.py. This file is run when the microcontroller is first powered or resets.

The file system tree above shows these files/directories and also includes the four output binary files which are the basis for the charts and plots in this article.

The versions used for this article were:

  1. CircuitPython: 9.1.4
  2. CircuitPython library bundle: adafruit-circuitpython-bundle-9.x-mpy-20240827

Measuring 0mV-50mV

FN85WH6M1F0PBXS.jpg

The measurements shown in the video on a prior page were repeated with the improved potential divider going from 0mV to 10mV in 1mV steps and then 10mV to 50mV in 5mV steps. The voltage was set to within 3uV of the target value with the exception of 0mV where 0.102mV was as low as this circuit would go.

The yellow button starts the ADC sampling period after a brief pause. The 200 samples over 10 seconds can be written to a csv file or a more compact binary file if the CIRCUITPY file system is write enabled. The latter was used as CIRCUITPY on the Pi Pico isn't huge. The file name is adc-N.ext where ext is csv or bin and N is the decimal number of the file starting at 1. This number increments when the Pi Pico is power cycled or the reset (can be marked as RST or RUN) button is pressed. The four runs were:

  1. Desktop PC USB power, Vref=1.235V (LM385-1.2);
  2. Desktop PC USB power, Vref=3.3V (default);
  3. Power bank USB power, Vref=1.235V (LM385-1.2);
  4. Power bank USB power, Vref=3.3V (default).

The binary format has 6 bytes per measurement, for 200 samples per voltage with 19 voltages and 3 ADC measurements this creates a file with length 68400 bytes.

The charts on the subsequent pages show the results from the four data files retrieved from the CIRCUITPY drive.

When the CIRCUITPY file system is made writable by CircuitPython using a boot.py program it must not be written to by a USB connected computer. The Adafruit CircuitPython Essentials Storage guide implies the CIRCUITPY drive becomes read-only to a computer under these circumstances.

ADC Comparison - RP2040 Offset

adc-rp2040-mcp3208-lowvolt-v8-g1.png

The plot above shows all of the results from the two ADCs using two voltage reference levels. The additional measurement marked RP2040 GP27 PFM replicates** a technique from the Arduino-Pico-Analog-Correction library where the Pi Pico's power supply mode is changed to pulse-width modulation (PWM) during sampling and then back to pulse frequency modulation (PFM), the default.

The data looks reasonably linear but there is an obvious offset on the RP2040 ADC. Fortunately it does not preclude measuring the full voltage range. For comparison, the offset on the Espressif ESP32 in the other direction prevents measurement below about 150mV.

The close grouping of the green points shows the MCP3208 suffers less from noise than the RP2040 ADC.

Subsequent charts correct the 3.3V reference voltage data with -16 and the 1.24V data with -48. This correction can cause occasional values below 0 - limiting the lower range to 0 may be useful. The Pi Pico (W) datasheet includes a suggestion on how to programmatically measure this offset, reproduced below.

The ADC offset can be reduced by tying a second channel of the ADC to ground, and using this zero measurement as an approximation to the offset.


** The timing in an interpreted language like CircuitPython will be different and less predictable than the C library, therefore the two implementations are not absolutely identical.

ADC Comparison - Distribution As Points

adc-rp2040-mcp3208-lowvolt-v8-g2-3.3-z1.png
adc-rp2040-mcp3208-lowvolt-v8-g2-3.3-z2.png
adc-rp2040-mcp3208-lowvolt-v8-g2-1.24-z1.png
adc-rp2040-mcp3208-lowvolt-v8-g2-1.24-z2.png

The pairs of plots above shows the offset-corrected data on a chart for each voltage reference level. There is also a zoomed in section for a closer look at 0mV-10mV. The points are artificially spread horizontally to allow them to be better distinguished, only the RP2040 GP27 (red) points are in the correct horizontal position. The steps of the ideal ADC values are shown.

The distribution can be seen more clearly here with the overplotting causing more saturated colours where more values occur. The RP2040 is more noisy but is between +/-4 LSB for the almost all the samples. This increases in LSB terms for the lower voltage reference, at Vref=1.24 it's +/- 10 LSB.

The MCP3208 is less capable of measuring the smallest voltages when the voltage reference is lowered. It doesn't respond properly until about 2mV. It would also benefit from some sort of linearity correction.

ADC Comparison - Distribution As Violin Plots

adc-rp2040-mcp3208-lowvolt-v8-g4-low_v-3.3.png
adc-rp2040-mcp3208-lowvolt-v8-g4-high_v-3.3.png
adc-rp2040-mcp3208-lowvolt-v8-g4-low_v-1.24.png
adc-rp2040-mcp3208-lowvolt-v8-g4-high_v-1.24.png

This pair of pairs above shows the distribution for the offset-corrected data minus the multimeter-measured voltage. A violin plot is accompanied by a boxplot and a small grey diamond indicating the arithmetic mean value. This gives a clearer picture on most of the points being very close to the central value with only a few outliers at or beyond +/- 2.5mV.

The RP2040 ADC has a wider spread in millivolts when using the LM385 voltage reference. This is surprising as the voltage reference be expected to provide a more stable voltage reference than the Pi Pico's switch-mode power supply with basic passive RC filter. The RP2040 ADC isn't intended to work below 1.8-2.0V which makes this less surprising.

ADC Comparison - Grouped Distributions As Violin Plots

adc-rp2040-mcp3208-lowvolt-v8-g5.png

The charts above amalgamates all of the distributions previously shown by voltage. These are now split by power source to look for any difference between the normally noisy USB power from a Desktop PC compared to the low-noise power from a PowerBank. The standard deviation (sd) has been added to the plots as text.

The difference in noise between the MCP3208 and RP2040 is shown here and again there's no obvious difference between the RP2040 GP27 and RP2040 GP27 PFM distributions.

The standard deviation values are useful here in to confirm that the power supply to the Pi Pico does influence the ADC noise and the lower-noise PowerBank even with the LM385. This can also be seen to some extent from the outlier points on the boxplots.

ADC Comparison - Grouped Distributions As Points

adc-rp2040-mcp3208-lowvolt-v8-g7-100uv.png
adc-rp2040-mcp3208-lowvolt-v8-g7-1000uv.png
adc-rp2040-mcp3208-lowvolt-v8-g7-6000uv.png
adc-rp2040-mcp3208-lowvolt-v8-g7-8000uv.png
adc-rp2040-mcp3208-lowvolt-v8-g7-50000uv.png

The plots above use the previous grouping but show the 200 samples as overplotted points for some selected voltages: 0.1mV, 1mV, 6mV, 8mV and 50mV. Comparing the plots allows a detailed comparison to check for any differences between these voltages. They are plotted in time order so could also show any anomalies or trends over time.

The distribution of points all looked plots all look very similar. A few values are shown above across the range including some chosen for very consistent values from the MCP3208 values. The full set can be seen as an animation on the final page.

Software Noise Reduction With Mean and IQ Mean

adc-rp2040-mcp3208-lowvolt-v8-g9.png

A common approach to removing random noise with a reasonably even distribution is to take an average (arithmetic mean) value over some (consecutive) samples. This is a form of oversampling. A slightly more advanced approach discards some outliers and takes the mean of a central cut of some samples. For a cut between the 25th and 75th percentile this is know as the interquartile mean. This is more computationally intensive than a mean function.

The charts above compare post-processed data (yellow) with the original raw data (blue). The mean is for ten values, the IQmean discards the lowest two and the highest two values and averages the remaining six.

For these noise reduction techniques the RP2040 values show the boxplot's interquartile range is smaller, there are far fewer outliers (less dots and shorter yellow tails) and the standard deviation is dramatically improved. The IQmean and mean both yield similar improvements.

The MCP3208 data is split by colour but wasn't post-processed hence the symmetry of the plots and same sd values.

Summary

test-adc-revised.jpg
  1. The RP2040 ADC has an obvious offset but this is easily corrected. The corrected value could go below 0 due to noise - constraining the lower range to 0 is wise.
  2. The RP2040 ADC suffers from noise similar to many microcontroller ADCs (although lower than the nRF52 series). This noise does not diminish if the voltage reference is lowered.
  3. The MCP3208, like many external ADCs, has excellent low-noise characteristics. This is useful for reading one good value without needing further processing over more samples. This could be very attractive for an interpreted language like CircuitPython.
  4. Lowering the voltage reference is mathematically attractive and easily be done with a single external component on the Pi Pico. For real world ADCs there will be adverse effects and this isn't a great route to finer resolution.
  5. The technique of briefly switching the Pico's power supply from PFM to PWM mode during ADC sampling does not appear to be beneficial in this case. This could be because it isn't or because it's not for this particular setup.
  6. Averaging ten samples from RP2040 ADC gets reasonably close to the noise performance of the MCP3208. The interquartile mean provides a similar enhancement but with the extra computation will not be worthwhile in this case. If there were more distant outliers then it would be worth using. In software, this processing clearly comes with a processing cost, a reduction in maximum effective sampling rate and possibly errors for high frequency signals from the crude window function.
  7. The voltage reference can be the limit for the input to some ADCs. Some care is required not to exceed this limit on all channels. The RP2040 ADC behaviour is surprising here with the excess voltage on one input appearing on other inputs and to a lesser extent the input pins.
  8. The RP2040 ADC can sample at an aggregate maximum rate of 500ksps. The maximum from the MCP3208 is around 75ksps with a 3.3V power supply. These rates are unlikely to be achievable or sustainable with simple programming in CircuitPython. The new analogio library is available for RP2040 boards and could be useful here.

The RP2040 ADC has a minor fault with incorrect value capacitors in its successive approximation ADC using the charge redistribution design. This is summarised in Errata RP2040-E11 "Summary DNL error peaks in ADC" in the RP2040 datasheet. It creates four "kinks" in its response which can be seen by closely studying the waveform plots (RP2040 in light green) in Adafruit Forums: Feather ADC comparison including 2.6V limited ESP32-S2 and more obviously from the voltage difference plots. For many applications this will be inconsequential.

Going Further

adc-rp2040-mcp3208-lowvolt-v8-g7.gif

Ideas for areas to explore:

  1. Repeat tests with a voltage reference in the permissible range above 2V for the Pi Pico. There are many 2.50V ones and the TI LM4040 at 3.00V is a suggested one.
  2. The MCP3208 according to the datasheet doesn't appear to work well with a low voltage reference of 0.6V. It might be interesting to explore exactly what happens at 0.6V, 0.5V and 0.25V.
  3. The MCP3208 dot plots show that the values can be almost all one value or spread between two values. This suggests that averaging samples might be useful to increase the accuracy below 1 LSB. This could be investigated by checking a small range, like 6-8mV in 0.1mV steps, and then looking at averages over different windows and window sizes.
  4. Check the performance of the MCP3208 with different sample windows. This is 1.5 times the SPI bus clock period. The CircuitPython libraries default to a fairly slow 100kHz clock but this can now be changed with the baudrate argument.
  5. Compare with the 16bit TI ADS1115 at different PGA gains.
  6. Compare with an independent, very stable voltage reference.
  7. Test the performance of the 14bit ADC in the Renesas RA4M1 on the Arduino UNO R4 and try using its internal, general-purpose op-amp to amplify small voltages.
  8. Try some simple op-amp circuits for 10x-100x amplification of small signals.
  9. Test microcontrollers with internal programmable gain amplifiers (PGA) - CircuitPython (version 9.1.4) does not offer control over these.

Further reading:

  1. Instructables: Exploring and Reducing ADC Noise on Adafruit CLUE (Nordic NRF52840) and ADC Analysis page of Adafruit Learn: CLUE Metal Detector in CircuitPython
  2. Element 14: How Do ADCs Work? - The Learning Circuit (YouTube)
  3. Instructables: Making a Charge Redistribution SAADC in Falstad Circuit Simulator
  4. Andreas Spiess: #340 How good are the ADCs inside Arduinos, ESP8266, and ESP32? And external ADCs (ADS1115) (YouTube)
  5. Adafruit Learn: Choosing an ADC
  6. Texas Instruments: AC & DC specifications: Offset error, gain error, CMRR, PSRR, SNR and THD (YouTube)
  7. RP2040 (microcontroller on Pi Pico) ADC and its minor flaw
  8. Mark Omo's Characterizing the Raspberry Pi Pico ADC
  9. Raspberry Pi Forums: ADC Differential Non-Linearity
  10. RP2040 Datasheet - sections 4.9.3, 4.9.4 and errata RP2040-E11 discuss the ADC.
  11. Adafruit Forums: Feather ADC comparison including 2.6V limited ESP32-S2 - a basic comparison of the ADCs in the RP2040, ESP32-S2, ESP32, ATMega328p, nRF52840, SAMD21.
  12. Analog: What Are the Basic Guidelines for Layout Design of Mixed-Signal PCBs?
  13. Microchip: Techniques that Reduce System Noise in ADC Circuits (Analog Design Note ADN007) - a look at selecting external components (pdf).
  14. Open Music Labs: ATmega ADC | ATmega ADC in-depth analysis
  15. Stargirl Flowers: Getting the most out of the SAM D21's ADC
  16. STMicroelectronics: How to get the best ADC accuracy in STM32 microcontrollers (Application Note AN2834) (pdf)
  17. Adafruit Learn for Microchip MCP3008 (10bit version of MCP3208)
  18. MCP3008 - 8-Channel 10-Bit ADC With SPI Interface
  19. Analog Inputs for Raspberry Pi Using the MCP3008
  20. Stack Exchange: Use Cases for an External ADC
  21. Texas Instruments: Fundamentals of Precision ADC Noise Analysis (pdf) - very detailed!
  22. Raspberry Pi Forums: Changing ADC Vref on Pi Pico