Getting the best ADC performance from mbed
.
When using an ADC, for best results, it is important to consider ways to reduce noise. Here are the main things you can to to ensure noise is kept to a minimum when using the mbed Microcontroller :
- Unused ADC pins are either tied to ground, or declared as DigitalOut
- Quality of signal source, including low noise design techniques such as filtering.
The most marked influence is the state of the unused ADC pins. Grounding them, or configuring them as DigitalOut reshapes the profile of the noise by dramatically reducing the total number of large spikes. The low amplitude noise is most often due to the quality and integrity of the signal.
To ensure the quality and integrity of the original signal, standard circuit design techniques should be applied, such as filtering, termination, careful PCB routing (guard rails, ground planes, separated analog and digital planes, separation of high speed digital signals). There is no one single answer to this issue, it requires the application of best practices.
Background and Experiments
Lots of mbed users have shared their experience around noise in ADC readings based on various setups, including in particular situations where large spikes in ADC readings can be seen. This can be the case even when setting AnalogIn in to a fixed voltage and seeing the variations. The remainder of this page discusses some of these experiences, and some of the analysis that demonstrates the behaviour of applying the above recommendations.
Some of the fixes put forward so far include :
- Software filtering techniques to remove the spikes
- Decoupling capacitors to remove the electrical noise
- The addition of a hand crafted ground plane by davemalham
It is possibly worth taking 5 minutes to read some of the history and appreciate how much effort the community has put in.
After a new forum thread was posted, with the title Spikes Again by Wim van der Vegt is seemed like time to mount a proper investigation at mbed HQ.
I took up the challenge on the hardware side, with Emilio looking into the software implications.
The first thing we identified that was there was no single way of characterizing the ADC performance, everyone who has done experimentation around this have made their own (perfectly valid) way of measuring. We gave this some thought, and decided to come up with an ADC performance measuring program that we could publish - anyone who wants to do ADC work can reuse this, so we're all working against the same measurement.
The program is fairly simple, the main features are :
- pin 17 is biased to 1.65v, 0.5 when reading the AnalogIn
- It takes 500,000 samples and averages them, rejecting <0.45 and >0.55
- with an average calculated, it takes samples in blocks of 500,000
- Each sample is compared with the average, and counter is incremented according to the deviation
- We are checking for 4,8,16,32,64,128,256,512,1024 and 2048 Least Significant Bit (LSB) differences
- At the end of a 500,00 sample block, the running totals are displayed
Import programADCPerformanceMeter
Added explicit check for spikes
First Samples
The first step was to get an idea of the basic performance. The test conditions were:
- mbed in an bread board
- Pin 17 biased with a 10k potentiometer to 1.65v
- The published program compiled and run as published
Test Harware |
---|
The results are pretty dire, especially the number of spike over 1024 LSB, which is 25% of the full scale
Taking an average over 500000 samples Average = 0.503725 Profiling 2500000 samples 500000 337469 157284 572 2 2 0 3 15 23 0 15.900089 1000000 675545 313872 1118 3 3 0 5 32 45 0 15.901036 1500000 1014321 469761 1694 11 5 0 8 51 68 0 15.901663 2000000 1352535 626349 2244 12 8 0 12 68 87 0 15.900941 2500000 1690494 782901 2789 16 11 0 14 85 117 0 15.901027 ==== Test Complete ====
NXP App note
While I was doing some various investigation with copper tape ground planes (which didnt work for me) Emilio was looking into an App note about the ADC :
Emilio had downloaded and run the example program on an MCB1700, and seen very good results. The NXP program sampled 10 values either side of the expected value, and also kept a counter of how many times a sample was seen outside this range. Its performance around the expected value was great.
Emilio then modified the program so that it was sampling wider, as our test program does, and still found the the MCB1700 to perform better than the mbed board (plugged into a breadboard). As it is the same silicon for the MCU, there are clearly some key differences in implementation to account for the differences.
First quick experiments
Firstly, I just want to do some quick experiments, going on hunches and circuit design intuition
10k potentiometer, other ADC pins grounded
Thinking about hardware influences that might affect the performance, I remembered that in the early days of my mbed experimentation, I found that driving an AnalogIn beyond 3.3v doesn't damage it, but can have an effect readings taken on other AnalogIn pins that are in the 0.0-3.3v range.
What if the other AnalogIn pins are introducing noise? Uninitialized pins are inputs with weak pulls ups.
So the next experiment was to pull all the other pins to ground.
Taking an average over 500000 samples Average = 0.503577 Profiling 2500000 samples 500000 29474 470484 0 0 0 0 0 0 0 0 15.525647 1000000 60216 939693 0 0 0 0 0 0 0 0 15.527260 1500000 91377 1408476 0 0 0 0 0 0 0 0 15.527783 2000000 122109 1877696 0 0 0 0 0 0 0 0 15.527227 2500000 152269 2347477 0 0 0 0 0 0 0 0 15.526503 ==== Test Complete ====
So that is a big improvement on the large spikes, but there is still quite a lot of low level noise.
10k potentiometer, other ADC pins driven low internally
My attention now turns to the questions "what if the ground wires are antenna?" - Can i simply declare the other ADC pins as DigitalOuts and drive them low?
Taking an average over 500000 samples Average = 0.503498 Profiling 2500000 samples 500000 22149 477828 0 0 0 0 0 0 0 0 15.583364 1000000 46111 953845 0 0 0 0 0 0 0 0 15.585538 1500000 70468 1429466 0 0 0 0 0 0 0 0 15.586010 2000000 94537 1905376 0 0 0 0 0 0 0 0 15.585663 2500000 117597 2382290 0 0 0 0 0 0 0 0 15.584459 ==== Test Complete ====
Not really that much better.
Fixed resistors, other ADC pins driven low internally
Going on a hunch, I started thinking how noisy a cheap potentiometer is, and how it's impedance might affect the noise level. So I decide to replace it with a pair of 4k7 resistors, which should give me roughly the same bias (given tolerances, and pot precision). Lets see how that goes.
Taking an average over 500000 samples Average = 0.508731 Profiling 2500000 samples 500000 0 0 0 0 0 0 0 0 0 0 16.142586 1000000 0 0 0 0 0 0 0 0 0 0 16.142324 1500000 0 0 0 0 0 0 0 0 0 0 16.142078 2000000 0 0 0 0 0 0 0 0 0 0 16.141958 2500000 0 0 0 0 0 0 0 0 0 0 16.142168 ==== Test Complete ====
Well, that looks pretty good :-)
Fixed resistors, other ADC pins floating
So now we have established that it *can* be made clean, lets see what the other factors might be.
Firstly, I'll repeat the fixed resistor experiment, but without grounding or driving the other ADC pins low.
Taking an average over 500000 samples Average = 0.510484 Profiling 2500000 samples 500000 89 17 0 0 5 0 0 17 19 0 16.076658 1000000 185 40 1 1 7 0 5 36 38 0 16.076626 1500000 272 57 1 4 11 0 7 49 56 0 16.076687 2000000 346 71 4 5 17 0 9 62 77 0 16.076639 2500000 437 93 7 6 21 0 13 73 93 0 16.076696 ==== Test Complete ====
The difference between grounded and floating pins with fixed value resistors is pretty big. One scenario is perfect, the other is pretty dire, so clearly, the state of the other pins has a big influence.
Now to experiment with a slightly more expensive "control" potentiometer, rather than the cheap trimmer. After all, connecting a potentiometer is a pretty standard thing to want to do!
Quality control potentiometer, other ADC pins grounded
When I tried this configuration with the low cost pot, the broad noise was missing, but there was a lot of low amplitude noise, which I believe it associated with the potentiometer.
'Quality Pot' |
---|
Taking an average over 500000 samples Average = 0.535003 Profiling 2500000 samples 500000 284 496610 2959 19 4 0 2 3 2 0 15.551474 1000000 499 993821 5458 26 5 0 2 6 4 0 15.551894 1500000 839 1489438 9288 74 8 0 5 14 5 0 15.550431 2000000 1825 1977177 19734 252 34 0 14 64 41 0 15.541887 2500000 2688 2461966 33259 430 88 0 22 106 70 0 15.537833 ==== Test Complete ====
Hmm... Maybe its not all that great quality after all.
50k potentiometer, other ADC pins grounded
This time I will use a 50k trimmer pot with the other ADC pins grounded.
50k Trimmer configuration |
---|
Taking an average over 500000 samples Average = 0.496764 Profiling 2500000 samples 500000 0 0 0 0 0 0 0 0 0 0 16.534067 1000000 0 0 0 0 0 0 0 0 0 0 16.534651 1500000 0 0 0 0 0 0 0 0 0 0 16.534674 2000000 0 0 0 0 0 0 0 0 0 0 16.534210 2500000 0 0 0 0 0 0 0 0 0 0 16.534685 ==== Test Complete ====
I wasn't expecting that! This pot is very low profile, so maybe that is less opportunity to pick up noise.
'Quality' 10k potentiometer, other ADC pins grounded (again)
I'll repeat the test, but with really short leads to the pot, to test the hypothesis that the wires might be to blame.
Taking an average over 500000 samples Average = 0.519472 Profiling 2500000 samples 500000 1476 496863 1130 117 4 0 8 36 24 0 15.554942 1000000 2400 995117 1744 160 7 0 10 48 28 0 15.555830 1500000 3147 1494181 1933 160 7 0 10 48 28 0 15.556872 2000000 4012 1993156 2093 160 7 0 10 48 28 0 15.557085 2500000 4893 2492121 2247 160 7 0 10 48 28 0 15.557070 ==== Test Complete ====
So it really might be the pot rather than the wires.
Other Experiments
The App note from NXP suggests that a lot of noise can be introduced by a debug session taking place, because of the extra activity from the debug logic.
As the LPC1768 is *always* in debug, that might be a source of noise. I'll now rebuild the binary with floating inputs but have the mbed detach the debugger using the mbed_interface_disconnect(); function.
I'll run this test with floating inputs and the original potentiometer so see if there is a marked difference.
Potentiometer, floating ADC pins, no interface
Taking an average over 500000 samples Average = 0.500203 Profiling 2500000 samples 500000 149419 1073 235 2 1 0 2 5 11 0 16.135899 1000000 298635 2105 450 4 2 0 3 12 24 0 16.135973 1500000 447184 3199 680 4 2 0 7 17 38 0 16.135851 2000000 595798 4249 883 4 3 0 8 26 51 0 16.135960 2500000 744252 5276 1106 4 4 0 10 33 69 0 16.135889 ==== Test Complete ====
This compares favorably!
connected : 1690494 782901 2789 16 11 0 14 85 117 0 disconnected : 744252 5276 1106 4 4 0 10 33 69 0
So what if we disconnect the interface, and drive the ADC pins low, using the original potentiometer.
Potentiometer, ADC pins driven low, no interface
Taking an average over 500000 samples Average = 0.500188 Profiling 2500000 samples 500000 108293 7 0 0 0 0 0 0 0 0 16.209215 1000000 216290 22 0 0 0 0 0 0 0 0 16.209204 1500000 323363 27 0 0 0 0 0 0 0 0 16.209171 2000000 430649 31 0 0 0 0 0 0 0 0 16.209175 2500000 537710 38 0 0 0 0 0 0 0 0 16.209183 ==== Test Complete ====
The noise has broadly gone. The only noise that remains is the low amplitude noise which I would attribute to the potentiometer.
Fixed 4k7 resistors, ADC pins driven low, no interface
aking an average over 500000 samples Average = 0.508413 Profiling 2500000 samples 500000 0 0 0 0 0 0 0 0 0 0 16.207121 1000000 1 0 0 0 0 0 0 0 0 0 16.207090 1500000 2 0 0 0 0 0 0 0 0 0 16.207085 2000000 2 0 0 0 0 0 0 0 0 0 16.207071 2500000 3 0 0 0 0 0 0 0 0 0 16.207073 ==== Test Complete ====
This isn't the "perfect zero's that we saw in the same configuration with the interface connected. The results are still good though, just three samples out of 2,500,000 have an error, but all those errors are less than 8 LSB
Note
Disabling the debug communucation between the interface and the LPC1768 reduces the digital activity inside the LPC1768 which can influence the noise on the ADC. The profile of the noise remains largely the same, but with the total number of errant samples in each range reduced significantly.
However, it should be done with careful consideration, as there is an impact on how the mbed behaves.
14 comments on Getting the best ADC performance from mbed:
Please log in to post comments.
What exactly does "disabling the debug communication" do? What is the "impact on how the mbed behaves"?
Thanks for an excellent read.