Das Serial Peripheral Interface - SPI
Das SPI ermöglicht den synchronen Datentransfer zwischen dem ATmega8 und
verschiedener Peripherie bzw. zwischen verschiedenen Controllern. Es wird auch
zum Austauschen von Daten mit externen Datenspeichern (z.B. EEPROM) genutzt.
Für eine vollduplexe Übertragung werden zwei serielle Datenleitungen des ATmegas
(MOSI, MISO) und zusätzlich eine Taktleitung benötigt. Eine Komponente des
Netzwerks muss immer als Master arbeiten. Diese stellt auch den Takt für die
Übertragung nach dem Schieberegisterprinzip zur Verfügung. Alle andere
Komponenten verhalten sich als Slaves, welche nur auf Masteraufforderung hin
ihre Daten auf dem Bus bereitstellen.
Mit Hilfe des SPI lassen sich sehr einfach busähnliche Strukturen aufbauen, da
jede SPI-Komponente über ein Aktivierungspin (Slave Select ->
SS) verfügt.
An dieser Grafik kann man auch schon einen wesentlichen Nachteil des SPI erkennen. Augenscheinlich benötigt der Master für jeden Slave einen Pin (PB0...3) um das SPI nutzen zu können. Dies kann in bestimmten Anwendungsfällen die Nutzung des SPI unmöglich machen, jedoch verfügt der ATmega8 über weitere Möglichkeiten zur seriellen Kommunikation, beispielsweise das TWI, welches unter einem eigenen Menüpunkt erläutert wird.
Konkret sieht das Ganze nun so aus:
Die Verbindung zwischen Master und Slave(s) besteht aus zwei Schieberegistern
und einem Taktgenerator auf Masterseite. Der Master eröffnet die Kommunikation
mit einem Slave, indem er dessen SS-Pin
gegen Masse zieht. Dann bereiten Master und Slave die zu versendenden Daten in
ihrem jeweiligen Schieberegister vor. Nun beginnt der Master die erforderlichen
Taktimpulse auf seinem SCK-Pin zur Verfügung zu stellen, damit ein
Datenaustausch stattfinden kann.
Die Daten vom Master an den Slave bewegen sich auf der MOSI-Verbindung (Master
Out, Slave In), die Daten vom Slave an den Master auf der MISO-Verbindung
(Master In, Slave Out).
Nach jedem Datenpaket versucht der Master sich mit dem Slave erneut zu
synchronisieren, indem er dessen SS-Pin
kurz auf High-Pegel setzt.
Wenn eine Komponente als Master funktionieren soll, so ist ihr von
Software-Seite aus die Kontrolle über die
SS-Verbindung zu geben,
andernfalls kann keine Kommunikation stattfinden. Sobald dies getan ist, bewirkt
das Schreiben eines Bytes in SPDR (Serial Peripheral Interface Data
Register) das Starten des Taktgenerators und das Byte wird automatisch zum Slave
übertragen. Ist die Übertragung abgeschlossen stoppt der Taktgenerator und
SPIF (Serial Peripheral Interface Flag) wird gesetzt. Falls durch Setzen von
SPIE (Serial Peripheral Interface Interrupt Enable) der entsprechende
Interrupt aktiviert ist, so beginnt der MC mit dem Abarbeiten einer
entsprechenden ISR.
Nun kann entweder das nächste Byte in SPDR geschrieben werden oder der Master
signalisiert dem Slave das Ende der Übertragung indem er
SS wieder auf High-Pegel legt.
Das letzte empfangene Byte verbleibt immer im entsprechenden Schieberegister.
Um das SPI generell zu aktivieren muss noch SPE (SPI Enable) in SPCR
gesetzt werden.
Nun das ganze noch einmal für den Slave. Dessen SPI wartet solange, bis sein
SS-Pin auf Low gesetzt wird.
Solange der Pin auf High-Pegel ist kann die Software zwar ständig das SPDR
aktualisieren, dies hat jedoch keine Auswirkungen, da der Slave die Daten nicht
versendet. Hat der Master einen Datentransfer initialisiert, wird das in SPDR
geschriebene Byte versendet und abschließend nach erfolgreichem Transfer SPIF
gesetzt. Ist das SPIE-Bit in SPCR (Serial Peripheral Interface Control
Register) gesetzt, so kann eine entsprechende ISR abgearbeitet werden.
Dann kann der Slave je nach Bedarf neue Daten in SPDR schreiben, bevor er die
vom Master eingegangen Daten liest. Das zuletzt eingetroffene Byte verbleibt
auch hier im Schieberegister.
Für den Anwender wichtig ist, dass das SPI in Empfangsrichtung doppelt und in Senderichtung nur einfach gepuffert ist. Praktisch bedeutet das, dass man beim Senden in SPDR keine neuen Werte schreiben sollte, solange der Sendevorgang nicht abgeschlossen ist. Bei Empfangen von Daten muss das vorangegangene Byte vollständig ausgelesen werden, bevor dessen Nachfolger angekommen ist. Andernfalls ist das erste Byte verloren.
Allgemein soll noch gesagt werden, dass die Taktrate am SCK-Pin des Masters nie fosz/4 übersteigen sollte. Auch gilt es zu berücksichtigen, dass mit verwenden des SPI die normalen Funktionen der entsprechenden Pins an den Controllern nicht mehr zur Verfügung stehen. Die Auswahl der Taktrate erfolgt wie folgt:
SPI2X |
SPR1 |
SPR0 |
SCK Frequenz |
0 |
0 |
0 |
fosz/4 |
0 |
0 |
1 |
fosz/16 |
0 |
1 |
0 |
fosz/64 |
0 |
1 |
1 |
fosz/128 |
1 |
0 |
0 |
fosz/2 |
1 |
0 |
1 |
fosz/8 |
1 |
1 |
0 |
fosz/32 |
1 |
1 |
1 |
fosz/64 |
SPR1 und SPR0 sind in SPCR zu finden, SPI2X (Double SPI Speed Bit) liegt in SPSR (SPI Status Register).
Der Slave-Modus:
Wenn das SPI einer Komponente als Slave definiert ist, so arbeitet dessen
SS-Pin immer als Eingang. Wird
SS low, so startet das SPI, MISO
wird zum Ausgang, falls dies vom Programmierer so vorgesehen wurde. Alle anderen
Pins arbeiten als Eingänge. Ist SS
high, so verhält sich das SPI passiv, alle Pins arbeiten als Eingänge und
eingehenden Daten werden nicht empfangen. Das SPI führt einen automatischen
Reset aus, sobald SS high wird.
SS sorgt für eine synchrone
Datenübertragung zwischen Master und Slave, indem es den Bitzähler des Slaves
mit dem Takt des Masters synchronisiert. Wird
SS high, so bewirkt der Reset,
dass alle teilweise erhaltenen Informationen im Schieberegister abgelegt werden.
Der Master-Modus:
Wenn das SPI einer Komponente durch setzen von MSTR in SPCR als Master
definiert wurde, legt der Anwender die Datenrichtung an
SS fest.
Wird SS als Ausgang festgelegt,
dann hat das keinen Einfluss auf das SPI-System. Im Normalfall steuert er dann
die SS-Pins der Slaves.
Wird SS als Eingang definiert, so
muss es ständig auf High gehalten werden, um die Arbeitsweise als Master des SPI
sicherzustellen. Wird der Pin dessen zu trotz auf Low Pegel gelegt, so
interpretiert die SPI-Logik dies so, als wenn ein anderer Master die Komponente
als Slave ausgewählt hat und beginnt Daten zu senden. Um Konflikte auf dem BUS
zu vermeiden, führt die SPI folgende Einstellungen durch:
Dieses sollte durch den Anwender berücksichtigt werden. Wenn das Senden der Daten durch den entsprechenden Interrupt gesteuert wird und die Möglichkeit besteht, dass der Pin durch externe Einflüsse auf Low-Pegel geht, so muss die ISR überprüfen, ob MSTR noch gesetzt ist und gegebenenfalls neu setzen.
Programmtechnisch habe ich mich noch nicht bemüht, eine Kommunikation mit externen Bausteinen (EEPROM o.ä.) per SPI umzusetzen, deshalb sind unter Programme lediglich die Beispiele aus dem Datenblatt des ATmega zu finden. Zusätzlich habe ich ein Beispiel bereit gestellt, welches die Kommunikation zwischen zwei ATMega's verdeutlicht. Die genaue Funktion kann der Kommentierung entnommen werden.
NEU: Wen die Anwendung des SPI interessiert, der sollte sich die Bausteine der Rubrik ICs & Co sowie die Rubrik MMC einmal näher anschauen.