Das vorgestellte Bild stammt von OpenClipart-Vectors auf Pixabay.

Wenn man eine eigene MCU-Platine baut, verwendet man oft keinen Quarz oder Resonator. Stattdessen wird der interne RC-Oszillator verwendet, der ziemlich ungenau sein kann. Wenn man die interne Referenzspannung zur Messung der Versorgungsspannung verwenden will, stellt sich heraus, dass die Referenzspannung sehr stark von ihrem Nennwert abweichen kann. Sowohl der RC-Oszillator als auch die interne Referenzspannung können jedoch kalibriert werden. In diesem Blogbeitrag beschreibe ich eine einfache Methode, um beides mit einem UNO-Board und einem Multimeter unter Verwendung der avrCalibrate-Bibliothek zu kalibrieren.

Motivation

Vor allem bei der Entwicklung von batteriebetriebenen Systemen mit geringem Stromverbrauch stellt sich die Frage nach der Kalibrierung des RC-Oszillators und der internen Referenzspannung.

Warum sollte der RC-Oszillator kalibriert werden?

Die Verwendung des internen RC-Oszillators reduziert die Anzahl der Bauteile, spart Platz auf der Leiterplatte, ermöglicht die Nutzung von mehr MCU-Pins als GPIOs und reduziert den Versorgungsstrom und die Aufwachzeit aus dem Ruhezustand. Alles in allem hat es viele Vorteile, insbesondere für Anwendungen, bei denen geringer Stromverbrauch essenziell ist. Der größte Nachteil ist die geringe Genauigkeit. Während Quarzoszillatoren eine maximale Abweichung von ca. ± 50 ppm und Keramikresonatoren von ca. ± 1000-5000 ppm oder ± 0,1 bis 0,5 % haben, ist die werkseitige Kalibrierung von RC-Oszillatoren in AVR-Chips mit einer Genauigkeit von bis zu ±3 % oder ±10 % (je nach Gerät) angegeben.

Wie im Blogbeitrag über asynchrone Kommunikation erwähnt, kann eine Abweichung von 3 % bereits jenseits der akzeptablen Grenze liegen. 10 % sind es auf jeden Fall! Wenn du eine Zeitmessung durchführen willst, sieht ein Fehler von 10 % ebenfalls nicht sehr überzeugend aus. Allerdings kann man den Fehler auf 1 % senken, indem man das OSCCAL-Register der AVR MCUs verändert. Dabei ist allerdings zu beachten, dass die Kalibrierung von der Versorgungsspannung und der Temperatur abhängt. Mit anderen Worten: Der Fehler von 1 % ist nur dann garantiert, wenn sich diese beiden Parameter nicht zu stark ändern.

Warum sollte man die interne Referenzspannung kalibrieren?

Bei Low-Power-Anwendungen möchte man oft die (von einer Batterie stammende) Versorgungsspannung überwachen, um den Betrieb stoppen zu können, bevor die Anzeige nicht mehr lesbar ist oder das EEPROM beschädigt wird. Man kann diese Aufgabe dem Brownout-Erkennungsmechanismus der MCU überlassen. Allerdings zieht dieser Mechanismus im Abschaltmodus eine beträchtliche Menge Strom, es gibt nur wenige feste Spannungspegel, er ist nicht sehr genau und, was am wichtigsten ist, er setzt den Chip zurück und erlaubt nicht die Ausgabe einer Unterspannungsmeldung auf einem Display.

Eine Möglichkeit, die Versorgungsspannung recht genau zu messen, ist die Messung der internen Referenzspannung (meist 1,1 Volt), indem der ADC die Versorgungsspannung als Referenz verwendet. Das Problem ist nur, dass auch die interne Spannung nur bis zu 10 % genau ist. Wie im obigen Fall kann man die Genauigkeit verbessern. Wenn die Versorgungsspannung bekannt ist, ist es einfach, die wahre interne Referenzspannung mit einem Fehler von weniger als 1 % zu schätzen, vorausgesetzt, die Temperatur ändert sich nicht zu stark.

Kalibrierungsvorgang

Für den Kalibrierungsvorgang brauchst du ein Serverboard, das die Referenzfrequenz erzeugt. Das kann ein UNO-Board oder ein ähnliches Board sein. Die Taktfrequenz sollte idealerweise von einem Quarz gesteuert werden, aber auch ein Keramikresonator ist akzeptabel. Normalerweise haben diese Resonatoren eine Genauigkeit von mehr als 0,1 %. Manchmal kann es aber auch bis zu 0,9 % Abweichung geben. Wenn du also sichergehen willst, solltest du die Frequenz messen, die am MOSI-Pin (digitaler Pin 11 bei einer UNO) erzeugt wird. Sie sollte bei 10 Hz liegen. Statt eines UNO-Boards eignet sich auch ein MEGA(2560) oder ein Nano-Board.

Kalibrierungsziele

Du kannst fast alle klassischen AVR MCUs kalibrieren, die von ATTinyCore, MicroCore, MiniCore und MightyCore unterstützt werden. Außerdem funktioniert das Verfahren auch für einige MCUs, die von MegaCore unterstützt werden. Die Spannungskalibrierung wird jedoch nicht für den ATtiny2313(A) und den ATtiny4313 unterstützt, da beide keinen ADC haben. Auch für den ATtiny13 funktioniert sie nicht, weil die interne Referenzspannung nicht an den ADC weitergeleitet werden kann. Außerdem wird der ATtiny43U überhaupt nicht unterstützt, da ich beim Messen der Versorgungsspannung keine vernünftigen Werte erhalten konnte. Bitte sieh dir die Liste der unterstützten MCUs in der Readme-Datei der avrCalibrate-Bibliothek an.

Hardware-Konfiguration

Der einfachste Weg, die Serverplatine mit der Zielplatine zu verbinden, ist die Verwendung eines ICSP-Kabels, vorausgesetzt, deine Zielplatine hat einen ICSP-Anschluss. Damit werden die Masseleitung und die Signalleitungen(MISO, MOSI, SCK, RESET) der beiden Boards verbunden. Außerdem verbindet er die Versorgungsspannung des Serverboards mit der Versorgungsspannungsschiene des Zielboards. Wenn das Zielboard bereits von einer separaten Quelle mit Strom versorgt wird oder wenn für das Zielboard eine andere Versorgungsspannung als die 5 V vom Serverboard erwartet wird, muss die Vcc-Leitung des ICSP-Kabels herausgebrochen werden.

Wenn du dich fragst, welche Pins verbunden werden müssen, lass uns einen Blick auf den Stecker von oben werfen.

Wenn du kodierte Stecker hast, ist es klar, in welche Richtung du sie einstecken musst. Oft enthalten die Platinen jedoch nur 6 Stifte und es ist unklar, in welche Richtung du die Buchsen einstecken sollst. Achte in diesem Fall auf eine Markierung, oft eine „1“, die Pin 1 kennzeichnet. Bei Arduino-Boards ist Pin 1 immer in Richtung des USB-Anschlusses ausgerichtet. Im Zweifelsfall verwende ein Ohm-Meter, um den GND-Pin zu identifizieren. Auf jeden Fall ist es mir noch nicht gelungen, ein Board zu zerstören, weil ich den Stecker falsch herum eingesteckt habe.

Um das Leben zu vereinfachen, habe ich ein ICSP-Kabel mit heraus gebrochener Vcc- und RESET-Leitung gebaut (ähnlich dem, das dmjlambert in seinem Instructable beschrieben hat), das man auch zum Programmieren eines Zielchips oder zum Debuggen mit debugWIRE verwenden kann. Der Anschluss des Serverboards an das Target sieht dann wie folgt aus.

Sobald du die beiden Boards verbunden hast und das Target-Board mit Strom versorgt wird, solltest du die Versorgungsspannung des Targets mit einem Multimeter messen. Achte darauf, dass die Versorgungsspannung in der Nähe der Spannung liegt, die das Board später verwenden wird, denn die Kalibrierung ist von der Versorgungsspannung abhängig.

Software-Konfiguration

Nachdem du die avrCalibrate-Bibliothek (mit dem Bibliotheksmanager oder durch Herunterladen der Bibliothek von GitHub) zusammen mit der Vcc-Bibliothek installiert hast, musst du die Kalibrierungsprogramme hochladen, die im Ordner extras gespeichert sind:

  1. Korrigiere den Wert der Kompilierzeitkonstante TRUEMILLIVOLT im Sketch calibTarget im Ordner extras entsprechend der von dir gemessenen Versorgungsspannung für die Zielplatine.
  2. Wähle die richtige Ziel-MCU im Menü Tools aus, wähle als Taktfrequenz entweder 1 MHz oder 8 MHz (was auch immer du in der eingesetzten MCU verwenden wirst) und verwende als Taktquelle intern. Im Fall des ATtiny13 sind es 1,2 oder 9,6 MHz. Wenn du es mit einer 2-K-Byte-MCU zu tun hast, deaktiviere millis()/micros(). Und natürlich musst du den richtigen Programmierport einstellen.
  3. Lade den calibTarget-Sketch im Extras-Ordner auf deine Zielplatine hoch, indem du entweder einen separaten ISP-Programmierer verwendest oder ein Arduino-Board zu einem solchen Programmierer machst (Arduino als ISP).
  4. Lade den calibServer-Sketch auf ein UNO-Board (oder ähnliches) hoch.
  5. Öffne das Arduino-Monitorfenster.
  6. Drücke die Reset-Taste auf dem Server-Board.
  7. Jetzt wird die Zeile „Press any key to start calibration“ im Monitorfenster angezeigt. Drücke eine beliebige Taste und sende sie an das Server-Board, indem du auf das Feld „Senden“ klickst.
  8. Jetzt findet die Kalibrierung statt. Wie bereits erwähnt, ist die Kalibrierung temperaturabhängig und die Betriebstemperatur des Zielchips ändert sich nach dem Einschalten. Aus diesem Grund ist es ratsam, die Schritte 5-7 ein paar Mal zu wiederholen, bis sich die Werte stabilisieren.

Das Ergebnis des Kalibrierungsprozesses könnte wie folgt aussehen.

Zunächst wird der werkseitig festgelegte Wert des OSCCAL-Registers systematisch in Richtung 100.000 Ticks verändert und der nächstgelegene Wert dann im EEPROM gespeichert. Danach wird der korrekte Wert der internen Referenzspannung ermittelt, der ebenfalls im EEPROM gespeichert wird. Wenn der Vorgang auf einem Chip mit 2K Bytes durchgeführt wird, ist die Ausgabe etwas weniger ausführlich, um alles in den 2K Bytes Flash unterbringen zu können. Außerdem muss man bei diesen MCUs die Millis/Micros-Zeitmessung im Menü Tools deaktivieren. Beim ATtiny13, der nur 1K Byte Flash hat, ist die Ausgabe noch spärlicher (siehe unten).

In diesem Fall werden nur die Anfangs- und Endwerte von OSCCAL angegeben und es wird keine Kalibrierung der internen Referenzspannung durchgeführt, da letzteres auf diesem Chip nicht möglich ist.

Wenn die Dinge nicht nach Plan laufen, solltest du den Abschnitt zur Fehlerbehebung in der Readme-Datei konsultieren.

Verwendung der Kalibrierungswerte

Nachdem der Chip kalibriert wurde, können die Werte in der Setup-Funktion eines Sketches verwendet werden, indem die init-Methode der avrCalibrate-Bibliothek wie folgt aufgerufen wird.

#include <avrCalibrate.h>

void setup ()
{
  avrCalibrate::init();
  ...
} 

Die init-Methode holt den OSCCAL- und den internen Referenzspannungswert aus dem EEPROM und setzt das OSCCAL-Register bzw. eine interne Kalibrierungsvariable. Dies funktioniert jedoch nur, wenn die EESAVE-Sicherung gesetzt wurde, die das EEPROM vor dem Löschen schützt, wenn der Flash-Speicher neu programmiert wird. Du kannst diese Sicherung entweder mit einem Fuse Programmer setzen oder indem du EEPROM retained im Menü Tools auswählst und dann Burn bootloader ausführst.

Wenn du die Kalibrierungswerte nur für einen Chip verwenden willst, kannst du, anstatt mit Fuses herumzuspielen, die init-Methode mit den entsprechenden Kalibrierungswerten aufrufen, die während des Kalibrierungsprozesses angezeigt wurden. Der erste Parameter ist der OSCCAL-Wert und der zweite ist die interne Referenzspannung in Millivolt, wie im nächsten Sketch.

void einrichten ()
{
  avrCalibrate::init(OxCE, 1090);
  ...
} 

Wenn du das OSCCAL-Register nicht ändern willst, verwende die Konstante NOOSCCAL. Wenn du die Referenzspannung nicht einstellen willst, dann verwende die Konstante NOVOLT.

Theorie

Der Kalibrierungsprozess ist kein Hexenwerk. Aber vielleicht interessiert es dich, was hinter den Kulissen passiert, damit du eine Vorstellung davon bekommst, wie sehr du dem ganzen Verfahren vertrauen kannst.

Kalibrierung des RC-Oszillator

Wie bereits erwähnt, liegt die Werkskalibrierung des RC-Oszillators je nach MCU-Typ garantiert innerhalb von ±3 % oder ±10 %. Dies gilt jedoch für eine feste Temperatur und Versorgungsspannung. Wenn du dir die Schwankungen ansiehst, die durch Temperatur und Versorgungsspannung verursacht werden, kann es noch schlimmer werden (siehe Anwendungshinweis AVR053):

Wie du sehen kannst, kann die Taktfrequenz (nach der Kalibrierung auf 8 MHz bei Raumtemperatur mit 5 V) tatsächlich zwischen 6,7 MHz (bei 85° C mit 2,7 V Versorgungsspannung) und 8,4 MHz (bei -40° C mit 5,5 V Versorgungsspannung) schwanken. Das sind mehr als ±16 % in Bezug auf die Nennfrequenz von 8 MHz.

Mit anderen Worten: Das Versprechen, die Genauigkeit auf weniger als 1 % zu senken, gilt nur für eine feste Temperatur und Spannung. Wenn man sich die Frequenzkurve auf der Grundlage der OSCCAL-Werte (bei fester Temperatur und Versorgungsspannung) aus derselben Application Note ansieht, scheint eine bessere Genauigkeit zu erwarten zu sein.

Im Bereich um 8 MHz beträgt jeder Schritt etwa 0,05 MHz (oder 0,6 % von 8 MHz). In dem Bereich mit der höchsten Frequenz beträgt jeder Schritt etwa 0,1 MHz (oder 1,2 % der Nennfrequenz). Das scheint darauf hinzudeuten, dass man in der Lage sein sollte, einen Wert mit einem Fehler von weniger als 0,6 % zu finden. Die Dinge sind jedoch nicht so einfach. Bei der Messung der Taktfrequenz über einige Minuten hinweg habe ich bei einigen Chips eine Schwankung der Taktfrequenz von bis zu ±0,5 % festgestellt. Mit anderen Worten: Ein Fehler von 1,1 % im schlimmsten Fall scheint unvermeidlich.

Der allgemeine Ansatz zur Kalibrierung des OSCCAL-Wertes besteht darin, eine genaue externe Frequenz zu verwenden. In unserem Fall wird ein 10-Hz-Signal auf einem UNO oder einem ähnlichen Board erzeugt. In den Fällen, die ich erlebt habe, war die Genauigkeit immer besser als 0,1 %. Es kann sich aber lohnen, das zu überprüfen, bevor du mit dem Kalibrierungsvorgang beginnst. Wenn die Abweichung größer als 0,1 % ist, kannst du die Kompilierzeitkonstante TRUETICKS entsprechend anpassen.

Der calibTarget-Sketch zählt einfach die Anzahl der Ticks zwischen zwei fallenden Flanken des 10-Hz-Signals (geteilt durch 8, wenn 8 MHz ausgewählt wurde). Das heißt, wir wollen einen OSCCAL-Wert finden, der so nah wie möglich an 100.000 liegt,

Das Standard-Kalibrierungsverfahren von Microchip, für das du Atmel Studio installieren und einen der Microchip AVR-Programmierer verwenden müsstest, verwendet eine binäre Suche über die möglichen OSCCAL-Werte (siehe AVR053). Dadurch erhältst du eine Obergrenze von 8 Suchschritten plus 4 zusätzliche Vergleiche, um das zu berücksichtigen, was Microchip ein pseudomonotones Verhalten des OSCCAL-Wertes nennt. Das bedeutet, dass sich die Frequenz nicht streng monoton mit dem OSCCAL-Wert ändert. Jeder zweite Schritt ist jedoch garantiert höher oder niedriger.

Ich habe mich dafür entschieden, ausgehend vom Werkskalibrierungswert linear nach dem optimalen Wert zu suchen, was bedeutet, dass in der Regel 6 (bei einer Abweichung von 3 %) und nicht mehr als 18 Schritte (bei einer Abweichung von 10 %) ausreichend sind.

Der endgültige Wert wird im EEPROM bei E2END gespeichert. Außerdem wird das Byte an der Adresse E2END-1 auf Null gesetzt, wenn der Kalibrierungsprozess erfolgreich war.

Kalibrierung der internen Referenzspannung

Die Kalibrierung der internen Referenzspannung ist viel einfacher. Allerdings ist sie auch hier von der Temperatur und der Versorgungsspannung abhängig. Ein Beispieldiagramm für den ATmega328P ist unten abgebildet.

Die Kalibrierung erfolgt durch Schätzung der Versorgungsspannung anhand der nominalen internen Referenzspannung von 1,1 V. Mithilfe des mitgelieferten TRUEMILLIVOLT-Wertes kann man dann leicht den wahren internen Referenzwert schätzen, der im EEPROM gespeichert ist (zwei Bytes ab E2END-3. Dieser kann später zum Messen der Versorgungsspannung mit der Klassenmethode Vcc::measure aus der Vcc-Bibliothek verwendet werden. Wenn du willst, kannst du auch jeden mit analogRead gemessenen Wert in einen Spannungswert umwandeln. Die Aussage, dass die nominale interne Referenzspannung 1,1 V beträgt, stimmt nur teilweise. Es gibt ein paar ältere MCUs, die eine andere interne Referenzspannung haben (siehe Vcc.h).

Views: 51