Der I2C-Bus
bei Atmel auch "Two-Wired Serial Interface" kurz "TWI" genannt

Ein Artikel von Alexander Starke

Das TWI ist begründet durch seinen Aufbau ideal auf typische Mikrocontroller Applikationen zugeschnitten. Durch seinen 7 Bit breiten Adressraum können bis zu 128 (27 = 12 Geräte miteinander verschalten werden. Im Gegensatz zum SPI werden nur zwei Busleitungen benötigt. Eine dient der Bereitstellung des Taktes (SCL) und die andere dem Datentransport (SDA). Die einzige zusätzlich benötigt Hardware besteht aus zwei Pull-Up Widerständen, welche von jeweils einer Busleitung gegen Vcc (5V) geschalten werden. Da alle Bustreiber mit offenem Kollektor bzw. Drain am Bus anliegen, ergibt sich eine logische UND-Verknüpfung. D.h., sobald irgendein Gerät auf einer der Busleitungen Low-Pegel anlegt, liegt automatisch die gesamte Busleitung auf Low. Der BUS hat nur High-Pegel, wenn alle angeschlossenen Geräte auch High-Pegel an ihrer entsprechenden Schnittstelle haben.
Genau wie beim SPI initiiert auch beim TWI der Master den Datentransfer und beendet selbigen auch wieder. Gestartet wird eine Transmission durch eine Start-Bedingung und entsprechend beendet durch eine Stop-Bedingung. Während einer Transmission gilt der Bus als "busy" (beschäftigt) und kein anderer Master darf versuchen Kontroller über ihn zu erlangen. Einzige Ausnahme bildet hier der Fall, dass vor einer Stop-Bedingung durch den gerade aktiven Master noch eine zusätzliche Start-Bedingung auf den Bus gegeben wird. Dieser Fall tritt normalerweise dann ein, wenn der Master noch weitere Daten zu versenden hat und nicht die Kontrolle über den Bus verlieren möchte. Nach solch einem wiederholten Start (Repeated Start) ist der Bus wieder beschäftigt, bis zum nächsten Stop.
Start- und Stop-Bedingungen werden signalisiert, indem der Pegel der SDA-Leitung wechselt, während SCL High-Pegel hat.
Alle Adresspakete auf dem TWI Bus haben eine Länge von 9 Bit. Davon beinhalten 7 Bit wie bereits eingangs erwähnt die Adresse der angesprochenen Komponente. Zusätzlich gibt es noch ein Bit, dass darüber bestimmt, ob ein Lese- oder ein Schreibzugriff durchgeführt werden soll (R/W=1 -> Lesen;
RW=0 -> Schreiben). Das 9 Bit dient der Bestätigung. Wenn ein Slave bemerkt, dass er angesprochen wird, so bestätigt er dies, indem er mit dem 9.
Taktzyklus (ACK) von SCL SDA auf Low-Pegel legt. Sollte der angesprochene Slave aus irgendwelchen Gründen nicht antworten können, so sollte SDA auf H-Pegel bleiben. Der Master hat dann die Wahl, ob er ein Stop sendet oder einen wiederholten Start durchführt.

SLA +R --> Adresspaket mit einer Slave-Adresse und einem Lese-Bit
SLA +W --> Adresspaket mit einer Slave-Adresse und einem Schreib-Bit


Das höchstwertige Bit wird prinzipiell zuerst übertragen (MSB Most Significant Bit). Die Slave-Adressen können durch den Anwender frei gewählt werden, nur 0000 000 ist reserviert, hiermit werden alle Slaves angesprochen. Wird ein solcher Zugriff durchgeführt, so sollten alle Slaves im ACK-Zyklus SDA auf L-Pegel legen.
Benutzt wird diese Aktion, wenn der Master die selben Daten an mehrere Slaves senden möchte. Sinn macht die Verwendung nur in Verbindung mit dem Schreib-Bit. Ein setzen des Lese-Bits hätte zur Folge, dass verschiedene Slaves ja verschiedene Daten auf den Bus stellen könnten, was zu einem Durcheinander führen würde. Wird das Schreib-Bit gesetzt, so setzen im ACK-Zyklus alle Slaves SDA auf L-Pegel, welche den allgemeinen Adressaufruf erhalten und ausgewertet haben (also die nicht beschäftigt waren). Die folgenden Datenpakete werden dann von allen Slaves empfangen, welche SDA auf L-Pegel gelegt hatten.
Alle Datenpakete auf dem TWI-Bus haben analog zu den Adresspaketen 9 Bit. Hiervon sind 8 Datenbits. Das 9. dient der Bestätigung. Während einer Datenübertragung ist es Aufgabe des Masters, den Takt, das Start- und das Stopzeichen bereitzustellen. Aufgabe des Empfängers ist die Bestätigung der erhaltenen Daten, indem er die SDA-Leitung während des 9. SCL-Zyklus auf L-Pegel legt. Dieses wird als ACK bezeichnet (Acknowledge). Bleibt SDA auf H-Pegel, so wird dem Sender signalisiert, dass die gesendeten Daten nicht empfangen wurden (NACK). Das MSB wird zuerst übertragen.
Wenn man nun Adress- und Datenpakete kombiniert, hat man schon eine fertige Transmission. Diese besteht aus:

START --> SLA R/W --> ein oder mehr Datenpakete --> STOP

Ein START gefolgt von einem STOP ist nicht zulässig. Wenn der Takt des Masters für den Slave zu schnell ist oder er noch mehr Zeit zur Bearbeitung braucht, so kann er SCL einfach länger auf L-Pegel halten. Die Verlängerung der L-Phase von SCL hat allerdings keinen Einfluss auf die Länge der H-Phase, da diese vom Master zur Verfügung gestellt wird. Dadurch kann es allerdings zu einer Reduzierung des Datentransfers kommen.

Multi-Master-Bussysteme

Das TWI-Bussystem erlaubt den Multi-Master Betrieb. Es wurden spezielle Vorkehrungen getroffen, so dass auch wenn mehrere Master zur selben Zeit eine Transmission beginnen wollen keine Probleme auftreten und der Bus normal funktioniert. Nur die zwei folgenden Probleme sollten beachtet werden:

1. Es ist Sache des Anwenders, seine Algorithmen so auszulegen, dass in diesem Fall nur ein Master seine Transmission fortsetzt. Alle anderen Master sollten ihre Transmission sofort abbrechen. Diesen Auswahlprozess zwischen den Mastern nennt man Arbitrierung (Entscheidung). Wenn ein Master bemerkt, dass er den Entscheidungsprozess (die Arbitrierung) verloren hat, sollte er sofort in den Slave-Modus gehen, da es sein kann, dass der Master welcher den Prozess gewonnen hat ihn adressieren will. Die Tatsache, dass mehrere Master versucht hatten, eine Übertragung zu starten, sollte für die Slaves nicht feststellbar sein, die Daten auf dem Bus müssen nicht beschädigt sein.

2. Da verschiedene Master mit verschiedenen Taktfrequenzen auf dem Bus arbeiten könnten, ist eine Festlegung zu treffen, wie man diese synchronisiert. Dieses erleichtert auch den Arbitrierungsprozess.
Diese Lösung dieses Problems stellt die schon oben angesprochene UND-Verknüpfung aller Komponenten auf dem Bus dar. So werden alle seriellen Taktraten der einzelnen Master UND verknüpft. Somit ergibt sich ein High-Pegel entsprechend dem des Masters mit dem kürzesten H-Pegel, der Low-Pegel ist durch den Master mit der geringsten Taktrate gegeben.
Da der Multi-Master Betrieb für meine Anwendung keinen Belang hat, werde ich hier nicht näher darauf eingehen.

Aufbau des TWI

Der SCL- und der SDA-Pin stellen die Schnittstelle des einzelnen MC mit dem Bus dar. Zusätzlich ist intern vorgesehen, dass Spannungsspitzen, welche kürzer als 50ns sind, herausgefiltert werden. Es besteht bei manchen Konfigurationen die Möglichkeit, die internen Pull-Up Widerstände zu verwenden, dies kann die Verwendung der externen überflüssig machen.
Zusätzlich verfügt der ATmega über einen Bitraten-Generator, welcher im Masterbetrieb das entsprechende Signal auf SCL gibt. Die Taktrate wird durch das TWBR (TWI Bit Rate Register) und TWSR (TWI Status Register) festgelegt. Zu beachten ist, dass die interne Taktfrequenz der einzelnen Slaves mindestens 16 mal höher als die Taktrate des Bus ist. Diese ergibt sich nach folgender Formel:



TWBR - TWI Bit Rate Register
TWPS - TWI Prescaler Bits im TWI Status Register


Des weiteren verfügt der MC über je ein Daten- und Adressschieberegister, einen START/STOP Controller und die Arbitrierungslogik. Das TWDR (TWI
Data Register) beinhaltet entweder die Adresse und Daten welche gesendet werden sollen oder die empfangene Adresse samt Daten. Zusätzlich existiert noch ein Register, welches das (N)ACK-Bit enthält, das aber nicht direkt zugänglich ist. Jedoch kann es im Empfangsmodus durch verändern von TWCR (TWI Control Register) bzw. im Empfangsmodus durch verändern von TWSR manipuliert werden.
Der START/STOP Controller ist wie sein Name bereits sagt, dafür verantwortlich, den anderen Teilnehmern am Bus mitzuteilen, dass der entsprechende Master eine Übertragung plant bzw. beendet. Zusätzlich führt er auch den bereits erwähnten REPEATED START durch. Eine Besonderheit ist, dass er solche START/STOP-Zeichen auf dem Bus sogar detektieren kann, wenn sich der Controller in einem der Sleep-Modi befindet. Er kann somit "aufgeweckt" werden, wenn er von einem Master adressiert wird.
Ein weiterer Bestandteil des TWI ist die "Adress Match Unit". Diese überwacht, ob die empfangenen Adress-Bytes mit denen im TWAR (TWI Adress Register) übereinstimmen. Wenn TWGCE (TWI General Call Recognition Enable) in TWAR gesetzt ist, werden alle eingehenden Adress-Bytes zusätzlich noch daraufhin überprüft, ob eine allgemeine Ruf (0000 000) vorliegt. Sollte eine Übereinstimmung vorliegen, wird die Kontrolleinheit informiert, eventuelle Korrekturmaßnahmen können durchgeführt werden. Die TWI-Logik kann nun die Anforderung bestätigen, je nach dem welche Einstellungen in TWCR getroffen wurden. Wie bereits oben angesprochen wurde, arbeitet die Adress-Vergleichs-Logik sogar, wenn sich der MC in einem der Sleep-Modi befindet. Man kann den MC somit per TWI reaktivieren. Einzige Ausnahme bildet der Fall, dass der Controller zuvor durch einen anderen Interrupt reaktiviert wurde. Danach geht die TWI-Logik sofort in den Leerlauf. Sollte das bei der vorgesehenen Problemstellung zu Problemen führen, bleibt nur der
Ausweg sämtliche anderen Interrupts in der Hinsicht zu sperren, dass sie den Controller nicht mehr reaktivieren können.
Die Kontrolleinheit des TWI beobachtet ständig den Bus und antwortet auf Anfragen entsprechend den Einstellungen in TWCR. Tritt ein Ereignis ein, auf welches die angesprochene Einheit reagieren soll, so wird automatisch TWINT (TWI Interrupt Flag) gesetzt. Im nächsten Taktzyklus wird dann TWSR aktualisiert, in ihm stet jetzt ein Code mit welchem das Ereignis spezifiziert werden kann. TWSR beinhaltet nur relevante Informationen, wenn TWINT gesetzt wird, andernfalls beinhaltet es bloß einen Statuscode, welcher aussagt, dass keine relevanten Informationen vorliegen. Solange TWINT gesetzt ist, wird SCL auf Low Pegel belassen. Dies gibt dem angesprochenen MC die Chance, alle Anwendungen erst zu beenden, bevor er sich der Transmission widmet. TWINT wird gesetzt wenn:

  • wenn das TWI START/REPEATED START gesendet hat
  • wenn das TWI SLA +R/W gesendet hat
  • wenn das TWI ein Adress-Byte gesendet hat
  • wenn das TWI seine "Vormacht" auf dem Bus verloren hat
  • wenn das TWI durch seine eigene Slave-Adresse bzw. einen allgemeinen Ruf (general call) adressiert wurde
  • wenn das TWI ein Datenbyte empfangen hat
  • wenn ein STOP oder REPEATED START empfangen wurde, während es immer noch als Slave angesprochen ist
  • wenn ein Busfehler durch einen illegalen START bzw. STOP aufgetreten ist


Benutzung des TWI

Das TWI ist wie bereits ausführlich dargestellt wurde, byte- bzw. interruptbasiert. Dadurch ist es der Anwendersoftware möglich, parallel zum Datenversand bzw. -empfang auf dem TWI Bus noch weitere Anwendungen (Operationen) auszuführen. Die Ausführung einer ISR ist allein durch das Setzen von TWIE (TWI Interrupt Enable) in TWCR bedingt (die Interrupts müssen natürlich auch global freigegeben sein). Es ist Sache des Anwenders, ob das Setzen von TWINT einen Interrupt üerursachen soll. Ist TWIE nicht gesetzt, so ist es dem Programm selbst überlassen, ständig TWINT zu prüfen, um sämtliche Ereignisse auf dem Bus mit zu bekommen.
Bei jedem Setzen von TWINT ist eine Operation auf dem Bus abgeschlossen worden und es wird eine Antwort erwartet. In diesem Fall beinhaltet TWSR einen Wert, welcher ein direktes Maß für den aktuellen Status des Bus ist. Die Software legt nun fest, welche Aktion mit dem nächsten Buszyklus durchgeführt werden soll, indem sie TWCR und TWDR entsprechend verändert. Im folgenden wird schrittweise ein Beispiel für den Ablauf einer Übertragung gegeben.

1. Zuerst muss vom Master ein START-Signal auf den Bus gegeben werden. Dies erfolgt durch Schreiben eines speziellen Wertes in TWCR. Nach Abschluss der Operation wird TWINT gesetzt. Die Logik wartet nun so lange, bis durch den Anwender das Flag wieder gelöscht wurde (durch
Schreiben einer '1'). Unmittelbar nach dem Löschen von TWINT beginnt die Logik damit das START-Signal zu senden.

Code:
TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN);                        //TWSTA = TWI START Condition Bit
2. Nach dem Senden des START wird sofort wieder TWINT in TWCR gesetzt. Zusätzlich beinhaltet TWSR jetzt den entsprechenden Status Code, welcher mitteilt, dass START erfolgreich gesendet wurde.

Code:
while  (!(TWCR & (1<<TWINT)));
3. Nachdem durch die Applikation TWSR daraufhin überprüft wurde, dass START erfolgreich gesendet wurde, kann es nun weitergehen. Im Fehlerfall könnte beispielsweise eine vom Anwender definierte Fehlerroutine greifen.
Nun muss SLA +W in TWDR geladen werden. Ist dies abgeschlossen, muss wiederum ein spezieller Wert in TWCR geschrieben werden, um der
TWI-Logik mitzuteilen, dass die Adresse und der Schreibbefehl aus TWDR gesendet werden können. Unmittelbar nachdem durch den Anwender dann TWINT in TWCR gelöscht wurde (Schreiben einer '1') sendet das TWI das Adresspaket.

Code:
    
    if ((TWSR & 0xF8) != START)
            ERROR();                                                                //Fehlerbehandlung
    TWDR = SLA_W;
    TWCR = (1<<TWINT) | (1<<TWEN);
4. Nach Abschluss der Sendung wird wiederum TWINT gesetzt in TWSR steht der entsprechende Statuscode, welcher über Erfolg bzw. Misserfolg der Sendung urteilt. In ihm ist auch das ACK-Bit des angesprochenen Slaves enthalten (oder auch nicht, was dann einen Fehler bedeuten würde).

Code:
    
    while (!(TWCR & (1<<TWINT)))
    ;
5. Nach der Prüfung von TWSR ob bei der Sendung keine Fehler aufgetreten sind, kann das Datenpaket in TWDR geladen werden. Erneut muss ein spezieller Wert in TWCR geschrieben werden, welcher der Logik sagt, dass ein Datenpaket aus TWDR versendet werden soll. Nach dem Löschen von TWINT wird dieses automatisch versendet.

Code:
    
    if ((TWSR & 0xF8) != MT_SLA_ACK)
    ERROR();
    TWDR = DATA;
    TWCR = (1<<TWINT) | (1<<TWEN);
6. Nachdem TWINT gesetzt wurde kann mit Hilfe von TWSR überprüft werden, ob das Datenpaket erfolgreich gesendet und vom angesprochenen Slave angenommen wurde (ACK-Bit).

Code:
    
    while (!(TWCR & (1<<TWINT)))
    ;
7. Nachdem bis hierhin alles funktioniert hat (angenommen), muss nun nur noch ein STOP gesendet werden. Dies erfolgt analog zu den obigen
Ausführungen durch Schreiben eines speziellen Wertes in TWCR. Nach dem Löschen von TWINT wird dieses gesendet. Allerdings wird danach TWINT nicht automatisch wieder gesetzt, wie es zuvor immer der Fall war.

Code:
    
    if ((TWSR & 0xF8) != MT_DATA_ACK)
    ERROR();
    TWCR = (1<<TWINT)|(1<<TWEN)|
    (1<<TWSTO);
Anmerkung: Selbstverständlich muss zuvor beim anzusprechenden Slave in TWAR (TWI Adress Register) eine Adresse festgelegt werden, damit er auch gezielt angesprochen werden kann.

Sende-Modi

Das TWI kann prinzipiell in vier verschiedenen Modi arbeiten: Master Transmitter (MT), Master Receiver (MR), Slave Transmitter (ST), Slave Receiver (SR). Diese können natürlich alle in einer Anwendung verwendet werden, je nachdem, wie sie es erfordert.

a.) Master Transmitter Mode

Im MTM wird eine Abfolge von Bytes (Daten) an einen SR gesendet. Um ihn zu benutzen, muss das Adresspaket nach dem gesendeten START eine bestimmte Form aufweisen. Wird SLA+W gesendet, liegt der MTM vor, für SLA+R wäre es der MRM.
Das Senden eines START gestaltet sich wie folgt (TWCR):

<TABLE width="100%" border=1><TR><TD><P align=center>TWINT</P></TD><TD><P align=center>TWEA</P></TD>
<TD><P align=center>TWSTA</P></TD><TD><P align=center>TWSTO</P></TD><TD><P align=center>TWWC</P></TD><TD><P align=center>TWEN</P></TD>
<TD><P align=center>-</P></TD><TD><P align=center>TWIE</P></TD></TR><TR><TD><P align=center>0</P></TD><TD><P align=center>1</P></TD><TD><P align=center>0</P></TD><TD><P align=center>0</P></TD><TD><P align=center>0</P></TD><TD><P align=center>1</P></TD><TD><P align=center>0</P></TD><TD><P align=center>X</P></TD></TR></TABLE>


TWEN: Aktivierung des TWI
TWSTA: Senden des START
TWINT: um TWINT zu löschen

Das TWI wartet nun solange, bis der Bus frei ist und sendet dann START. Danach wird TWINT wieder gesetzt und TWSR aktualisiert. Es sollte jetzt 0x08 enthalten. Beim Auslesen des Status-Code müssen die Prescaler-Bits mit Null maskiert werden. Um den MTM zu benutzen, muss SLA+W in TWDR geschrieben werden. Nachdem TWINT gelöscht wurde, wird dies gesendet. TWCR muss dazu die folgende Form haben:

<TABLE width="100%" border=1><TR><TD><P align=center>TWINT</P></TD><TD><P align=center>TWEA</P></TD><TD><P align=center>TWSTA</P></TD><TD><P align=center>TWSTO</P></TD><TD><P align=center>TWWC</P></TD><TD><P align=center>TWEN</P></TD>
<TD><P align=center>-</P></TD><TD><P align=center>TWIE</P></TD></TR><TR><TD><P align=center>1</P></TD><TD><P align=center>X</P></TD><TD><P align=center>0</P></TD><TD><P align=center>0</P></TD><TD><P align=center>X</P></TD><TD><P align=center>1</P></TD><TD><P align=center>0</P></TD><TD><P align=center>X</P></TD></TR></TABLE>


Nachdem SLA+W gesendet und das ACK-Bit empfangen wurde, wird TWINT erneut gesetzt. Der Statuscode in TWSR kann nun unter anderem folgende Formen haben: 0x18, 0x20, 0x38.
Nachdem bis hierhin alles erfolgreich funktioniert hat, kann jetzt ein Datenpaket versendet werden. Dies erfolgt durch Schreiben der Daten in TWDR.
TWDR kann nur aktualisiert werden, wenn TWINT gesetzt ist, andernfalls kommt es zu einem Fehler, TWWC (TWI Write Collision Bit) wird gesetzt. Um die Daten zu senden, muss TWINT erneut gelöscht werden. TWCR sollte so aussehen:

<TABLE width="100%" border=1><TR><TD><P align=center>TWINT</P></TD><TD><P align=center>TWEA</P></TD>
<TD><P align=center>TWSTA</P></TD><TD><P align=center>TWSTO</P></TD><TD><P align=center>TWWC</P></TD><TD><P align=center>TWEN</P></TD><TD><P align=center>-</P></TD><TD><P align=center>TWIE</P></TD></TR><TR><TD><P align=center>1</P></TD><TD><P align=center>X</P></TD><TD><P align=center>1</P></TD><TD><P align=center>0</P></TD><TD><P align=center>X</P></TD><TD><P align=center>1</P></TD><TD><P align=center>0</P></TD><TD><P align=center>X</P></TD></TR></TABLE>

Dieses Schema wiederholt sich nun solange, bis alle Daten versendet wurden und ein STOP gesendet werden kann. Dies erfolgt folgendermaßen:

<TABLE width="100%" border=1><TR><TD><P align=center>TWINT</P></TD><TD><P align=center>TWEA</P></TD><TD><P align=center>TWSTA</P></TD><TD><P align=center>TWSTO</P></TD><TD><P align=center>TWWC</P></TD><TD><P align=center>TWEN</P></TD><TD><P align=center>-</P></TD><TD><P align=center>TWIE</P></TD></TR><TR><TD><P align=center>1</P></TD><TD><P align=center>X</P></TD><TD><P align=center>0</P></TD><TD><P align=center>1</P></TD><TD><P align=center>X</P></TD><TD><P align=center>1</P></TD><TD><P align=center>0</P></TD><TD><P align=center>X</P></TD></TR></TABLE>

Ein erneuter Start (REPEATED START) erfolgt durch Schreiben der folgenden Werte in TWCR:

<TABLE width="100%" border=1><TR><TD><P align=center>TWINT</P></TD><TD><P align=center>TWEA</P></TD><TD><P align=center>TWSTA</P></TD><TD><P align=center>TWSTO</P></TD><TD><P align=center>TWWC</P></TD><TD><P align=center>TWEN</P></TD><TD><P align=center>-</P></TD><TD><P align=center>TWIE</P></TD></TR><TR><TD><P align=center>1</P></TD><TD><P align=center>X</P></TD><TD><P align=center>1</P></TD><TD><P align=center>0</P></TD><TD><P align=center>X</P></TD><TD><P align=center>1</P></TD><TD><P align=center>0</P></TD><TD><P align=center>X</P></TD></TR></TABLE>

Nach einem REPEATED START kann der Master denselben Slave erneut kontaktieren oder auch einen anderen, ohne ein STOP zu senden. Der REPEATED START erlaubt dem Master das Wechseln zwischen Slaves, MTM und MRM ohne die Kontrolle über den Bus zu verlieren.
Eine Tabelle mit sämtlichen Status-Codes und den zugehörigen Ereignissen ist dem Datenblatt S.176 zu entnehmen.

b.) Master Receiver Mode

Im MRM empfängt der Master Daten von einem ST. Zunächst muss wieder START gesendet werden. Das folgende Adresspaket sollte dann SLA+R enthalten.

<TABLE width="100%" border=1><TR><TD><P align=center>TWINT</P></TD><TD><P align=center>TWEA</P></TD><TD><P align=center>TWSTA</P></TD><TD><P align=center>TWSTO</P></TD><TD><P align=center>TWWC</P></TD><TD><P align=center>TWEN</P></TD>
<TD><P align=center>-</P></TD><TD><P align=center>TWIE</P></TD></TR><TR><TD><P align=center>1</P></TD><TD><P align=center>X</P></TD><TD><P align=center>1</P></TD><TD><P align=center>0</P></TD><TD><P align=center>X</P></TD><TD><P align=center>1</P></TD><TD><P align=center>0</P></TD><TD><P align=center>X</P></TD></TR></TABLE>

TWEN: Aktivierung des TWI
TWSTA: Senden des START
TWINT: um TWINT zu löschen

Das TWI wartet nun solange, bis der Bus frei ist und sendet dann START. Danach wird TWINT wieder gesetzt und TWSR aktualisiert. Es sollte jetzt 0x08 enthalten. Beim Auslesen des Status-Code müssen die Prescaler-Bits mit Null maskiert werden. Um den MTM zu benutzen, muss SLA+R in TWDR geschrieben werden. Nachdem TWINT gelöscht wurde, wird dies gesendet. TWCR muss dazu die folgende Form haben:

<TABLE width="100%" border=1><TR><TD><P align=center>TWINT</P></TD><TD><P align=center>TWEA</P></TD><TD><P align=center>TWSTA</P></TD><TD><P align=center>TWSTO</P></TD><TD><P align=center>TWWC</P></TD><TD><P align=center>TWEN</P></TD><TD><P align=center>-</P></TD><TD><P align=center>TWIE</P></TD></TR><TR><TD><P align=center>1</P></TD><TD><P align=center>X</P></TD><TD><P align=center>0</P></TD><TD><P align=center>0</P></TD><TD><P align=center>X</P></TD><TD><P align=center>1</P></TD><TD><P align=center>0</P></TD><TD><P align=center>X</P></TD></TR></TABLE>

Nachdem SLA+R gesendet und das ACK-Bit empfangen wurde, wird TWINT erneut gesetzt. Der Statuscode in TWSR kann nun unter anderem folgende Formen haben: 0x38, 0x40, 0x48.
Die empfangenen Daten können aus TWDR gelesen werden, so denn TWINT gesetzt ist. Dieses Schema kann sich bis zum Empfang des letzten Bytes immer wieder wiederholen. Nachdem das letzte Byte empfangen wurde, kann der Master dem Slave durch senden von NACK klar machen, dass keine Daten mehr erwartet werden. Beendet wird der Transfer durch senden von STOP oder REPEATED START.

Für STOP muss folgendes in TWCR geschrieben werden:

<TABLE width="100%" border=1><TR><TD><P align=center>TWINT</P></TD><TD><P align=center>TWEA</P></TD><TD><P align=center>TWSTA</P></TD><TD><P align=center>TWSTO</P></TD><TD><P align=center>TWWC</P></TD><TD><P align=center>TWEN</P></TD><TD><P align=center>-</P></TD><TD><P align=center>TWIE</P></TD></TR><TR><TD><P align=center>1</P></TD><TD><P align=center>X</P></TD><TD><P align=center>0</P></TD><TD><P align=center>1</P></TD><TD><P align=center>X</P></TD><TD><P align=center>1</P></TD><TD><P align=center>0</P></TD><TD><P align=center>X</P></TD></TR></TABLE>

Für einen REPEATED START muss folgendes in TWCR geschrieben werden:

<TABLE width="100%" border=1><TR><TD><P align=center>TWINT</P></TD><TD><P align=center>TWEA</P></TD><TD><P align=center>TWSTA</P></TD><TD><P align=center>TWSTO</P></TD><TD><P align=center>TWWC</P></TD><TD><P align=center>TWEN</P></TD><TD><P align=center>-</P></TD><TD><P align=center>TWIE</P></TD></TR><TR><TD><P align=center>1</P></TD><TD><P align=center>X</P></TD><TD><P align=center>1</P></TD><TD><P align=center>0</P></TD><TD><P align=center>X</P></TD><TD><P align=center>1</P></TD><TD><P align=center>0</P></TD><TD><P align=center>X</P></TD></TR></TABLE>

Nach einem REPEATED START kann der Master denselben Slave erneut kontaktieren oder auch einen anderen, ohne ein STOP zu senden. Der REPEATED START erlaubt dem Master das Wechseln zwischen Slaves, MTM und MRM ohne die Kontrolle über den Bus zu verlieren.
Eine Tabelle mit sämtlichen Status-Codes und den zugehörigen Ereignissen ist dem Datenblatt zu entnehmen.

c.) Slave Receiver Mode

Im SRM werden Daten vom MT empfangen. Um einen Atmega8 im SRM zu betreiben, müssen TWAR und TWCR die folgende Form haben:

TWAR:
Die oberen 7 Bit stellen die Adress dar, an die das TWI antwortet, wenn es von einem Master angesprochen wird. Wenn das LSB (Least Significant Bit) in Form von TWGCE gesetzt ist, antwortet der Slave auch auf allgemeine Rufe (general calls), andernfalls natürlich nicht.

<TABLE width="100%" border=1><TR><TD><P align=center>TWA6</P></TD><TD><P align=center>TWA5</P></TD><TD><P align=center>TWA4</P></TD><TD><P align=center>TWA3</P></TD><TD><P align=center>TWA2</P></TD><TD><P align=center>TWA1</P></TD><TD><P align=center>TWA0</P></TD><TD><P align=center>TWGCE</P></TD></TR><TR><TD><P align=center>Hier</P></TD><TD><P align=center>steht</P></TD><TD><P align=center>dann</P></TD><TD><P align=center>die</P></TD><TD><P align=center>Adresse</P></TD><TD><P align=center>des</P></TD><TD><P align=center>Slave!</P></TD><TD><P align=center>X</P></TD></TR></TABLE>


TWCR:
TWEN muss zum aktivieren des TWI gesetzt werden. TWEA muss gesetzt werden, damit der Slave antwortet, falls er von einem Master oder gegeben falls durch einen general call angesprochen wird. TWSTA und TWSTO müssen auf Null gesetzt werden.

<TABLE width="100%" border=1><TR><TD><P align=center>TWINT</P></TD><TD><P align=center>TWEA</P></TD><TD><P align=center>TWSTA</P></TD><TD><P align=center>TWSTO</P></TD><TD><P align=center>TWWC</P></TD><TD><P align=center>TWEN</P></TD><TD><P align=center>-</P></TD><TD><P align=center>TWIE</P></TD></TR><TR><TD><P align=center>0</P></TD><TD><P align=center>1</P></TD><TD><P align=center>0</P></TD><TD><P align=center>0</P></TD><TD><P align=center>0</P></TD><TD><P align=center>1</P></TD><TD><P align=center>0</P></TD><TD><P align=center>X</P></TD></TR></TABLE>

Wenn TWAR und TWCR initialisiert wurden, wartet der Slave ab, bis er mit seiner Adresse bzw. gegebenen falls durch einen generall call angesprochen wird gefolgt von einem Datenrichtungs-Bit. Hierbei steht eine '0' für Schreiben (SR) und eine '1' für Lesen (ST).
Nachdem die Logik ihre eigene Adresse und ein Schreib-Bit erhalten hat, wird TWINT gesetzt und TWSR beinhaltet den entsprechenden Statuscode. Mit seiner Hilfe kann die Software dann eine sinnvolle Reaktion einleiten. Der Eintritt in den SRM kann auch erfolgen, wenn ein Master sein Vorrecht auf dem Bus verloren hat (0x68, 0x7.
Wenn TWEA während eines Transfers zurückgesetzt wird, wird das TWI ein NACK (Not Acknowledge) auf den Bus nach Empfang des nächsten Bytes geben. Dies kann verwendet werden, wenn der Slave nicht mehr in der Lage ist, mehr Bytes zu empfangen. Solange TWEA '0' ist, reagiert das TWI nicht mehr auf seine eigene Slave-Adresse. Jedoch wird der Bus weiterhin beobachtet und das TWI ist nach dem Setzen von TWEA sofort wieder einsatzbereit. Somit kann dieses Feature verwendet werden, um einen Baustein für eine bestimmte Zeitspanne vom Bus zu nehmen.
In sämtlichen Sleep-Modi (außer Idle Mode) ist der Systemtakt des TWI inaktiv. Dessen zu trotz kann das TWI durch setzen von TWEA allein mit Hilfe des Bustaktes erfassen, wenn es mit seiner Adresse bzw. durch einen general call angesprochen wird. Somit kann das TWI den Controller aufwecken.
Während der Aufweck-Phase kann SCL auf L-Pegel gehalten werden wenn TWINT gelöscht ist (Schreiben einer '1'). Der Datenempfang kann wieder im Normalbetrieb stattfinden. Zu beachten ist, dass solange SCL auf L-Pegel ist keine anderen Transmissionen stattfinden können. Wichtig ist, dass TWDR nach dem Aufwecken nicht mehr das letzte Byte, welches auf dem Bus war, enthält.
Eine Tabelle mit sämtlichen Status-Codes und den zugehörigen Ereignissen ist dem Datenblatt zu entnehmen.

d.) Slave Transmitter Mode

Im STM werden Daten an einen MR gesendet. Um den Controller im STM zu betreiben, müssen TWAR und TWCR wie folgt initialisiert werden.
TWAR:

Die oberen 7 Bit stellen die Adress dar, an die das TWI antwortet, wenn es von einem Master angesprochen wird. Wenn das LSB (Least Significant Bit) in Form von TWGCE gesetzt ist, antwortet der Slave auch auf allgemeine Rufe (general calls), andernfalls natürlich nicht.

<TABLE width="100%" border=1><TR><TD><P align=center>TWA6</P></TD><TD><P align=center>TWA5</P></TD><TD><P align=center>TWA4</P></TD><TD><P align=center>TWA3</P></TD><TD><P align=center>TWA2</P></TD><TD><P align=center>TWA1</P></TD><TD><P align=center>TWA0</P></TD><TD><P align=center>TWGCE</P></TD></TR><TR><TD><P align=center>Hier</P></TD><TD><P align=center>steht</P></TD><TD><P align=center>dann</P></TD><TD><P align=center>die</P></TD><TD><P align=center>Adresse</P></TD><TD><P align=center>des</P></TD><TD><P align=center>Slave!</P></TD><TD><P align=center>X</P></TD></TR></TABLE>

TWCR:
TWEN muss zum aktivieren des TWI gesetzt werden. TWEA muss gesetzt werden, damit der Slave antwortet, falls er von einem Master oder gegeben falls durch einen general call angesprochen wird. TWSTA und TWSTO müssen auf Null gesetzt werden.

<TABLE width="100%" border=1><TR><TD><P align=center>TWINT</P></TD><TD><P align=center>TWEA</P></TD><TD><P align=center>TWSTA</P></TD><TD><P align=center>TWSTO</P></TD><TD><P align=center>TWWC</P></TD><TD><P align=center>TWEN</P></TD><TD><P align=center>-</P></TD><TD><P align=center>TWIE</P></TD></TR><TR><TD><P align=center>0</P></TD><TD><P align=center>1</P></TD><TD><P align=center>0</P></TD><TD><P align=center>0</P></TD><TD><P align=center>0</P></TD><TD><P align=center>1</P></TD><TD><P align=center>0</P></TD><TD><P align=center>X</P></TD></TR></TABLE>

Nach der Initialisierung wartet das TWI auf eine Anfrage gefolgt von einem Datenrichtungsbit. Wird das TWI angesprochen wird TWINT gesetzt und TWSR beinhaltet den Statuscode. Mit seiner Hilfe kann das weitere Vorgehen festgelegt werden. Ein Controller kann auch in den STM gelangen, wenn er die Hoheit auf dem Bus an einen anderen Master verliert (0xB0).
Wird TWEA während eines Transfers gesetzt, wird das aktuelle Byte noch fertig gesendet und Status 0xC0 oder 0xC8 tritt ein, je nachdem ob der
Master ACK oder NACK nach dem letzten Byte gesendet hatte. Das TWI wird in einen Blockierzustand gehen, unabhängig davon, ob der Master den Transfer fortsetzt. So erhält der Master nur noch '1' auf dem seriellen Bus. Status 0xC8 tritt ein, wenn der Master weitere Daten fordert (durch Senden von ACK), obwohl der Slave bereits das letzte Byte gesendet hat (TWEA '0' und erwartet NACK).
Trotz des Blockierzustandes wird der Bus weiter beobachtet und das TWI kann durch setzen von TWEA jederzeit wieder daran teilnehmen. Somit kann der Slave mit Hilfe von TWEA kurzzeitig vom Bus isoliert werden.
In sämtlichen Sleep-Modi (außer Idle Mode) ist der Systemtakt des TWI inaktiv. Dessen zu trotz kann das TWI durch setzen von TWEA allein mit Hilfe des Bustaktes erfassen, wenn es mit seiner Adresse bzw. durch einen general call angesprochen wird. Somit kann das TWI den Controller aufwecken.
Während der Aufweck-Phase kann SCL auf L-Pegel gehalten werden wenn TWINT gelöscht ist (Schreiben einer '1'). Der Datenversand kann wieder im Normalbetrieb stattfinden. Zu beachten ist, dass solange SCL auf L-Pegel ist keine anderen Transmissionen stattfinden können. Wichtig ist, dass TWDR nach dem Aufwecken nicht mehr das letzte Byte, welches auf dem Bus war, enthält.Eine Tabelle mit sämtlichen Status-Codes und den zugehörigen Ereignissen ist dem Datenblatt S.185 zu entnehmen.

Zusätzlich zu den Betriebsart bezogenen Statuscodes gibt es noch zwei, welche davon unabhängig sind.
Status 0xF8 bedeutet, dass keine relevanten Informationen vorhanden sind, da TWINT nicht gesetzt ist. Dieser Fall tritt bei einem Statuswechsel ein oder wenn TWI im Moment nicht am Bus beteiligt ist.
Status 0x00 steht für einen Busfehler während einer Übertragung. Ursache kann das Senden von START oder STOP zu einem nicht zulässigem Zeitpunkt sein. Bei solch einem Fehler wird TWINT automatisch gesetzt. Um die Fehlerroutine zu verlassen, muss TWSTO gesetzt und TWINT gelöscht werden.
Dieses führt dazu, dass das TWI in den nicht adressierten Slave-Modus geht und SDA und SCL wieder freigegeben werden. Es wird kein STOP gesendet.

Der Artikel wurde bereitgestellt von Alexander Starke
Homepage des Autors http://www.mc-project.de/


Nachtrag:Keine Sorge wenn das ganze auf den ersten Blick etwas kompliziert klingt. Immer mehr Hochsprachen haben Befehle oder Bibliotheken welche einem die Nutzung des I2C-Busses erheblich vereinfachen. Teilweise reicht dann ein einziger Befehl zum senden oder abrufen von Bytes aus!
In diesem Zusammenhang kann ich noch folgende Links für C-Programmierer empfehlen:
http://sourceforge.net/projects/winavr
http://savannah.nongnu.org/projects/avr-libc/
http://homepage.sunrise.ch/mysunrise...-software.html