Monday, March 28, 2011

LPC1768 ADC has too many glitches

The on-chip ADC in the Atmega lineup was so easy to use compared to the one on LPC1768. Last time I had tried, the Atmega ADC didn't need much filtering to give reasonable results. But the ADC module on LPC1768 seems unusable without filtering.

The setup I used was simple enough. A 2k2 resistor from 3.3 V and another 2k2 in series to GND with the AD0.0 pin connected to the voltage dividing point (this gives Vref / 2 as the input to the ADC). The results dumped onto the screen were quite startling. Here is a small section focusing on the glitch.

2050
2051
2049
2052
4095
2049
2052

Being a 12 bit converter, one would expect the result to be 2047 or 2048 or jumping around somewhere close by. Most values seem close enough. But that 4095 is way too off to ignore it. Connecting a 10nF cap from the dividing point to GND didn't change this. And this glitch didn't happen once in a blue moon either. For every 100 to 1000 conversions, one turned out to be a glitch.
Looks like hypersensitivity to noise, which is throwing off the whole conversion. I wonder if the LPC1768 ADC even has a sample hold circuit. If any of you readers come up with a good explanation as to why this is happening, please drop a note in the comments.

Using a ferrite bead might have solved the issue but nonetheless there is something seriously wrong. This ADC seems too fragile compared to the robustness of the ADC in Atmega's. Right now, all we can do is to workaround the issue with a bit of software.

It's immediately noticeable that this aberration doesn't happen successively. This can be taken to our advantage to workaround the issue. So, we compare the latest conversion value with the previous value and if they are close by, we accept the new value as correct and not a glitch. This simple algorithm however can easily be fooled even if a medium frequency , large amplitude signal is input to the ADC. Now, we can take into account that 2 aberrations rarely happen successively. Even if 2 do, 3 consecutive aberrations are extremely unlikely. So, if the algorithm scanning for correctness of the converted value detects 3 consecutive errors, then the converted value is assumed to be right and the algorithm resets itself.

This code gave me reasonable results.

While this technique works quite well for slow moving signals, it is unlikely to cater to the needs of high frequency signals (> 20 kHz). If sampling such signals is necessary, my recommendation is to oversample and lose accuracy. At 200 kHz, LPC1768 ADC can get 12 bits of accuracy. If you need to sample, say 50 kHz signal, then sample at 500 kHz and hope for at least 8-10 bits of accuracy. Another weakness of this technique is that sampling continually is necessary. If you need the ADC value intermittently, then it becomes very hard to guess if the converted value is right or not.

All in all, LPC1768 ADC seems to be very disappointing. NXP should fix this in future revisions.

18 comments:

  1. Found this blog writing via Google and thought to give a comment. Maybe there is a flaw of some sort in the PCB design? I'm using a voltage divider too (NTC and fixed resistor in series to measure ambient temperature) and I get smooth results without any digital filtering. The board is custom made.

    ReplyDelete
  2. Perhaps. But it does seem unlikely as I discovered soon after writing this post that many mbed users are facing the same issue.

    http://mbed.org/forum/mbed/topic/1866/

    The conclusion is further collaborated by the fact that I used a different board. Here is the link to it.

    http://shop.ngxtechnologies.com/product_info.php?cPath=21&products_id=65

    I've not gone through the PCB layout of either the mbed or the NGX board. It seems unlikely that they share a common flaw. But if you happen to spot it, please let me know.

    Finally, I find it incumbent to mention that I've used the ADC on atmega 8-bit controllers on a breadboard with no separation between the analog and digital rails ( many times, even without decoupling ) and the values read by the ADC have never been so far off or as inconsistent as above.

    ReplyDelete
  3. hi sagar
    i am sampling an ECG on channel 0 and plotting it on glcd. but i am missing something. i am not getting the desired waveform.

    ReplyDelete
  4. What is the reading of the ADC ? Is it stuck to 0 or 4095 or something like that ? It'll help a lot if you post a few readings.

    I'll need more details to help troubleshoot.

    Here's a list of things striking me at the moment.
    Forgive me if they seem obvious and not what you wanted.

    -The pin is configured as GPIO and not as ADC pin.
    -You are forcing the pin with FIOPIN's bit set to 1
    -Maybe you missed the common ground.

    ReplyDelete
  5. Hi sagar
    Thanks for reply.
    I am not doing any of the first two points. Also I have common ground.

    1. My LPC1768 dev board has 12MHz crystal.
    2. Configured to CCLK=72 MHz.
    ADC clock = 3MHz,
    3. and here is what I do....
    GLCD resolution 320x240....

    unsigned int adcArray [2];

    for (i = 0; i < 300; i++)
    {
    trace [i] = 30;
    }
    while(1)
    {
    for (i = 0; i < N; i++)
    {
    adcArray [i] = readADC();
    }
    for(k = 0; k < N; k++)
    {
    adc_val = adcArray[k];

    /**Clear existing trace**/
    for (i = 0, j = 1; i < 299; i++, j++)
    {
    Line (i+10, trace [i], j+10, trace [j], 1, no_bg);
    }

    /**Move trace left by one point and append new data point to trace**/
    memmove (trace, trace + 1, 299);
    trace [299] = (adc_val >> 5) + 30;

    sprintf(str_adc,"%d ",adc_val);
    lcd_printStr_hor(str_adc,155,5,BRIGHT_YELLOW,BLACK);

    /**Plot the signal trace**/
    for (i = 0, j = 1; i < 299; i++, j++)
    {
    Line (i+10, trace [i], j+10, trace [j], 1, YELLOW);
    }

    /**Delay - adjust to reduce sample rate as needed**/
    delay_ms (1);
    }
    (This is part of code....)
    4. Input to ADC is ECG generated using LPC2148 with appro. 1 Hz freq. and 800mv amplitude.
    I tested the ECG on CRO.

    I am not able to decide the buffer size and ADC clock frequency.

    Prithvi.

    ReplyDelete
  6. For ECG, a sampling rate of 1 kHz should be more than enough. The heart beats at a max of 170 times per minute which is about 3 Hz. So, even 10Hz should be enough. But to be sure you've captured detail, perhaps a 100 Hz sampling rate is a good choice.

    I'm not sure of this. You should read some literature or at least find out what sampling rate similar projects used.

    As for the buffer size, we'll need the refresh rate of the screen and resolution ( number of sample points you can display on screen ).

    May be a ring buffer is what you want.

    ReplyDelete
  7. (copied from my post on the mbed forum)
    I just wanted to give some more data points related to my experience on this problem. The spikes are definitely an internal _hardware_ phenomenon particular to the ADC of the LPC. I've never had any problems before with other ADC's even without worrying to much with analog filtering.

    The spikes do seem to be "noise provoked", but are not a measure of the actual noise going into the analog pins.

    On a circuit here that had about 5kOhm impedance output going to the ADC, I was able to make the spikes completely disappear by just using a 330pF capacitor between the ADC input and ground. The resulting low-pass filter (5kOhm, 330pF) is still well above the Nyquist frequency at any sampling rate the ADC can support.

    ReplyDelete
  8. Thank you for posting this info.

    I agree completely that its a hardware problem.

    Good to hear that an RC low pass filter solved the problem for you. But when I did this experiment some months ago, I had tried an RC low pass filter with a cut-off much lower than yours, about 5kHz and I still had issues. The signal that I gave was practically DC ( potential divider ) followed by a 0.1uF capacitor.

    Hopefully the issue isn't as severe for others and my results are less than credible since it was done on a breadboard. Perhaps my board wasn't designed well in the first place and has aggravated the issue.

    Never the less, NXP should pay attention to this and fix the problem.

    ReplyDelete
  9. I'm also doing the tests with an mbed on a breadboard, so maybe there is something else going on.

    The way I see it, the 330pF capacitor that I used is a _workaround_ for an internal problem with the LPC.

    Maybe this has something to do with the sample and hold circuit on the LPC and it actually requires a very low ESR capacitor on the input, so that when it tries to charge the internal capacitor if can transfer the charge very quickly. That might explain why a larger capacitor (100nF instead of 0.33nF) could actually give worse results?

    Without knowing the internals of the LPC the best we can do is guess.

    IIRC, I tried to use 100nF capacitors before to filter the noise (on a different project) and never was able to get rid of the glitches completely. I think this is the first time I'm seeing a LPC's ADC working without glitches.

    By the way, I made a mistake in my previous calculations: a 5 kOhm resistor with a 330pF capacitor should give a low-pass filter at 96kHz which is actually close to the Nyquist frequency for a 200kHz ADC.

    ReplyDelete
  10. That's an interesting theory. But it doesn't explain why the conversion value shoots to 4095 instead of being lower than normal. If the internal capacitor of the S/H circuit is taking too much time to charge, the conversion should give a lower reading.

    That said, if I ever have to use the ADC on LPC1768 again, i'll be trying with a 330pF !

    ReplyDelete
  11. hello people!
    my name is arturo tramontini ( a 57year old man) working in electronics by age 16. i have the same problem of glitch on adc of lpc1768 two year ago, very disappointed, but yesterday 4-8-2011 i found a wonderfull solution: a simple 330pf at adc input and lpc-ground. i have make a simple routine that keep adc0 value and put it on dac, and i see that leaving input open , no glitch appear, touching open adc input with a wire, glitch appears, so the suspect it is radio frequency problem ( remember that lpc1768 is a 100Mhez deice, uaoh!!) , so i try to put a 330pf at input , and wonderfully all glitches disapper, now is several hours running and no glitch appear. i am very very happy of this.
    best regards
    arturo tramontini
    arturo.tramontini@tiscali.it

    ReplyDelete
  12. thanks all, could you post the code, thanks. Camilo

    ReplyDelete
  13. I observerd these glitches (0-4095) with an ADC clock of 12Mhz, below the 13Mhz limit stated in the datasheet.
    When I lowered the clock to 6Mhz, they ALMOST disappeared. That is, they became smaller (around 1000 units) and less frequent (about once in 20000). Lowering the clock down to 1 Mhz doesn't mprove the performance. The ADC of the LPC1768 is definitely
    deffective.
    Daniel

    ReplyDelete
  14. We've seen these too, regularly, on both the lpcxpresso boards and custom-made pcbs. Readings of 4095 in amongst good readings.

    We've had to abandon the use of this processor in favour of TI's offering.

    Come one NXP, sort this out and issue a new version of the silicon!

    ReplyDelete
  15. Hello, I have a NGX 1768-H

    Sorry to be a noob, but I'm learning coding on LPC1768. I'm good at programming ( 15y xp ) but I'm a noob in electronics.
    I manage to write on pin ( 1.29 test led )
    I manage to read on pin ( 1.0 with a button ). I connect one button pin GND to any LPC1768 GND (J3-6) and other pin on J13-1 ( p1.0). And it working, my simple sample, put led 1.29 on when I push button down.

    Now I wanted to read analog value with potentiometer.
    I manage to code the ADC part. But I am a bit lost how to wire the potentiometer.

    I plug from GND to J5-1 ( AD0.0 ), but I don't think it should be like this when reading this article, it seems you wire the resistor from 3.3V ( for example J6-1 ? ) to GND.

    Also I think my wiring is wrong because when I debug value,it seems I have totaly random value ( not just glitches like you explain in your article )

    I don't understand how AD0.0 can convert the voltage then?

    Can you explain? And also can you give me how you wired exactly your resistor to the board please?

    Thanks you very much in advance for Sharing.

    Seb

    ReplyDelete
  16. One resistor was connected between 3.3v and ADC pin and the second resistor was connected between ADC pin and GND.

    ReplyDelete
  17. Ok, so If I want just to read simple pot I must connect between 3.3v and ADC pin, right?

    Thanks for helping.
    Seb

    ReplyDelete
  18. From documentation (for ADC registers): "Reserved, user software should not write ones to reserved bits. The value read from a reserved bit is not defined.". If you set register like this
    ADC_REG |= some bits;
    then you can write reserved bit with 1 but this operation is not allowed.

    ReplyDelete