Atmega328p ADC & CPU frequency

For Adafruit customers who seek help with microcontrollers

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
User avatar
tcharron
 
Posts: 59
Joined: Tue Oct 13, 2009 7:15 pm

Atmega328p ADC & CPU frequency

Post by tcharron »

I have a TMP36 hooked to an Atmega328p. I get temperature readings that are within 0.5 degrees when I run at 1MHZ, or at 2MHZ using an externall full-swing 16MHz crystal with the CKDIV8 activated.

When I run at 16MHz, the accuracy of the ADC dropps significantly. Is this normal? I'm using the internal 1.1v reference, and have confirmed that the ADC measurements don't match the output on the TMP36 using an accurate voltmeter.

Thoughts?

User avatar
fat16lib
 
Posts: 595
Joined: Wed Dec 24, 2008 1:54 pm

Re: Atmega328p ADC & CPU frequency

Post by fat16lib »

What software are you using to control the ADC?

The dynamic impedance of the AVR ADC depends on a number of factors including clock rates.

The TMP36 has an output impedance that is high enough that noise and the ADC input impedance can cause problems. Sensors like the TMP36 are low current to avoid self heating which limits their output capability.

Here is an interesting article on this problem http://focus.ti.com/lit/an/spna061/spna061.pdf.

User avatar
tcharron
 
Posts: 59
Joined: Tue Oct 13, 2009 7:15 pm

Re: Atmega328p ADC & CPU frequency

Post by tcharron »

I've been using arduino code (although my hardware is not an arduino). Analogread().
Thanks for the article. I get it. I tried a 1uF capacitor and it made things worse. This 'proves' that the ADC is drawing more current than the chip can provide. The best answer for me would be to use an op-amp but I think I can tweak things and get by using 1MHz. Unfortunately, I've also got a frequency based humidity sensor on the device, and I get more accuracy at 16MHz. Tradeoffs!

User avatar
fat16lib
 
Posts: 595
Joined: Wed Dec 24, 2008 1:54 pm

Re: Atmega328p ADC & CPU frequency

Post by fat16lib »

Often you can get better results with analogRead for two sensors by doing a reading, delay for 10 ms, then do another reading of the same sensor. The first reading switches the ADC mux and lets voltages settle. Use the second reading for the sensor value.

Also if you switch to the 1.1V reference you need to do a reading, delay, and do another reading. It takes a long time to switch from the 5V default to the 1.1V reference. analogReference() does not switch the reference. It just sets a global variable that is used by analogRead() to select the reference. The first reading switches the reference and the second reading will be more accurate after the reference settles.

I assume you use the Arduino IDE so init() is called before setup()/loop(). init() sets the ADC clock prescaler to 128 which results in a 125KHz ADC clock on a 16MHz Arduino. The ADC requires a clock frequency between 50 kHz and 200 kHz to get maximum resolution.

User avatar
tcharron
 
Posts: 59
Joined: Tue Oct 13, 2009 7:15 pm

Re: Atmega328p ADC & CPU frequency

Post by tcharron »

Thanks -- this is very helpful for me to understand what's going on. I'm still a bit confused though.

1) I'm only using one ADC device (the humidity sensor generates a square wave that is read via a digital pin)

2) All measurements are off the 1.1V reference, and I do a read and discard before a long delay in my setup() routine.

3) Yes - the prescaler is getting set to 128. The strange thing (to me) is that while this is designed to work at 16MHz, the actual arduino code doesn't scale for the slower F_CPU settings that I have tried. As a result, when I'm running the Atmega328 at 1MHz, the ADC is actually running at 15625 Hz. I guess that this means that my device won't work without an opamp at the target 125KHz. It also means that the Atmega328 can safely handle the slower frequency despite having a specified requirement of between 50kHz and 200kHz

My need for a faster cpu was because of the accuracy I wanted in measuring the frequency based humidity sensor. I think now that by using an external crystal, setting CKDIV8, and perhaps using a scope to actually measure the CPU frequency (and program an adjustment in my code), I can get a pretty accurate measure of the external frequency.

User avatar
fat16lib
 
Posts: 595
Joined: Wed Dec 24, 2008 1:54 pm

Re: Atmega328p ADC & CPU frequency

Post by fat16lib »

The Arduino software should take F_CPU into account but it works OK for 8-16 MHz CPUs.

You may not get max accuracy with a slow ADC clock, not the full 10-bits.

You should be able to read a TMP36 at F_CPU of 16 MHz, ADC clock 125 KHz if it is the only analog sensor.

I can read a TMP36 to 1.0 degrees F with a 5V reference on a standard Arduino. You should be able to do better with the 1.1V reference. Do you have a cap from AREF to ground? The 1.1V source is high impedance.
The internal voltage reference may thus be decoupled by an external capacitor at the AREF pin to improve noise immunity.
You must calibrate the 1.1V reference since it can vary by up to 10%. It is really only intended for brownout detection and is not a very good reference.

You could try oversampling http://www.atmel.com/dyn/resources/prod ... oc8003.pdf

User avatar
chelmi
 
Posts: 53
Joined: Wed Nov 19, 2008 12:09 pm

Re: Atmega328p ADC & CPU frequency

Post by chelmi »

fat16lib wrote: You may not get max accuracy with a slow ADC clock, not the full 10-bits.
If I understand the datasheet correctly, slower ADC clock increases accuracy.

User avatar
fat16lib
 
Posts: 595
Joined: Wed Dec 24, 2008 1:54 pm

Re: Atmega328p ADC & CPU frequency

Post by fat16lib »

The ATmega328 datasheet states
By default, the successive approximation circuitry requires an input clock frequency between 50 kHz and 200 kHz to get maximum resolution.
I have not seen a clear description of what happens at slower ADC clock rates for the AVR ADC. The normal problem with a slow ADC clock is
The conversion must complete in some minimum time or droop on the sample-and-hold can degrade conversion results.

User avatar
tcharron
 
Posts: 59
Joined: Tue Oct 13, 2009 7:15 pm

Re: Atmega328p ADC & CPU frequency

Post by tcharron »

fat16lib wrote:The Arduino software should take F_CPU into account but it works OK for 8-16 MHz CPUs.
Unfortunately, it doesn't (although it could be easily adjusted). wiring.cpp (arduino-0017) has this:

Code: Select all

	// set a2d prescale factor to 128
	// 16 MHz / 128 = 125 KHz, inside the desired 50-200 KHz range.
	// XXX: this will not work properly for other clock speeds, and
	// this code should use F_CPU to determine the prescale factor.
This is a very simple board and it should work. Other than the cpu, it has an xbee, temperature sensor, and (digital) humidity sensor attached. I have a 0.1uF cap on aref, a 16Mhz crystal with caps installed, and a power line cap (1uF I think). I have measured the 1.1V reference with an accurate voltmeter (and I don't think that this is the problem as the ref voltage doesn't change when I change the CPu frequency).

I don't think that oversampling would help. The signal I'm measuring is stable, and my measurements are off by 3% of the reference voltage - it doesn't seem to be a LSB measurement problem.

User avatar
fat16lib
 
Posts: 595
Joined: Wed Dec 24, 2008 1:54 pm

Re: Atmega328p ADC & CPU frequency

Post by fat16lib »

It's a real puzzle why it doesn't work. Have you tried with only the TMP36. This is dead simple on an Arduino.

Here is my test program that tracks the temperature measured by a thermocouple next to the TMP36 to about 0.1 degree C on a standard 16 MHz Arduino.

Code: Select all

#define V_REF 1.076  // measured value of reference
#define CAL_OFFSET -0.2 // TMP36 correction degrees C

void setup(void) {
  analogReference(INTERNAL);
  Serial.begin(9600);
}

void loop(void) {
  uint16_t sum = 0;
  for (uint8_t i = 0; i < 16; i++) {
    sum += analogRead(0);
  }
  float adcAvg = sum/16.0;
  float v = V_REF*adcAvg/1023;
  float temp = 100.0*(v - 0.5) + CAL_OFFSET;
  Serial.print("adc: ");
  Serial.print(adcAvg);
  Serial.print(", temp C: ");
  Serial.println(temp);
  delay(1000);  
}
Here is typical output showing the noise level.

Code: Select all

adc: 682.25, temp C: 21.56
adc: 682.31, temp C: 21.57
adc: 682.13, temp C: 21.55
adc: 682.25, temp C: 21.56
adc: 682.25, temp C: 21.56
adc: 682.50, temp C: 21.59
adc: 682.06, temp C: 21.54
adc: 682.31, temp C: 21.57
adc: 682.13, temp C: 21.55
adc: 682.13, temp C: 21.55
adc: 682.31, temp C: 21.57
adc: 682.25, temp C: 21.56
adc: 682.25, temp C: 21.56
adc: 682.19, temp C: 21.55
adc: 682.75, temp C: 21.61
adc: 682.44, temp C: 21.58
adc: 682.38, temp C: 21.57
adc: 682.25, temp C: 21.56
adc: 682.06, temp C: 21.54
adc: 682.13, temp C: 21.55
adc: 682.63, temp C: 21.60
adc: 682.25, temp C: 21.56

User avatar
tcharron
 
Posts: 59
Joined: Tue Oct 13, 2009 7:15 pm

Re: Atmega328p ADC & CPU frequency

Post by tcharron »

Yeah, it's a puzzle all right.

Here are the readings I get using your code (I ran these at four different CPU frequencies all within about 3 minutes of each other and on the same hardware).

Code: Select all

room temp 19.8   8Mhz int  // CKDIV8 // CPU 1MHz

adc: 652.31, temp C: 19.76
adc: 652.19, temp C: 19.75
adc: 652.31, temp C: 19.76
adc: 652.38, temp C: 19.77
adc: 652.19, temp C: 19.75
adc: 652.63, temp C: 19.79
adc: 652.06, temp C: 19.73
adc: 652.13, temp C: 19.74
adc: 652.19, temp C: 19.75
adc: 652.19, temp C: 19.75
adc: 652.31, temp C: 19.76

room temp 19.8   16MHz crystal // CKDIV8 // cpu 2MHz

adc: 643.63, temp C: 18.83
adc: 643.44, temp C: 18.81
adc: 643.25, temp C: 18.79
adc: 643.13, temp C: 18.78
adc: 642.88, temp C: 18.75
adc: 642.94, temp C: 18.76
adc: 642.75, temp C: 18.74
adc: 642.88, temp C: 18.75
adc: 642.88, temp C: 18.75
adc: 643.19, temp C: 18.78

room temp 19.8   8Mhz internal // CPU 8MHz

adc: 580.44, temp C: 12.07
adc: 576.94, temp C: 11.70
adc: 583.19, temp C: 12.37
adc: 588.19, temp C: 12.90
adc: 581.56, temp C: 12.19
adc: 577.00, temp C: 11.70
adc: 583.06, temp C: 12.35
adc: 587.19, temp C: 12.79
adc: 580.81, temp C: 12.11
adc: 577.06, temp C: 11.71

room temp 19.8   16MHz crystal // cpu 16MHz

adc: 602.56, temp C: 14.44
adc: 600.13, temp C: 14.18
adc: 600.56, temp C: 14.22
adc: 604.50, temp C: 14.65
adc: 604.56, temp C: 14.65
adc: 600.44, temp C: 14.21
adc: 598.63, temp C: 14.02
adc: 598.25, temp C: 13.98
Interestingly, the results are 'stable' despite being wrong.

I actually have three 'versions' of this hardware and they all behave the same way. I will do as you suggest and strip the device down to CPU+TMP36 to see if these symptoms persist.

Thanks for your insight.

User avatar
didier
 
Posts: 115
Joined: Mon Nov 17, 2008 6:14 am

Re: Atmega328p ADC & CPU frequency

Post by didier »

It may be a silly trivial question: How did you, both tcharron and fatlib16 bind the sensor to what ?

User avatar
fat16lib
 
Posts: 595
Joined: Wed Dec 24, 2008 1:54 pm

Re: Atmega328p ADC & CPU frequency

Post by fat16lib »

didier,
I used a tiny clip to hold a thermocouple against the TMP36. The TMP36 is in a tiny breadboard on a bench in still air. Short wires connect the breadboard to an Arduino. The reading from the thermocouple tracks the TMP36 value from the Arduino closely when room temperature changes.

tcharron,
Your results should be good a clue to the mystery but I don't have any new ideas. Hope you figure it out. I am now really curious to know what's happening.

User avatar
tcharron
 
Posts: 59
Joined: Tue Oct 13, 2009 7:15 pm

Re: Atmega328p ADC & CPU frequency

Post by tcharron »

didier wrote:It may be a silly trivial question: How did you, both tcharron and fatlib16 bind the sensor to what ?
I have installed everything onto an atmega target board (link here: http://evilmadscience.com/tinykitlist/74-atmegaxx8). The sensor is soldered to the conveniently located power and ground pins near ADC0. Each of the sensor legs is about 1cm in length. The 0.1uF capacitor is soldered directly next to the chip in the nearest two via holes across Aref and GND.

I still have some work to do to try to isolate the various components. I also have an oscilloscope in storage that might reveal some interesting noise ripples on the chip. Something to do on a rainy day!

User avatar
didier
 
Posts: 115
Joined: Mon Nov 17, 2008 6:14 am

Re: Atmega328p ADC & CPU frequency

Post by didier »

May I draw your attention to one critical point which has been mentionned above: power supply noise!
The TMP36 data sheet is very explicit on noise: see p 8 and p 10 from http://www.datasheetcatalog.org/datashe ... _6_7_c.pdf.

You may say, OK, but we have a filtered power supply. True. But the filter is fitted for a specific frequency (default 16 Mhz), isn't it? I would suggest that you decouple the µcontroller from the DC line using a LC filter, or cheaper and pretty efficient a RC pi filter (with 1 Ohm R) in sandwitch between two capacitors (my favorite) and adjust it to your frequencies.

What is the weather like tcharron? Your scope measurement should tell you quite a lot. I remember that René, a former collegue of mine solved a critical problem on $$$$$$$ equipment in this way. A known as undestructible, bullet proof, over rated filtering capacitor was deffective and let HF signal flow through sensitive amplifiers, leading to unpredictible results!!! Since, I keep an ear on noise! No, no an eye on nose! Argl, an eye on noise.

Locked
Please be positive and constructive with your questions and comments.

Return to “Microcontrollers”