Der I2C-Bus ist als Zweidrahtverbindung zwischen einem Master (Controller) und an ihn angeschlossene Sensoren oder IC-Bausteine (Slaves) für kurze Distanzen konzipiert worden. Nur der Master steuert die Verbindung zwischen ihm und den Slaves.
An einer Kommunikation können auch mehrere Master und bis zu 128 Slaves beteiligt sein. Die beiden dazu notwendigen Datenleitungen, neben den Versorgungsspannungsleitungen, bezeichnen wir mit SDA (Datenleitung) und SCL (Taktleitung); SDA und SCL bilden den Datenbus.
Die Daten- und Taktleitung sind open drain, was so viel heißt, die angeschlossenen elektronischen Bauteile können ihren Ausgang auf LOW legen, aber nicht aktiv auf HIGH. Letzteres erfolgt über Pull-up Widerstände RPU, die in beiden Leitungen einmal eingebaut sind und deren Wert irgendwo zwischen 1kOhm und 10kOhm liegen kann.
Nur Master können Slaves ansprechen, umgekehrt geht das nicht - also eine klare Hierarchie. Um eine Kommunikation zu beginnen, muss der Master den Bus übernehmen und die Adresse des Slaves angeben, mit dem er Daten austauschen möchte.
Am häufigsten werden für die Adressierung 7 Bit verwendet (es gibt auch eine 10 Bit Variante). Damit stehen insgesamt 2^7 = 128 Adressen für 128 Geräte (Slaves) zur Verfügung. Bei der Übertragung einer 7 Bit Adresse werden immer 8 Bit gesendet. Das 8. Bit (LSB) informiert den Slave, ob der Master zum Slave überträgt (write) oder vom Slave zum Master etwas gesendet werden soll (read).
0 bedeutet, der Master überträgt an den Slave (write) 1 bedeutet, der Master liest vom Slave (read)
Der Master teilt dem Slave mit, ob er Daten senden oder empfangen möchte und danach werden die Daten (entweder vom Master oder vom Slave) auf den Bus gelegt. Mit Abschluss des Lese-/Schreibvorgangs gibt der Master den Bus wieder frei.
Die Start- und Stoppsequenzen sind die einzigen Vorgänge, bei denen die SDA-Leitung von HIGH auf LOW (Start) bzw. LOW auf HIGH (Stopp) gelegt werden darf, während gleichzeitig die SCL-Leitung auf HIGH liegt.
Daten werden in Sequenzen von 8 Bit übertragen. Die Bits werden auf die SDA Leitung gelegt (MSB zuerst). Auf SCL wird eine Impulsfolge gelegt; nach jeweils 8 übertragenen Bit sendet das Empfangsgerät ein LOW-ACK-Bit (Acknowledge LOW) zurück und zeigt damit an, dass es weitere 8 Bit empfangen kann. Wird ein HIGH-ACK-Bit zurückgesandt, beendet der Master die Übertragung und sendet eine Stopp-Sequenz.
Die Adressierung eines Slaves
Die Adresse eines Slaves baut sich aus sieben Bit auf, die der Hersteller eines I2C-Bauteils in seinem Datenblatt veröffentlicht. Von diesen sieben Bit sind häufig die höchstwertigen fest vorgegeben und die niederwertigen variabel und durch den Anwender einstellbar.
Beispiel
Als I2C-Baustein nehmen wir den LED Treiberbaustein TLC59116. Im Datenblatt des Herstellers wird seine Adresse (device address) auf S. 23 beschrieben. Von den sieben Adressbits sind die ersten drei fest vorgegeben, während sich die letzten vier über Hardwareeinstellungen individuell durch den Nutzer einstellen lassen. In diesem Beispiel werden die Pins [A3:A0] hardwaremäßig auf 0 gelegt. Die sich daraus ergebende Slaveadresse zeigt Abb. 4.
Reihenfolge der Befehlssequenzen bei einer I2C-Verbindung
Die Kontaktaufnahme eines Masters (in diesem Beispiel ein Arduino UNO) mit einem Slave (hier: TLC59116) über einen I2C-Bus wird ebenfalls im Datenblatt des entsprechenden Bauteils beschrieben (Application Notes oder Application Information). Dort wird beschrieben, in welcher Reihenfolge in spezifische Register des Bauteils geschrieben oder aus ihnen etwas ausgelesen wird.
Für den TLC59116 sind die Anwendungsinformationen auf Seite 26ff beschrieben und können dort nachgeschlagen werden. Um in ein bestimmtes Register etwas hineinzuschreiben, wird der Vorgang mit einer Startsequenz (S) und der Angabe der Slaveadresse (wer wird angeschrieben?) gestartet. Es handelt sich um einen Schreibvorgang, deshalb wird das R/W-Flag auf 0 gesetzt. Die Slaveadresse lautet damit:
bei einem Schreibvorgang und
bei einem Lesevorgang.
Adressierung - 7-Bit oder 8-Bit?
Arbeitet man mit einem Arduino-UNO und der I2C-Bibliothek Wire.h, dann errechnet sich die korrekte Slaveadresse dadurch, dass die 7-Bit Adresse (1100_000 ohne das R/W Bit) des Slave um eine Position nach rechts (in Richtung des R/W Bits) verschoben wird (Abb. 6).
Wie man Abb. 6 entnehmen kann, wird aus der Slaveadresse 0xC0 (dezimal: 192) durch die Verschiebung 0x60 (dezimal: 96).
Bei der Programmiersoftware ist zu prüfen, ob bei einer I2C-Adressierung die 7-Bit Adresse ohne das R/W-Bit oder die 8-Bit Adresse mit R/W-Bit gemeint ist und dann entsprechend dem oben Gesagten zu verfahren.
Experiment 1 - LED einschalten | |
Material |
|
Aufgaben |
|
Das Programm LED_TLC59116_1.ino
Wie arbeitet das Programm LED_TLC59116_1.ino?
In der Methode loop() gibt es drei "neue" Befehle und einen in der Methode setup().Was sie bewirken, soll die kurze Übersicht zeigen.
Wire.begin(optional: address)
Initiiert die Wire-Bibliothek und - falls die 7-Bit Slaveadresse angegeben wird - wird sie auf dem I2C-Bus als Slave, bei fehlender Adresse als Master gesehen.
Parameter
address 7-Bit Slaveadresse (optional); wenn nicht angegeben, Verbindung als Master.
In der Methode loop() werden drei Funktionen aus Wire.h aufgerufen. Gestartet wird mit
<>·Wire.beginTransmission(22);
Wire.beginTransmission(address)
Startet eine Übertragung zum I2C Slave mit der angegebenen Adresse (address). Anschließend werden Bytes mit der Funktion write() übertragen und mit der Funktion endTransmission() abgeschlossen.
Parameter
address 7-Bit Adresse des Slave-Device.
Die Adresse 96 ist hier dem Datenblatt zum TLC59116 des Herstellers entnommen. Die Syntax der Funktion
Wire.write()
zeigt das Programm LED_TLC59116.ino.
Wire.write()
Es werden Daten vom Master an den Slave übertragen. Voraussetzung ist, dass vorher Wire.beginTransmission gestartet und die Übertragung mit Wire.endTransmission() beendet wird.
Syntax
Wire.write(value)
Wire.write(string)
Wire.write(data, length)
Parameter
value ein Wert, der als einfaches Byte gesendet wird
string ein String, der als Serie von Bytes übertragen wird
data ein Datenfeld, das als Bytes übertragen wird
Rückgabewert Anzahl der geschriebenen Bytes
Wire.endTransmission()
Beendet eine Übertragung an einen Slave, die mit beginTransmission() vorher gestartet wurde.
Argumente (optional)
true sendet nach der Übertragung eine Stopp-Mitteilung und gibt den i2c Bus wieder frei
false sendet eine Neustart-Meldung nach der Übertragung. Der Bus wird nicht freigegeben und lässt eine erneute Übertragung durch den Master zu. Andere Mastergeräte können in dieser Zeit keine Übertragungen vornehmen.
Syntax
Wire.endTransmission()
Wire.endTransmission(stop)
Parameter
stop boolean
TRUE sendet Stoppsequen und gibt den Bus nach der Übertragung frei.
FALSE löst Neustart aus und hält die Verbindung aktiv.
Rückgabewert Byte, gibt Hinweis auf den Status der Übertragung
0 - alles ok
1 - Daten zu lang; passen nicht in den Übertragungspuffer
2 - NACK erhalten bei Übertragung der Adresse
3 - NACK erhalten bei Übertragung von Daten
4 - sonstiger Fehler
Abschließend schauen wir uns die Zeitdiagramme der einzelnen Programmschritte an. In der ersten Übertragungssequenz (Programmzeilen 10 - 13) werden die Grundeinstellungen vorgenommen; in der zweiten (Programmzeilen 15 - 21) werden die Ausgänge des TLC59116 Treiberbausteins so modifiziert, dass LED1 auf dem Modulboard eingeschaltet wird. Bis dahin ist das sicherlich nicht spektkulär, aber mit diesem Wissen lassen sich zukünftig mindestens 16 LEDs unabhängig voneinander steuern. Das Zeitdiagramm für diesen kleinen Versuchsaufbau zeigen die folgenden Diagramme (aufgenommen mit PicoScope 2205).