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:

  1. Das MSTR-Bit wird gelöscht und die Komponente wird zum Slave. Dadurch werden MOSI und SCK zu Eingängen.
  2. SPIF wird gesetzt und falls so vorgesehen eine entsprechende ISR abgearbeitet.

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.

 

Zurück zur Startseite.