03 Jan
Posted by: frank in: Computers, Electronics, Programming
I’ve been working with the A/D converter on the Atmel Xmega AVR processors, and it’s been quite the handful. At this point in time (Jan 2010) the parts have some very serious issues, and I’ve lost a lot of time trying to get them to work as advertised. This posting is to share what I’ve found, and the best solutions I’ve determined to get the Xmega A/D converters to work.
If you haven’t already done so, you need to read Atmel application note AVR1300, “Using the XMEGA ADC”, as well as use the source code provided with that app note.
You also need to read the errata for the Xmega. The errata is found towards the bottom of the Xmega datasheet. I should point out that the errata only gives you a hint of the problems with the part, but at least Atmel acknowledges there are some big issues. I’ve been working a lot with Atmel’s tech support, and I must say they’ve been helpful (to the extent they can be) and responsive. Supporting a broken part can’t be easy for them either. They have told me that Atmel is working on a silicon revision to fix these problems, but they haven’t been able to tell me when it might see the light of day.
OK, here we go. The code snippets below are from my code; you’ll need to edit them slightly to suit your needs. But they will show you which AVR1300 functions to use.
Singled-Ended Vs Differential
The Xmega is a differential 12-bit ADC that can be used in either singled-ended or differential mode. Initially I’d been using it in single-ended mode, just because it’s easier, and I’d been getting errors of magnitude well in excess of 30 counts (LSBs). Obviously that’s enormous. In fact the errata implies that errors of up to 60 LSBs are possible. That’s almost 6 bits! At that point it’s closer to a random number generator than an A/D converter…
The best thing to do here is use differential mode. I found the best results came from tying one of the external ADC pins to GND, and using that as the “negative” input for the converter. You want to do this with no gain. Using gain only adds more error. So your code would look something like this (change your pin names as appropriate):
ADC_Ch_InputMode_and_Gain_Config(&ADC_BK.CH0, ADC_CH_INPUTMODE_DIFF_gc, ADC_DRIVER_CH_GAIN_NONE); // differential mode, no gain ADC_Ch_InputMux_Config(&ADC_BK.CH0, pin, ADC_CH_MUXNEG_PIN1_gc); // + & - inputs
It’s possible to use the internal GND reference, but my experiments seemed to favour using an external pin tied to GND.
Xmega ADC Reference Voltage
The part has an internal 1.00V reference voltage, that you’re supposed to be able to use as the reference voltage for the A/D. In practice this doesn’t work. The errata suggests this, and suggests the 1.00V reference is too low a voltage for the ADC to function properly.
I suspect the best solution is to provide a buffered external stable reference voltage of around 2V and feed it into the part via its external reference pin. In my case this wasn’t an option so I had to settle for something else. The next best option is to use the internal setting of VCC/1.6 as the ADC reference. In such a case your code will look something like this:
ADC_Reference_Config(&ADC_BK, ADC_REFSEL_VCC_gc); // use Vcc/1.6 as ADC reference
With a 3.3V VCC, this gives a reference of 2.06V. The problem here is that the reference for an A/D is assumed to be stable. Very stable. That’s hard to claim for a VCC line, which may have all kinds of noise on it. So this falls into the “do the best you can” camp, but it’s still better than using the internal 1.00V.
If you don’t know what VCC is (perhaps you need to measure it), how do you accomplish that when VCC/1.6 is your ADC reference? The only way I know is by getting the ADC to sample the internal bandgap voltage. Something like this:
ADC_Ch_InputMode_and_Gain_Config(&ADC_BK.CH0, ADC_CH_INPUTMODE_INTERNAL_gc, ADC_DRIVER_CH_GAIN_NONE); ADC_Ch_InputMux_Config(&ADC_BK.CH0, ADC_CH_MUXINT_BANDGAP_gc, 0);
You’ll want to calibrate this yourself. The datasheet says the bandgap is 1.1V. I’ve found it’s a little less than that – more like 1.08V. There’s no way to put a multimeter on it directly, but you can get the ADC to measure it, and you can of course measure your VCC voltage, so that tells you what the bandgap actually is. Note that according to the errata, you cannot measure the bandgap if your VCC is below 2.7V, so in that case you’re probably out of luck, and you’d better look again at providing an external ADC reference voltage.
Note there is an error in the errata. (Yes, Atmel needs an errata for their errata….). Errata #4 talks about using the A/D to measure the 1.00V internal voltage reference. Atmel tech support has confirmed this is not possible – the errata is wrong. The only “reference” you can measure is the bandgap.
Signed vs Unsigned Mode
The Xmega has a 12-bit A/D. It can be run in either signed mode, or unsigned mode. If you’re measuring a simple single-ended input referenced to ground (which most folks do), the way to get the full 12-bits of resolution is to use unsigned mode. In unsigned mode, the “negative” input of the ADC is tied to an internally generated voltage which is at the approximate midpoint of the ADC reference voltage. The problem is this internally generated voltage is very unstable, which has the effect of producing widely varying ADC outputs for a stable input voltage.
The solution is to use signed mode. In signed mode, the “negative” ADC input is under your control, and should be routed to a external pin which is tied to GND (as per “Singled-Ended vs Differential” above). Signed mode is selected much like this:
ADC_ConvMode_and_Resolution_Config(&ADC_BK, ADC_ConvMode_Signed, ADC_RESOLUTION_12BIT_gc);
In signed mode, with a simple single-ended input referenced to ground, you effectively have an 11 bit converter, not a 12. Output values will typically be in the range of 0 – 2047 (0 – 0×7ff).
ADC Sampling Speed
For measuring internal signals you need to be running the ADC below 100 kHz. I’ve tried a bunch of different sampling speeds, and 62 kHz seems to be the sweet spot. If you’re using the internal 2 MHz CPU clock, this is an ADC prescaler of 32. Like so:
ADC_Prescaler_Config(&ADC_BK, ADC_PRESCALER_DIV32_gc);
ADC Offset
I’ve struggled with this one. The AVR1300 app note & example code shows a simple method of measuring the ADC’s DC offset, and subtracting it from every ADC measurement. I’ve found the DC offset to be relatively small: around -4 in my case. Yet when I try to “correct” my ADC measurements by subtracting it out, it makes my measurements less accurate, not more.
It almost makes me wonder if it’s not a real DC offset, but rather some artifact of the nonlinearity problems currently inherent to the ADC.
After much experimenting, I’ve decided not to use it. What I do is measure the ADC offset when the code starts up, and I print it out for informational purposes. But then I set the offset to zero, and leave it there. So I’m not using the offset (offset = 0 in my code) and this seems to produce better ADC results.
ADC Calibration Bytes
The AVR1300 code shows how to read the ADC calibration bytes into the appropriate ADC register. Like so:
ADC_CalibrationValues_Set(&ADC_BK);
I’ve found it doesn’t seem to make any real difference. I do indeed do it, but commenting this line out doesn’t appear to make a meaningful difference.
Averaging & Clipping
Averaging ADC measurements certainly helps reduce their sample-to-sample variability. To take an ADC measurement, I take 4 and average them. This is well worthwhile.
The other thing I do is clip them to zero. Because I’m measuring single-ended voltages, a negative voltage is not physically possible (or desired). So after my average of 4 ADC measurements, if the result is less than zero, I make the result zero. This helps in my code later, because I know I don’t need to deal with negative numbers. Otherwise, because my ADC appears to have a slight negative “offset”, measuring a grounded pin can result in an ADC measurement of -3 for example, which is not meaningful. So something like this gets clipped to zero.
Summary
To summarise a long post on the care & feeding of a currently rather broken Xmega ADC, here are my hard-earned suggestions:
Good luck! Let’s hope Atmel releases fixed silicon really soon.
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.
26 Responses
Partha
18|Mar|2010 1Hello Frank,
Thanks a million for sharing your finds on the XMEGA ADC. I had chosen XMEGA for a product of ours and ADC is essential. We are operating XMEGA at 32MHz (internal clock) and when we tried to scale down ADC conversion speed to near about 62k the controller is hanging but at higher speeds it works but not sure about the conversion accuracy.
martin
21|Apr|2010 2Hi Frank,
Wow, thanks for all the info. Can you tell me which Xmega and mask revision you did your tests on.
I’m working with 128A1 and Rev H (I have some Rev G as well). I thought that single ended, unsigned with the internal 1V reference would be OK for what I need to do but I’m having to reconsider that.
frank
21|Apr|2010 3Hi Martin,
I don’t know the mask revision, and with the boards now out of my hands I’m unable to hook one up to a programmer to read out any registers. However this is what can be read off the top of the chips:
ATXMEGA16A4
AU 0921
abey
30|Apr|2010 4is there any circuit for usb flash drive mp3 player,please tell the simple concept about reading mp3 from usb flash drive and how it convert it to sound,
frank
30|Apr|2010 5There are lots of MP3 player projects over at http://www.avrfreaks.net
Rob
05|May|2010 6Thanks Frank.
Im using an XMegaA3 device and have changed the design to incorporate all your valuable recommendations!
MarkW
17|Aug|2010 7I notice with interest your comments that the Calibration bytes have no appreciable effect on your results. I notice that all of the XMEGA xhips I have tested so far have these calibration bytes set as ADCACAL0=ADCBCAL0=0xff and ADCACAL1=ADCBCAL1=0×00
I too have confirmed that setting or not setting these calibration bytes seem to have little effect on the results. However 0×00ff (255) is quite a large offset. Perhaps they are not simply a linear offset scale? Perhaps one byte is a zero offset and the other a gain offset? 0×00 (0) for the one and 0xff (-1) for the other. That would explain why I am seeing little change, despite the disparate numbers. Just my 2c worth.
Jesper
15|Dec|2010 8hi frank,
nice article.. just a comment: I think you should combine the “single-ended vs differential” and “signed vs unsigned mode” sections as having them separate can be confusing since it’s not possible to combine unsigned and differential modes..
regarding the calibration values in the signature row; I’ve gone through a bunch of xmega32A4 chips, and they all have the calibration value 0×0444.. so much for calibrating anything..
also, for people forced to use unsigned mode; the offset that atmel specifies to be around 200 depends on Vref even if the transfer function says it shouldn’t!!! take a look at my thread here: http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=91379
Giuseppe
22|Dec|2010 9Gosh!
Thank you for the article, unfortunately I am unable to use differential mode as I have no more available pins (using an XMega128A1, almost completely full).
Does someone knows how much of this article is still true at the current date (2010/12/22)???
frank
22|Dec|2010 10It appears to still be true. Atmel doesn’t appear to be in any hurry to fix these parts. The most recent silicon I’ve seen, and comments from others on avrfreaks, indicates these problems are still current.
ER!K
17|Mar|2011 11Hello Frank,
thanks for sharing your Xmega ADC experiences. You write “For measuring internal signals you need to be running the ADC below 100 kHz.” and in your summary you suggest to use 62kHz overall. So you suggest to use the 62kHz clock also for external signals, not only for internals?
frank
17|Mar|2011 12Yes, that’s right. I was finding more consistent results measuring external signals when running the ADC more slowly.
Aziz
28|Mar|2011 13Hello Frank,
very useful article & blog, thank you very much!
What did you mean with “Consider assuming the ADC offset is zero.” at summary? Only the differential mode, right?
Unsigned, single-ended mode has a huge offset, as stated on the application note, around 200 counts. It is proposed to measure this offset by connecting the used external pin at actual configuration to GND, which sucks.
As you stated, signed, differential mode can be considered as offsetless (as I also found out experimentally), but the funny thing:
At the given sample driver code, they supply a function;
int8_t ADC_Offset_Get_Signed(ADC_t * adc, ADC_CH_t *ch, bool oversampling);
as well as int8_t ADC_Offset_Get_Unsigned(ADC_t * adc, ADC_CH_t *ch, bool oversampling);
Do you have an idea, what for the signed one does exist? It ruins the measurment result.
Phil
07|Apr|2011 14Thanks Frank
Great Errata sheet, I am just about to start using these chips, so all very handy to know
Thanks again
frank
22|Apr|2011 15I presume you’re asking about the UNsigned “get offset” function. The unsigned “get offset” performs an unsigned ADC measurement. From my original post:
“In unsigned mode, the “negative” input of the ADC is tied to an internally generated voltage which is at the approximate midpoint of the ADC reference voltage. The problem is this internally generated voltage is very unstable, which has the effect of producing widely varying ADC outputs for a stable input voltage.”
That’ll explain why taking an unsigned offset measurement is going to give a crazy result.
Aziz
25|Apr|2011 16Hello Frank,
I understand why the unsigned offset exists.
I just wanted to ask why the Signed offset function exist in Atmel code sample, although the signed differential mode is assumed to have no offset. At the moment, I think signed single-ended measurment mode has a similar offset as the unsigned mode, but I won’t use it anyway.
Thank you very much for the reply.
ER!K
24|May|2011 17Hello Frank,
in AVR1300 a minimum ADC clock frequency of 100kHz is recommended (due to self decharging of the S&H capacitor leading to too low results, I guess). Since you recommend less than 100kHz, in fact 62kHz, have you experienced any problems or effects here?
Thank you and best regards, ER!K
frank
24|May|2011 18From what I’ve seen, the part has bigger problems to worry about. It’s possible I have seen problems related to this; there’s no way to know. I simply tried a variety of different sample rates and found the best results at 62 kS/s (along with doing the other things mentioned in the posts, ie external 2V reference, averaging of multiple results, etc).
Edimahler
13|Jul|2011 19Dear Frank,
Also many thanks from my side, this page is just great! Had troubles using the ADC also. Because I’m using it already in the differential mode, only the divergences between the single conversions was a bigger problem. I solved it averaging by 16 or even 32 times sampling the same signal using 1MSPS. I found out, that this gives (at least for me) the smaller error and faster result than setting the ADC frequency to a smaller value. I’ve very time critical code there. Averaging using an amount of 2^n (2, 4, 8, 16, 32,… times) has of course the big advantage, that you’re able to do a fast shift operation instead of a really slow division by another value.
Today we had a supplier in house who told us, that the corrected chips should now be on market. I’m also using the ATxmega16A4 as you did and read a “H” on the housing of the recently (some weeks ago) ordered pieces. Could this already be the new version? Which advanced fuse-register tells me about the version? (I can only see data like “lot number”, “wafer number”, “wafer coordinates” and so on…
frank
13|Jul|2011 20I’ve read on the avrfreaks forums that revised silicon is coming. I don’t know how to identify the “fixed” silicon, but it’s great you’re hearing it may actually be out. If you ever get the chance to test some new chips, do let us know the results.
Edimahler
02|Aug|2011 21Our supplier just informed me today how to interpret the version of the chip looking on the housing only (still don’t know where to read it out of the fuses(?)). On my BGA-Chip the following data is given:
AT0945A – Manufactured on Week 45 Year 2009, Rev-A
XMEGA16A4 – Device Name
CU-K – Package Type – BGA
9H1120-1 – Lot Number
So, I’m one of the unlucky ones out there who still has the oldest possible version A of the chip with all the nice bugs inside.
Will tell you about news concerning the new version, as soon as I got them and made the first tests with it.
Matic
12|Sep|2011 22Hello,
first i would like to thank you for very useful advices on using ADC.
I have one question about XMEGA ADC. I don’t understand whay is in unsigned, single-ended mode negative pin fixed to Vref/2-dV. I would apreciate if someone could explain that.
Thanks
llimis
11|Jun|2012 23I have a xmega32A4U Rev E chip and I have to say that the ADC converter still have the same issues than the previous xmega chips. Atmel has not corrected none of its problems. Incredible.
Best Regards.
(Sorry for my bad english)
frank
11|Jun|2012 24That is surprising. I’ve personally moved on from the AVR chips – I’ve been using Cortex-M3 and M4 type chips for the last little while now. Vastly more performance, memory, etc, for the same price (they are a little more complex though – the learning curve for the AVR is a little smaller, although not a huge amount smaller). I had been hoping Atmel would fix their AVRs; from what you’re saying, it sounds like maybe not.
mark mccaughey
12|Sep|2012 25we have been using the old ATXMEGA128A1 (we used a work around to try and plug the linearity using fixed offsets in C.) and have had some ATXMEGA128A1U samples and these work as they should great.
ordered a bulk quantity of A1U versions to arrive.
babak
25|Dec|2012 26after lost a week , we found ADC of XMEGA worse and now we think to add LM324 to adj a voltage and use xmega , in my experience :
USE : in Differential mode with , signed mode , low speed and try to be patient
thanks for the person who write this page
Leave a reply
Search
Categories
Archives
Links
Calendar
A design creation of Design Disease
Copyright © 2009 - Frank's Random Wanderings - is proudly powered by WordPress
InSense 1.0 Theme by Design Disease.