Frank's Random Wanderings

Followup to Atmel Xmega ADC Problems

Time marches on and we’ve had to perform a new PCB revision for the board containing the Atmel Xmega part. So I had the opportunity to add an external voltage reference to the chip. This was one of the things I recommended considering in my last post.

There are some constraints. We wanted the reference’s voltage to be as high as possible, to allow as much dynamic range as possible, knowing that the ADC doesn’t work with reference voltages down around 1 volt. (Which of course is why the internal 1.00V reference is currently useless.) But the voltage reference cannot be greater than VCC – 0.6V. And good quality voltage references get expensive fast, whereas breaking the bank was not on our list of things to do. We ended up selecting the Analog Devices 2.048V 0.24% part, the ADR380. It comes in a trivially easy-to-use SOT23 package, and costs less than $2 at digikey if you buy just one; less than $1 if you buy a bunch.

You can help your voltage reference by powering it with a clean supply. Having some decoupling caps on both its input and output, as well as feeding it power through a ferrite bead or some other filter, helps prevent digital noise in your system from making its way into your reference. On our board the output from the ADR380 is connected to Port A bit 0. Then using it as the ADC reference is easily done, like so:

ADC_Reference_Config (&ADCA, ADC_REFSEL_AREFA_gc);

All the other tricks in the previous post are followed. Differential mode is used, with one of the external ADC pins tied to ground (Port A bit 1 on our board) being used as the “negative” input. Signed mode is used, so the effective ADC output range becomes 0 – 0x7ff, ie 11 bits worth. The software looks something like this:

ADC_ConvMode_and_Resolution_Config(&ADCA, ADC_ConvMode_Signed, ADC_RESOLUTION_12BIT_gc);    // signed mode, 12 bit resolution
ADC_Ch_InputMode_and_Gain_Config (&ADCA.CH0, ADC_CH_INPUTMODE_DIFF_gc, ADC_DRIVER_CH_GAIN_NONE);     // differential mode, no gain
ADC_Ch_InputMux_Config (&ADCA.CH0, ADC_CH_MUXPOS_PIN5_gc, DC_CH_MUXNEG_PIN1_gc);	// + & - inputs

The ADC is run at the speeds described in the previous post, and we take 4 measurements then average them, clipping to zero if the result is less than zero.

The result has been a tremendous improvement from that described in the previous post. The ADC results have been stable and consistent, and they seem to be about as accurate as we can verify. It’s a big improvement. It’s unfortunate that it requires external components to make the Xmega work, but still, it’s a very big step forward, and our new board is much more functional than the previous one.

As an interesting aside, you might contemplate, as I first did, “Gee, 2.048V is a very strange number for a reference; why not just 2V?” Well that’s a reasonable question, until it’s time to write code. Suddenly it becomes ludicrously easy to convert ADC results to millivolts. Consider this. The reference is 2.048 volts, ie 2048 millivolts. The full-scale ADC output is 0x7ff, ie 2047. You got it – you basically don’t have to do anything at all – using this reference, with the ADC in signed mode, the ADC results are already in millivolts. Life’s pretty simple, and the 2.048V reference is a pretty neat thing. Would a 2.047V reference be even better? Not really – remember the reference has a tolerance of 0.24% anyway.

As another aside, the Atmel Xmega datasheet says the internal bandgap has a nominal voltage of 1.1V. We’ve measured it on a handful of parts, and consistently found it to be in the range of 1.08V – 1.085V. Take that information as you will, but if you’re trying to use the bandgap as a known voltage in your system, I’d suggest you consider starting with an assumption of 1.085V rather than 1.1V for the bandgap.

There you have it. If you need to use the ADC in an Atmel Xmega, I can now say from personal experience: use an external voltage reference; it really helps.

Update: In late 2011 Atmel started shipping a revised line of Xmega parts called the “U” parts. The new partnumbers end with a U. For example ATXMEGA32A4U. Although I haven’t personally tried these new devices, apparently these U parts have the ADC problems fixed. I believe the non-U parts still have the ADC problems. If you’re going to be using an Xmega for something, I’d suggest looking for a U part.

13 thoughts on “Followup to Atmel Xmega ADC Problems

  1. frank Post author

    Thanks for the update! Good to know there’s a fixed version of the silicon.

  2. mark mccaughey

    now using A1U , problem has now gone away, new processor is also half price of the old

    on the A1 version , we had to use manual adjustments across the range to get things in spec not ideal, but got us put of a hole

  3. BAB

    hi dear frank
    i use LD1117-2.5 for aref of atxmega16a4 and LD1117-3.3 for VCC but my board burn sometimes when start working burn LD1117-2.5 and its voltage will be 11v and then uc burns .
    or simetimes LD1117-3.3 burn and then burn the uc i dont know what is happend !! ? please help me .
    best regards

  4. frank Post author

    The best place to go for all things AVR, including code examples, tutorials for newbies, etc, is avrfreaks.net

  5. Mario

    I really like this follow up to your original article.

    Is there anyway you can provide us with a compilable source for the newbies like me who already are having a hard time setting up the hardware?

    Thank you so much

  6. Tom Pappano

    I used a single 2.5v external ref for Vref and actually, tying the – adc input to Vref (*not* Vref/2) yields the proper -2048 thru +2047 for 0 – 2.5v applied to the + input, as one might actually have expected. I’m a little baffled about Atmel’s “Vref/2” business, which seems to make no sense. I get good stable readings with this arrangement, but I still need to check the linearity.

  7. Tom Pappano

    I was thinking of a low resistance divider for Vref/2, but also considering just stacking two 1.2v refs as an alternative. The dynamic impedance should be plenty low enough that way.

    Thanks,
    Tom

  8. frank Post author

    No I haven’t, but based on my apparent success with tying the -ve input to ground externally, I think your idea would likely work. Assuming of course you use a suitably low-impedance reference voltage. I don’t think a resistor-divider off the main ADC reference would work, however buffering it through an op-amp or some other similar scheme would probably work well.

  9. Tom Pappano

    Thanks for your very informative tests and posts. To attempt salvage of the adc with full 12 bit resolution, have you tried differential mode with external Vref and connecting the -diff input to an externally developed Vref/2? I just got my hands on an xmega Friday, and will try this scheme tomorrow, if you haven’t yet.

    Thanks!

  10. frank Post author

    You’re very welcome. Yes you can set the -ve differential input to Vref/2, but in my experiments I found that was a bad idea, because Vref/2 appeared to be unstable. I was finding the noise / variability of the A/D results increased substantially when I did this. That’s why I’ve suggested setting that -ve diff input to GND; it produced much more consistent A/D results.

  11. steve

    Thanks for your blog; googling helped me find them. It has saved me a _ton_ of time! If you want that extra bit of resolution, you can set the negative input of your differential pair to Vref/2.
    – Steve

Leave a Reply

Your email address will not be published.