Hallo zusammen,
Ich möchte eine DaisyChain von SPI Slave-Geräten zur bidirektionalen
Kommunikation verwenden.
DaisyChain heißt, alle SlaveSelects (SS) der Slaves sind
zusammengeschalten (der Master hat ohnehin nicht genügend Pins).
Erschwerend kommt hinzu, dass die Slaves nicht wissen, wie viele Geräte
in der Kette hängen.
bidirektional habe ich mir so vorgestellt:
Sagen wir, wir haben 8 Slaves. Jeder soll ein bestimmtes Byte an Daten
erhalten (also sind vom Master 8 Bytes zu senden). Hat jeder sein Byte
erhalten, schreiben die Slaves ihrerseits je ein Byte Rückgabewert in
ihre Register und senden den Datenstrom zurück an den Master. Er bekommt
also 8 Bytes Rückgabewerte.
Bei Schieberegistern ist das einfach:
die 8 Bytes werden durchgetaktet und per Latch-Flanke auf die Ausgänge
der Schieberegister geschalten. Jetzt könnten die Dinger ganz leicht
neue Werte in den Serial-Buffer schreiben (wenn es eben - rein
hypothetisch - bidirektionale Schieberegister wären). Mit den folgenden
Taktflanken kann sich der Master dann die Antwortdaten zurück holen...
Mit Microcontrollern im SPI-Slave-Modus wird das schwieriger.
Ich habe gerade ein PIC-Datasheet durch und scheinbar funktionert SS
nicht wie ein Latch Clock. Anstelle des "Annehmens" von den Daten im
Shift-Buffer wird die gesamte SPI-Hardware mit SS erst angeschalten.
Die Folge: ohne SS-Signal zerschellt der Datenstrom schon am ersten
Slave in der Kette; und mit SS-Signal wird nach jedem Byte ein
Empfangsinterrupt ausgelöst.
Da aber kein Slave weiß, wie viele Slaves in der Kette liegen, kann er
auch nicht wissen, wie viele Interrupts in der DaisyChain er abwarten
muss, bevor seine Daten im Buffer anliegen. Schlimmer noch: durch das zu
häufige Rückschreiben seiner Antwortdaten korrumpiert er den Datenstrom
an seine Nachfolger.
Ich hoffe, ich konnte das Problem nachvollziehbar formulieren? Ist wohl
ein rechter Kauderwelsch geworden... :)
Ein Workaround wäre, die SS-Leitungen immer low (SPI aktiv) zu legen und
die freigewordene Signalleitung vom Master zu den Slaves mit je einem
von deren Interrupt-Pins zu verbinden. Jetzt ließe sich die beschriebene
Funktionalität einfach manuell zusammenprogrammieren: anstelle des
SPI-Interrupts wird einfach alle 8 Bytes der ext-Interrupt verwendet, um
- wie beim Schieberegister-Latch - das jeweilige Byte aus dem
Slave-Puffer in den lokalen Speicher zu kopieren (und vielleicht die
Antwortdaten zurückzukopieren). Die urpsrünglichen SPI-Slave-Interrupts
können dann deaktiviert/ignoriert werden.
Ist das die Methode der Wahl oder gibt es eine elegantere Lösung (z.B.
in Hardware)?
Es geht genaus, wie bei einem Schieberegister.
Angenommen, es sind 8 Slave. Dann müssen diese zuerst ihre Sendebytes in
ihr SPI-Data schreiben. Nun schiebt der Master 8 neue Bytes rein und
damit liest er gleichzeitig diese vorbereiteten 8 Bytes aus.
Die Slave haben danach je ein neuese Byte empfangen und der Master hat
alle 8 Bytes der Slaves.
Aber dazu muß natürlich bekannt sein, wieviel Slaves maximal in der
Kette sind.
ja so will ich es haben. Der Master weiß natürlich, wie viele Slaves da
sind, nur die einzelnen Slaves haben davon keine Ahnung.
Geht das mit dem SS-Eingang der Slaves?
Ich behaupte "nein", da:
Wenn die SS-Eingänge auf high liegen, kann der Master keine Bytes
durchschieben, die Schiebelogik ist deaktiviert.
Also muss SS bei allen Slaves immer auf low (aktiv) liegen. Wenn das
aber so ist, wie teilt der Master den Slaves dann mit, dass das
"Eintakten" der Daten beendet ist?
Was spricht denn eigentlich dagegen, alle SPI-Slaves parallel an das
Interface zu hängen und bei jeder Übertragung ein Adressen-Byte
mitzugeben, welches den entsprechenden Slave auswählt? Dann bräuchtest
du keinen SlaveSelect- oder Latch-Ausgang mehr, wodurch der Pin am
Controller frei wird für andere Dinge.
Die Lösung mit dem Interrupt-Pin würde aber genauso funktionieren. Die
mit SS, wie du selbst schon festgestellt hast, leider nicht, wenn die
SPI-Transmitter der Slaves ohne SS abgeschaltet werden.
Gruß
Jonathan
Danke! Beides gute Hinweise!
Ich verbinde jetzt mal den Interrupt Pin. Dann kann ich mir überlegen,
wie es am Ende realisiert wird.
Gegen die Adressierung könnte sprechen, dass dafür jeder Slave wieder
eine bestimmte Adresse braucht, auf die er anspringt. Das ist aber
wieder eine Art der "zentralen Information", die ich dem Slave nicht
mitgeben (müssen) möchte.
mal sehen...
danke!
A. S. schrieb:> Also muss SS bei allen Slaves immer auf low (aktiv) liegen.
Nein.
SS = low
8 Bytes durchschieben
SS = high.
Die Slave legen SS mit auf einem Interrupt, dann wissen sie, wann Ende
ist und können die Bytes lesen und neue reinschreiben.
Peter Dannegger schrieb:> Die Slave legen SS mit auf einem Interrupt, dann wissen sie, wann Ende> ist und können die Bytes lesen und neue reinschreiben.
Stimmt, das wäre auch eine Möglichkeit, daran habe ich nicht gedacht.
A. S. schrieb:> Gegen die Adressierung könnte sprechen, dass dafür jeder Slave wieder> eine bestimmte Adresse braucht, auf die er anspringt. Das ist aber> wieder eine Art der "zentralen Information", die ich dem Slave nicht> mitgeben (müssen) möchte.
Wenn du es dann tatsächlich mit Adressen machst, kannst du ja dem ersten
Slave per Hardware sagen (1 Pin auf Masse o.ä.), er soll sich beim
Poweron eine Adresse vom Master holen, dann sagt dieser Slave dem
nächsten, er soll sich auch eine Adresse holen (legt dessen Pin einfach
auch auf Masse), usw., bis der letzte Slave seine Adresse hat. Damit
kann der Master auch gleichzeitig feststellen, wie viele Slaves
existieren.
Gruß
Jonathan