{"id":167,"date":"2012-02-14T16:37:23","date_gmt":"2012-02-14T21:37:23","guid":{"rendered":"http:\/\/capnbry.net\/blog\/?p=167"},"modified":"2012-02-14T16:37:37","modified_gmt":"2012-02-14T21:37:37","slug":"when-aref-isnt-aref-yet","status":"publish","type":"post","link":"http:\/\/capnbry.net\/blog\/?p=167","title":{"rendered":"When AREF isn&#8217;t AREF (yet)"},"content":{"rendered":"<p>I&#8217;d often noticed that measuring analog inputs on my ATmega, that the first round of values usually differed substantially from subsequent values. The datasheet even warns of a similiar-sounding issue:<\/p>\n<blockquote><p>The first ADC conversion result after switching reference voltage source may be inaccurate, and the user is advised to discard this result.\n<\/p><\/blockquote>\n<p>Knowing that the Arduino libraries don&#8217;t actually set the reference voltage until the time the first sample is made, it seemed logical that these first samples were an artifact of the voltage changing. However, it wasn&#8217;t just the first sample, or the first couple samples. It could take dozens of samples before the value returned had stabilized (i.e. stopped increasing by more than 2 LSB). Being a boot-only issue. I was content to ignore it until I started trying to read the on-chip temperature sensor.<br \/>\n<!--more--><br \/>\nYou don&#8217;t hear a lot about it but ATmegas have an on-chip temperature sensor connected to their ADC MUX. It can only be read if the analog reference is set to use the 1.1V internal voltage reference. All my other analog inputs needed to be referenced to the 3.3V AVCC, so my code needed to switch back and forth. Easy enough to switch to the internal reference and link the ADCMUX to the temperature sensor, which is ADC8<\/p>\n<pre class=\"brush:c\">\/\/ Switch to ADC8 and analog reference INTERNAL\r\nADMUX = (INTERNAL << 6) | 8;<\/pre>\n<p>The problem of the first N reads now being inaccurate was now being realized on every cycle. This phenomenon finally warranted investigation.<\/p>\n<p>When the ATmega is running on DEFAULT (AVCC) or INTERNAL voltage reference, the AREF pin is connected to these sources so it may therefore be decoupled by an external capacitor to improve noise immunity. This is the sort of thing you see in many schematics.<br \/>\n<div id=\"attachment_175\" style=\"width: 422px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/capnbry.net\/blog\/wp-content\/uploads\/2012\/02\/aref.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-175\" src=\"http:\/\/capnbry.net\/blog\/wp-content\/uploads\/2012\/02\/aref.png\" alt=\"\" title=\"AREF Capacitor Schematic\" width=\"412\" height=\"408\" class=\"size-full wp-image-175\" srcset=\"http:\/\/capnbry.net\/blog\/wp-content\/uploads\/2012\/02\/aref.png 412w, http:\/\/capnbry.net\/blog\/wp-content\/uploads\/2012\/02\/aref-150x148.png 150w, http:\/\/capnbry.net\/blog\/wp-content\/uploads\/2012\/02\/aref-300x297.png 300w, http:\/\/capnbry.net\/blog\/wp-content\/uploads\/2012\/02\/aref-64x64.png 64w\" sizes=\"(max-width: 412px) 100vw, 412px\" \/><\/a><p id=\"caption-attachment-175\" class=\"wp-caption-text\">A capacitor attached to AREF for the purpose of reducing noise<\/p><\/div><\/p>\n<p>Adding capacitance to this pin means from switching from the 3.3V of AVCC to the 1.1V of the internal reference is no longer a nearly instantaneous switch. Here's a scope graph of switching from DEFAULT at 3.3V to EXTERNAL (which has no source attached) to INTERNAL (1.1V) and back to DEFAULT. Given 2.5ms divisions it takes over 10ms to decay down to near-0V and at least 2.5ms to go from DEFAULT to INTERNAL.<br \/>\n<div id=\"attachment_168\" style=\"width: 696px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/capnbry.net\/blog\/wp-content\/uploads\/2012\/02\/AREFswitch-ann.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-168\" src=\"http:\/\/capnbry.net\/blog\/wp-content\/uploads\/2012\/02\/AREFswitch-ann.png\" alt=\"\" title=\"AREF switching\" width=\"686\" height=\"400\" class=\"size-full wp-image-168\" srcset=\"http:\/\/capnbry.net\/blog\/wp-content\/uploads\/2012\/02\/AREFswitch-ann.png 686w, http:\/\/capnbry.net\/blog\/wp-content\/uploads\/2012\/02\/AREFswitch-ann-300x174.png 300w, http:\/\/capnbry.net\/blog\/wp-content\/uploads\/2012\/02\/AREFswitch-ann-150x87.png 150w\" sizes=\"(max-width: 686px) 100vw, 686px\" \/><\/a><p id=\"caption-attachment-168\" class=\"wp-caption-text\">Analog Reference switching time with a 0.1uF capacitor at 3.3V<\/p><\/div><\/p>\n<p>Given that we know the capacitor is 0.1uF and the starting voltage is 3.3V, if we count the time it takes to lose 63% of its charge (down to 1.221V) we can calculate the internal resistance of the the AVR and therefore predict the amount of time it takes to switch from 3.3V to 1.1V directly. In this case it takes 3.353ms<\/p>\n<pre class=\"brush:plain\">\r\n3.353ms = R * 0.1uF\r\n3.353x10-3s \/ 1.0x10-7 = R\r\nR = 33530 ohms\r\n\r\nFrom the equation V = V0 * e ^ (-t\/RC)\r\nt = -1n(V\/V0) * RC\r\nt = -ln(1.1\/3.3) * 33530 * 1.0x10-7\r\nt = 3.68x10-3 = 3.68ms\r\n<\/pre>\n<p>This is fairly unacceptable for my application considering I wanted the whole operation to be completed in a lot less time than that. Lowering the AREF capacitor would proportionally lower the discharge time<\/p>\n<pre class=\"brush:plain\">\r\n0.1uF = 3.68ms\r\n10nF = 368us\r\n1nF = 36.8us\r\n<\/pre>\n<p>It is important to note that this is also the same effect I was seeing on boot up. When you first start the ATmega the reference is set to EXTERNAL so there is 0V on the AREF pin. Arduino libraries will switch the reference to DEFAULT on your first analogRead() call unless you explicitly change it using analogReference(). The AREF capacitor now must charge to AVCC before you can take an accurate reading. Fortunately the resistance between the two is very small so it charges on the order of nanoseconds. Still, there can be a small difference in your ADC reads until the capacitor charges.<\/p>\n<p>Back to the task at hand, measuring the on-chip temperature sensor:<\/p>\n<pre class=\"brush:c\">\r\nunsigned int getAvrTemp(void)\r\n{\r\n    unsigned char high, low;\r\n    ADMUX = (INTERNAL << 6) | 8;\r\n    \/\/ delay goes here if need\r\n    ADCSRA |= bit(ADSC);\r\n    while (ADCSRA &#038; bit(ADSC));\r\n    low = ADCL;\r\n    high = ADCH;\r\n    return (high << 8) | low;\r\n}\r\n<\/pre>\n<p>\u201cDue to process variation\u201d the value you get back is initially worthless. Both the internal reference voltage and the temperature circuit have some amount of tolerance and temperature variation coefficients. For example the \u201cTypical Case\u201d unit should read 314mV at 25C and 380mV at 85C. My device read 373mV indicating my living room was about 78C. To get accurate values you must store some calibration data specific to your ATmega unit. For more information on calibration see <a href=\"http:\/\/www.atmel.com\/Images\/doc8108.pdf\" title=\"Calibration of the AVR's internal temperature reference\" target=\"_blank\">Calibration of the AVR's internal temperature reference<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;d often noticed that measuring analog inputs on my ATmega, that the first round of values usually differed substantially from subsequent values. The datasheet even warns of a similiar-sounding issue: The first ADC conversion result after switching reference voltage source may be inaccurate, and the user is advised to discard this result. Knowing that the [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[10],"tags":[],"_links":{"self":[{"href":"http:\/\/capnbry.net\/blog\/index.php?rest_route=\/wp\/v2\/posts\/167"}],"collection":[{"href":"http:\/\/capnbry.net\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/capnbry.net\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/capnbry.net\/blog\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/capnbry.net\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=167"}],"version-history":[{"count":9,"href":"http:\/\/capnbry.net\/blog\/index.php?rest_route=\/wp\/v2\/posts\/167\/revisions"}],"predecessor-version":[{"id":178,"href":"http:\/\/capnbry.net\/blog\/index.php?rest_route=\/wp\/v2\/posts\/167\/revisions\/178"}],"wp:attachment":[{"href":"http:\/\/capnbry.net\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=167"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/capnbry.net\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=167"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/capnbry.net\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=167"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}