IO-Register
Worum geht's?
BearbeitenNeben Prozessor und Speicher verfügen Microcontroller der AVR-Familie über eine Reihe zusätzlicher auf dem Chip integrierter Komponenten, wie Timer, deren Verhalten durch die Programmierung das Controllers beeinflusst werden kann. Diese integrierten Komponenten werden auch als Funktionseinheiten bezeichnet.
Der Zugriff auf diese Funktionseinheiten findet mit Hilfe sogenannter Ein-/Ausgabe Register über eine einheitliche Schnittstelle statt.
Achtung! Der Begriff Register ist mehrfach besetzt. In diesem Kapitel wird es nicht um die Rechenregister der CPU gehen, sondern ausschließlich um Ein-/Ausgabe Register.
Das Datenblatt [M328p] unterscheidet bei der Bezeichnung von Ein-/Ausgabe Registern zwischen I/O Registern und Extended I/O Registern, da es für die Manipulation der erstgenannten Register spezielle Maschinenbefehle gibt.
Für die C-Programmierung spielt dieser Unterschied keine Rolle, da hier auf einer höheren Abstraktionsebene gearbeitet wird. Der Begriff Ein-/Ausgabe Register oder auch kurz E/A Register ist in diesem Kapitel stets so verstehen, dass er beide Varianten des Datenblatts umfasst.Die Zahl der Funktionseinheiten und damit auch die Zahl der Ein-/Ausgabe Register hängt vom Typ des Microcontrollers ab. Für einen AtMega328p stehen etwa 90 Ein-/Ausgabe Register bereit. Je nach Microcontroller können mehr oder weniger Funktionseinheiten und damit auch mehr oder weniger Ein-/Ausgabe Register zur Verfügung stehen.
In diesem Kapitel kannst Du die folgenden Dinge lernen:
- Informationen im Datenblatt finden
- IO-Register lesen
- IO-Register schreiben
- Besonderheiten beim Umgang mit I/O Registern beachten
Syntax
BearbeitenDie Ein-/Ausgabe Register eines Microcontrollers der AVR-Familie sind in einen festen Bereich des Hauptspeichers eingeblendet / gemappt. Bei einem AtMega328p liegt dieser Adressbereich zwischen 0x20 und 0x0FF. Der gewöhnliche Speicher beginnt dort erst ab der Adresse 0x0100.
Zugriff
BearbeitenPrinzipiell ist es möglich direkt mit der Speicheradresse eines E/A Registers zu arbeiten. Im Kapitel Quickstart Linux haben wir ein Programm übersetzt, das die Leuchtdiode L zum Blinken gebracht hat. Wenn Du einen Blick auf den Stand des Quellcodes wirfst, nachdem er durch den Präprozessor gelaufen ist, kannst Du sehen, dass der Compiler über die beiden Adressen 0x23 und 0x24 auf die beteiligten E/A Register zugreift.
void setup()
{
sbi((*(volatile uint8_t *)((0x04) + 0x20)), 5);
}
void loop()
{
sbi((*(volatile uint8_t *)((0x03) + 0x20)), 5);
_delay_ms(500);
}
Dieser Weg E/A Register direkt über Angabe der zugehörigen Speicheradresse anzusprechen ist nicht nur beim Schreiben des Quellcodes schmerzhaft, er macht auch späteres Lesen des Quelltexts und das Portieren auf einen anderen Microconotroller der AVR-Familie zu einem zeitaufwändigen und fehleranfälligen Unterfangen.
Eine geschicktere Möglichkeit auf E/A Register zuzugreifen bietet die Header Datei <avr/io.h> der AVR Libc. Abhängig von der bei der Übersetzung mit dem Schalter -mmcu angegebenen Microcontroller Variante stellt sie eine Reihe von Präprozessor Makros bereit, über die E/A Register über einen symbolischen Namen angesprochen werden können. Die symbolischen Namen, über die die E/A Register angesprochen werden können, folgt der Benennung im zugehörigen Datenblatt.
Zum Vergleich hier noch einmal der gleiche Code-Schnipsel. Diesmal unter Verwendung der symbolischen Namen.
void setup()
{
sbi(DDRB, DDB5);
}
void loop()
{
sbi(PINB, PINB5);
_delay_ms(500);
}
Bitmanipulation
BearbeitenAuch für die Manipulation einzelner Bits eines E/A Registers stellt die Header Datei <avr/io.h> eine Reihe von Makros bereit, über die sie mit den Bezeichnungen des Datenblatts angegeben werden können. Die zugehörigen Makros expandieren dabei zu der Position des entsprechenden Bits im jeweiligen E/A Register.
Achtung! Eine Überprüfung, ob die symbolischen Namen von E/A Register und Bit zusammen passen findet nicht statt. Sowohl X als auch Y expandieren zum selben Wert Z. Wenn Du sowohl Dich selbst, als auch andere Leser verwirren möchtest, kannst Du den Quellcode also auch so schreiben.
TODO: Beispiel
Weder für den Compiler noch für das fertige Programm macht es einen Unterschied.
Im eigenen Interesse solltest Du allerdings auf solche Verwirrspiele verzichten.Besonderheiten
BearbeitenAuf Ein-/Ausgabe Register kann auf dem gleichen Weg zugegriffen werden, wie auf gewöhnlichen Speicher. Dennoch sind beim Zugriff auf E/A Register eine Reihe von Unterschieden zu beachten.
Die meisten E/A Register können sowohl gelesen, als auch geschrieben werden, aber das muss nicht zwingend so sein. Genaue Auskunft darüber, in welcher Art und Weise auf ein Register zugegriffen werden kann, findet sich in der Beschreibung des jeweiligen Registers im Datenblatt.
Die Speicheradressen der Ein-/Ausgabe Register sind nicht durchlaufend vergeben. An die Speicheradresse reservierter E/A Register sollte nicht geschrieben werden.[1]
Einige E/A Register enthalten reservierte Bits. Reservierte Bits sollten beim Schreiben immer auf den Wert 0 gesetzt werden.[2]
Semantik
BearbeitenDie Syntax mit der in einem Programm auf Ein-/Ausgabe Register zugegriffen werden kann, unterscheidet sich in C nicht von der Syntax, die für den Zugriff auf gewöhnlichen Speicher verwendet wird. Die Semantik, d.h. die Bedeutung von Zugriffen auf gewöhnlichen Speicher und E/A Register unterscheidet sich hingegen gravierend.
Gewöhnlicher Speicher
BearbeitenDer Sinn und Zweck von gewöhnlicher Speicher ist, es Werte für die spätere Verwendung zwischen zu speichern. Eine Variable, in die ein bestimmter Wert geschrieben wird, behält den Wert so lange bei, bis ein neuer Wert in die Variable geschrieben wird. Das Zurücklesen eines in einer Variable liefert stets den Wert, der zuletzt geschrieben wurde. Auch bei mehrmaligem Zurücklesen.
E/A Register
BearbeitenDer Sinn und Zweck von E/A Registern ist es, das Verhalten des Microcontrollers zu beeinflussen und Informationen über den aktuellen Zustand des Microcontrollers abzufragen.
Das Schreiben in ein E/A Register dient nicht dem Zweck, einen Wert für die spätere Nutzung zwischen zu speichern, sondern den Microcontroller zu steuern, d.h. Parameter vorgeben und Aktionen auszulösen. Es gibt keine Garantie, dass ein geschriebener der Wert, beim zurück lesen von der selben Speicheradresse den geschriebenen Wert zurückliefert und in vielen Fällen wird er es auch nicht sein.
Das Lesen eines E/A Registers dient somit nicht dem Zweck, einen zwischengespeicherten Wert zurück zu lesen, sondern dazu, den aktuellen Status einzelner Komponenten des Microcontrollers abzufragen. Abhängig von Ausführungsstatus der jeweiligen Komponente kann mehrmaliges zurücklesen des selben E/A Registers unterschiedliche Werte zurückliefern.
Die Makros der Header Datei <avr/io.h> qualifizieren die symbolischen Namen, über die die E/A Register angesprochen werden können aus diesem Grund als volatile. Der Compiler ist damit gezwungen Werte aus E/A Registern bei jedem lesenden Zugriff tatsächlich von der jeweiligen Speicheradresse zu lesen. Kettenzuweisungen an E/A Register sind aus diesem Grund keine besonders gute Idee.
Rückschau und Ausblick
BearbeitenGlückwunsch! Mit Abschluss dieses Kapitels hast Du Dir alle Grundlagen angeeignet, die Du benötigst um erfolgreich mit E/A Registern zu arbeiten.
Dabei hast Du Dich nicht nur mit dem Aufbau des Datenblatts vertraut gemacht. und bist somit in der Lage, gezielt die Informationen zu einer bestimmten Funktionseinheit und die Beschreibung der zugehörigen Register ausfindig zu machen.
Zudem kennst Du auch die Gemeinsamkeiten und Unterschiede von gewöhnlichem Speicher und E/A Registern. Im einzelnen sind Dir dabei die folgenden Unterschiede bekannt:
- Schreiben in gewöhnlichen Speicher dient dem Zweck einen Wert zu speichern
- Schreiben in E/A Register dient dem Zweck um das Verhalten des Microcontrollers zu steuern
- Lesen von gewöhnlichem Speicher dient dem Zweck einen gespeicherten Wert zurück zu lesen
- Lesen von E/A Registern dient dem Zweck den Status des Microcontrollers abzufragen
Du bist mit den Besonderheiten vertraut, die bei der Arbeit mit E/A Registern beachtet werden sollten.
Beim Schreiben von Werten in E/A Registern beachtest Du die folgenden Dinge:
- in reservierte Register sollten nicht geschrieben werden
- in reservierte Bits sollte immer der Wert 0 geschrieben werden
- Kettenzuweisungen sollten vermieden werden
Fußnoten
Bearbeiten