Hallo,
ich versuche zurzeit die GPIO-Pins eines ESP32-Slaves mit einem
ESP32-Master über SPI fernzusteuern. Konkret soll der Master die
digitalRead- und digitalWrite-Methode fernsteuern. Für die
SPI-Kommunikation nutze ich diese Library hier:
https://github.com/hideakitai/ESP32DMASPI/
Nun zu meinem Problem. Es passiert recht häufig, dass Bits, die über den
Bus geschickt werden, nicht korrekt übertragen werden. Das Interessante
ist, dass bei einer Übertragungsfrequenz von 1 MHz nur selten ein Fehler
passiert. Ist die Übertragungsrate kleiner oder größer, schleichen sich
Fehler oft in fast jede Nachricht ein. Ich habe leider überhaupt keine
Idee mehr, woran das liegen könnte.
Warum die Übertragungsqualität so sehr davon abhängt, dass ich mit 1 MHz
übertrage, verstehe ich nicht. 100 kHz oder 2 MHz funktionieren kaum.
Kann man das irgendwie beheben?
*Hier ist mein Protokoll:*
Ich kodiere jeden Befehl und die Nachricht dazu in einem Byte.
Das Befehls-Byte vom Master zum Slave sieht so aus:
- Bit 1: Der Identifier des Befehls. 0 bedeutet schreiben, 1 bedeutet
lesen.
- Bit 2: Falls der Befehl ein Schreibbefehl ist, ist das hier der Wert,
der geschrieben werden soll.
- Bit 3 - 8: Die Pin-Nummer.
Der Slave sendet dann mit der nächsten Nachricht die Antwort.
Diese sieht dann so aus:
- Bit 1: Die Gültigkeit der Antwort.
- Bit 2: Der gelesene Wert.
- Bit 3 - 8: Die Pin-Nummer.
Wenn der Befehl 'Lesen' ist, wird der Befehl vom Master so lange
wiederholt, bis der Slave eine gültige Antwort gesendet hat.
Momentan übertrage ich trotzdem immer 4 Bytes. Das liegt daran, dass die
Library das so vorschreibt. Das werde ich aber später noch ändern. Im
Moment möchte ich erstmal die Daten zuverlässig übertragen bekommen.
Vielen Dank für eure Hilfe. Mein Aufbau/Schaltplan ist im Anhang.
*Master-Code:*
Alexander L. schrieb:> Ich habe leider überhaupt keine Idee mehr, woran das liegen könnte.
Allererster Schritt bei der Inbetriebnahme serieller Schnittstellen:
man nimmt das Oszilloskop und kontrolliert Spannungsverlauf und Timing.
Hast du das gemacht? Ist da alles im grünen Bereich? Siehst du auf dem
Oszi den richtigen SPI-Mode? Passt der zu dem, was der Empfänger
erwartet?
> Kann man das irgendwie beheben?
Dazu muss man erst mal wissen, was man beheben muss. Wenn man
Überschwinger oder Unstetigkeiten in den Flanken sieht, dann muss man
die Terminierung anpassen. Wenn die Pegel nicht passen, dann gibts evtl.
irgendwo eine Buskollision.
Das kann ich leider nicht tun. Ich bin eigentlich eher weniger im
Hardware-Bereich tätig und habe kein Oszilloskop. Eventuell kann ich mal
an der Uni schauen, ob ich dort irgendwo eines finde, womit ich kurz
testen kann.
Gibt es vielleicht häufige Fehler, die bei so etwas auftreten, die man
mal probieren könnte?
Alexander L. schrieb:> Eventuell kann ich mal an der Uni schauen, ob ich dort irgendwo eines finde
Tu das. Wenn da alles unfraglich passt, **dann** suche auf der SW-Seite
weiter.
> Gibt es vielleicht häufige Fehler
Fehlerhafte Terminierung und falscher SPI-Mode sind die häufigsten
Fehler. Aber das ist blindes Stochern im Trüben, solange die
Datenintegrität auf der Hardwareseite nicht sichergestellt ist.
Alexander L. schrieb:> nur selten ein Fehler passiert.
Meine SPI-Schnitten müssen im Labor und im Klimaschrank über mehrere
Tage absolut ohne jeglichen Übertragungsfehler laufen. Dann bin ich
zufrieden und traue mich damit raus ins Feld.
Alexander L. schrieb:> Gibt es vielleicht häufige Fehler
Wenn deine Schaltung so aussieht, wie du sie oben gezeichnet hast, dann
wundert mich, dass die überhaupt was tut.
Denn da fehlt ja jegliche Masseverbindung zwischen den µc und auch die
Versorgung der µC.
Oder der Schaltplan ist falsch. Und mit falschen Schaltplänen Fehler
suchen ist ein spannendes Unterfangen.
Lothar M. schrieb:> Denn da fehlt ja jegliche Masseverbindung zwischen den µc und auch die> Versorgung der µC.
Mich würde auch mal die Länge/Art der Verbindungen interessieren.
Der Schaltplan ist genau das was ich auch in echt gebaut habe. Den habe
ich selbst gezeichnet. Eine Masseverbindung bzgl. der SPI Kommunikation
existiert wirklich nicht. Ich bin eigentlich Informatiker und meine
Hardware-Kenntnisse kommen aus genau einem Vertiefungsmodul, wo wir das
am Rande mal angesprochen haben. Deshalb bin ich bei so etwas vermutlich
etwas unbeholfen.
Das Grafik aus der ich diesen Aufbau abgeleitet habe ich diese hier:
https://puu.sh/JNejs/a0800d4add.png (Steht so bei uns im Skript.)
Da sehe ich jetzt keine Masserverbindung. Wo genau müsste die dann sein?
Ich finde auch online keine Pläne, wo eine Masseverbindung dabei ist.
Ich nehme auch mal an, dass da dann noch ein Widerstand zur
Masseverbindung gehört, damit das nicht zum Kurzschluss wird.
Die Länge der Verbindung ist nicht weit. Das dürften etwa 15cm sein.
Alexander L. schrieb:> Eine Masseverbindung bzgl. der SPI Kommunikation> existiert wirklich nicht.
Und keiner der beiden ESP32 ist mit irgendeiner Art Netzteil verbunden?
Wie soll das dann funktionieren?
Alexander L. schrieb:> Der Schaltplan ist genau das was ich auch in echt gebaut habe. Den habe> ich selbst gezeichnet. Eine Masseverbindung bzgl. der SPI Kommunikation> existiert wirklich nicht. Ich bin eigentlich Informatiker
Aha, mal wieder die typische Einstellung vieler Informatiker, die sich
einbilden, dass für sie die physikalischen Gesetze nicht gelten.
> Das Grafik aus der ich diesen Aufbau abgeleitet habe ich diese hier:> https://puu.sh/JNejs/a0800d4add.png (Steht so bei uns im Skript.)
Das ist nur eine Vereinfachung, die die reinen Nutzsignale darstellt.
> Da sehe ich jetzt keine Masserverbindung. Wo genau müsste die dann sein?
Dann musst Du Dich wohl mal mit den elektrotechnischen Grundlagen
befassen. Hierfür gibt es unzählige Lehrbücher.
> Ich finde auch online keine Pläne, wo eine Masseverbindung dabei ist.
Dann benötigt man wohl auch keine, und tausende professioneller
Elektronikentwickler haben einfach keine Ahnung.
> Ich nehme auch mal an, dass da dann noch ein Widerstand zur> Masseverbindung gehört, damit das nicht zum Kurzschluss wird.
Aha. Gewagte Behauptung für jemanden, der schon mit seiner tatsächlichen
Unwesenheit so kokettiert. Offenbar scheinen die Autoren unzählige
Fachpublikationen über das Thema Masseführung, Signalintegrität und
Elektromagnetische Verträglichkeit keine Ahnung zu haben. Deren
Berechnungen, Simulationen und Messungen scheinen auch alle fehlerhaft
zu sein.
> Die Länge der Verbindung ist nicht weit. Das dürften etwa 15cm sein.
Aha. Gewagte Behauptung für jemanden, der jegliche physikalischen bzw.
elektrotechnischen Grundlagen konsequent ignoriert. Aber Du musst es ja
wissen.
Alexander L. schrieb:> Der Slave sendet dann mit der nächsten Nachricht die Antwort.
Das kann er schon rein zeitlich nicht. Der Master schickt immer den
Takt. Nach dem ersten Byte kriegt der Slave einen Interrupt und kann das
Byte auswerten. Dazu nutzt er die Zeitdauer des 2. Bytes, d.h. der
Master kriegt im 1. und 2. Byte Müll zurück. Erst im 3. Byte kann der
Slave was zurück senden.
Einen Oszi braucht man nicht fürs SPI. Nur etwas Lesen des Datenblattes
und logisches Denken.
Terminiert wird beim SPI auch nichts.
Ich würde aber erstmal nur dumme Slaves ansprechen (74HC595, 74HC165)
und zum Laufen bringen.
Alexander L. schrieb:> Da sehe ich jetzt keine Masserverbindung. Wo genau müsste die dann sein?
Verbinde GND ("Ground" = "Masse") des linken ESP-32 mit GND des rechten
ESP-32, falls das nicht sowieso über ein gemeinsam genutztes Netzteil
bereits der Fall ist.
Immerhin hast Du GND des rechten ESP-32 (obere rechte Ecke) ja mit dem
FE_Srly-Modul verbunden. So muss das auch sein.
Du brauchst Masseverbindungen, damit Pegel (Low, High) ein gemeinsames
Grundniveau haben. Spannungspegel sind Potentialdifferenzen. Diese
können nur existieren bzw. eine gemeinsame Grundlage haben, wenn beide
dasselbe Bezugspotential haben. Das ist eben GND.
Peter D. schrieb:> Terminiert wird beim SPI auch nichts.
Bei langen Verbindungen, insbesondere wenn dann auch noch externe
Leitungen enthalten sind, wirken sich kleine Serienwiderstände (z.B. 33
Ohm) sehr vorteilhaft auf die Signalintegrität aus. Gerade die
SPI-Taktleitung ist diesbezüglich sehr empfindlich und kann ggf. schon
leichtes "Klingeln" als weitere Impulse ansehen. Daher kann es je nach
Aufbau sogar ratsam sein, am Takteingang zusätzlich einen Tiefpass
vorzusehen, d.h. mit wenigen Picofarad und ebenfalls kleinem
Serienwiderstand. Natürlich darf man dabei den Takt nicht so stark
verzögern, dass die Empfangsrichtung aus dem Tritt gerät.
> Ich würde aber erstmal nur dumme Slaves ansprechen (74HC595, 74HC165)> und zum Laufen bringen.
Genau. Und sinnvollerweise verbindet man diese Bausteine nicht nur mit
den SPI-Leitungen, sondern auch den parallelen Ein- und Ausgängen, so
dass man munter Bitmuster generieren und zurücklesen kann. Das
ermöglicht dann auch quantitative Aussagen über die Signalintegrität.
Vorzugsweise sind natürlich die Parallelverbindungen gespiegelt, um
sicherzustellen, dass man nicht durch Softwarefehler versehentlich die
zu schreibenden Daten statt der ausgelesenen Daten miteinander
vergleicht.
Peter D. schrieb:> Einen Oszi braucht man nicht fürs SPI. Nur etwas Lesen des Datenblattes> und logisches Denken.> Terminiert wird beim SPI auch nichts.
Aua!
Dir reicht Fantasie zum Debuggen einer SPI Verbindung
Du Glücklicher!
Der ESP hat natürlich Strom. Der hängt bis das funktioniert per USB am
PC, der auch die Programme flasht.
@schweigstill Genau so motiviert man Leute, die einer neuen Community
beitreten. /s
@peda. Das wird soweit ich weiß von der Library gehandelt. Die
allermeisten Befehle kommen auch durch und die allermeisten Antworten
auch.
@ukw Ich habe das Schaltbild mal geupdated. So sieht es jetzt aus.
(Anhang)
Der Fehlerverhalten ist allerdings geblieben.
Hört doch mal auf zu mobben. Natürlich hat er eine Masseverbindung und
auch VCC. Mir wurde gesagt die Dupont-Leitungen seien nicht so gut
geeignet, und ich solle lieber Kieselsteine sammeln. Am besten wäre mal
ein Foto wenn Du Dich traust, da kann der ein oder andere vielleicht was
erkennen was stört.
Alexander L. schrieb:> Ich habe das Schaltbild mal geupdated. So sieht es jetzt aus.
Auch im upgedateten Schaltplan fehlt was ganz Elementares: die
Verbindung zum und die Versorgung über USB.
> Der ESP hat natürlich Strom. Der hängt bis das funktioniert per USB am> PC, der auch die Programme flasht.
Und auch der zweite ESP wird über USB versorgt? Und auch die
Masseverbindung zwischen den beiden ESP läuft über diese beiden USB?
Wenn es nicht gerade zwei unterschiedliche PCs sind? Frank hat es ja gut
erklärt, denke es wird angekommen sein. Wenn's nicht so wäre würde es
mit 1 MHz auch nicht funktionieren.
Das ist die aktuelle Verkabelung nochmal als Foto. Nicht wundern, dass
das nicht mehr zu der Pinbelegung aus dem Code passt. Ich habe den HSPI
mit dem VSPI-Bus getauscht.
Der ESP bei dem man den Chip sieht ist der Slave. Der andere ist der
Master.
Sind die Stiftleisten da einfach nur lose in die ESP32-Platinen
reingesteckt, oder warum sind die im einen Fall auf der Oberseite, und
im anderen Fall auf der Unterseite?
@kirnbichler Die sind richtig verlötet. Die sind nur deshalb einmal auf
der Unterseite, weil ich erst dachte, dass ich den kompletten ESP auf
mein Breadboard stecken kann. Dafür war der dann allerdings zu breit.
Beim 2. ESP habe ich das dann gewusst und ihn andersrum verlötet, damit
ich die Kabel anschließen kann und gleichzeitig einfacher an den
Reset-Knopf komme.
Ich glaube deine Slave-Programmierung ist nicht sauber. Bin grad am
Handy, aber kann es so wie du es machst nicht passieren dass der Master
von Slave einen veralteten Buffer bekommt?
LG, Sebastian
Alexander L. schrieb:> Das ist die aktuelle Verkabelung nochmal als Foto
Du verbindest da die internen 3V3 vom Einen mit den 3V3 vom Anderen?
Spannend...
Hast du mal die Versorungsspanungen mal gemessen?
Was passiert, wenn du die beiden ESP programmierst, sinnvoll mit den
nötigen 5V aus 1 Netzteil versorgst und dann die USB-Kabel aussteckst?
Lothar M. schrieb:> Du verbindest da die internen 3V3 vom Einen mit den 3V3 vom Anderen?> Spannend...
Das habt ihr doch so vorgeschlagen!?
Ich denke nicht dass es am Aufbau liegt. Wird wohl eher so ein Software
Ding sein. Die Frequenz wird ja letztendlich in Takte herunter geteilt,
und da gibt es naturgemäß nur Näherungswerte. Kenne mich absolut nicht
aus, aber könnte doch an der Library liegen? Mal die Warnings auf github
gelesen?
Alexander schrieb:> Das habt ihr doch so vorgeschlagen!?
Nein, es wurde vorgeschlagen, beide aus der selben einzigen Versorgung
zu versorgen. Denn zu diesem Zeitpunkt war ja nicht klar, das an beiden
ein USB-Kabel steckt...
> Die Frequenz wird ja letztendlich in Takte herunter geteilt, und da gibt> es naturgemäß nur Näherungswerte.
Bei SPI völlig uninteressant, weil da der Takt mitübertragen wird. Du
musst dich über die Bussysteme und ihre Funktion schlau machen, wenn du
sie einsetzen willst.
Alexander schrieb:> Mal die Warnings auf github gelesen?
1
There is also a known issue that received data is bit shifted depending on the SPI mode
2
Please try SPI mode 0 for this issue
3
But SPI mode 1 or 3 is required based on the official doc
4
Please use this library and SPI modes for your own risk
Sagte ich ja: falscher SPI-Mode. Das betrifft dann alle empfangenen
Datenbits eines der beiden Teilnehmer. Nicht nur einzelne Bits.
Allerdings ist diese Anmerkung ein Indiz dafür, dass der Programmierer
da auch nicht so richtig wusste, was er tat...
@wangnick Das sollte eigentlich passen. Das kann nur auftreten, wenn
zwei Read-Requests hintereinander kommen. Dabei gibt es zwei
verschiedene Fälle:
1. Der Read-Request ist für denselben Pin: In diesem Fall stammt der
Buffer zwar von der letzten Request, aber da zwischendrin keine
Write-Request stattgefunden hat, ist das Ergebnis trotzdem aktuell.
2. Der Read-Request ist für einen anderen Pin: Hier ist zwar das
Valid-Bit gesetzt, aber da es auch die Pin-Nummer in der Antwort
mitschickt, erkennt der Master, dass sich die Antwort auf einen anderen
Pin bezieht, und verwirft das Ergebnis.
Wenn die vorherige Request eine Write-Request war, antwortet der Slave
mit einem 0-Byte. Dabei ist dann auch das Valid-Bit 0.
Was die zusammengeschalteten VCC-Pins der ESPs angeht: Ich hatte die
Antwort vorhin so interpretiert, dass ich das machen soll. Der einzige
Effekt, den das hat, ist dass ich jetzt einen ESP vom USB trennen kann
und er trotzdem weiterläuft. Funktional macht es allerdings keinen
Unterschied.
Was die Warnung auf GitHub angeht: Ich hatte zuerst diese Library
verwendet: https://github.com/hideakitai/ESP32SPISlave. Da ich mit
dieser bereits Probleme hatte, dachte ich, ich probiere mal die andere
aus (also die, die ich gerade nutze). Ich habe auch die known Issues
gesehen und die entsprechenden Workarounds implementiert.
Alexander schrieb:> Lothar M. schrieb:>> Du verbindest da die internen 3V3 vom Einen mit den 3V3 vom Anderen?>> Spannend...>> Das habt ihr doch so vorgeschlagen!?
Wenn das Modul über den 3V3-Pin versorgt wird, dann ja.
Du versorgst aber beide Module über USB (5V). Diese Info kam erst jetzt.
In diesem Fall werden die 3V3-Pins zu Ausgängen durch den jeweiligen auf
der Platine befindlichen Spannungswandler (5V -> 3V3). In diesem Falle
solltest Du tunlichst die 3V3-Verbindung kappen, denn hier treiben dann
2 Ausgänge gegeneinander. Schon bei geringen
Spannungsdifferenzen/Toleranzen fließt dann ein nicht unerheblicher
Strom, welche die 3V3-Wandler unnötig belastet.
Also: Nimm die 3V3-Verbindung zwischen den ESP32 raus - zumindest
solange Du die über USB versorgst. Wenn später die USB-Versorgung
wegfällt, versorge die Module über den 5V-Pin mit 5V, denn ich kenne
nicht den Schaltplan des Moduls. Unter Umständen lässt sich der 3V3-Pin
lediglich als Output nutzen und nicht, um das komplette Modul mit 3V3 zu
versorgen.
Die 3V3-Verbindung zum FE_SRly-Modul ist okay. Dieses wird hier über den
3V3-Output des rechten ESP32-Moduls mit Spannung versorgt.
Alexander L. schrieb:> Der einzige Effekt, den das hat, ist dass ich jetzt einen ESP vom USB> trennen kann und er trotzdem weiterläuft. Funktional macht es allerdings> keinen Unterschied.
Doch, ja, einen gewichtigen. Du musst dir einfach mal die interne
Schaltung der Boards mit einzeichnen...
Du meinst vermutlich nur, dass sich die Funktion dadurch nicht
verbessert/ändert. Das hat mit der Funktionalität aber nur am Rande zu
tun.
Alexander L. schrieb:> Das werde ich ausprobieren.
Hatte ich den Trick mit dem Oszi schon mal erwähnt? Damit kannst du
nämlich sehen, was auf dem Bus los ist. Und schauen ob es zu dem
passt, was dein Programm macht.
Derzeit ist es, wie wenn du mit verbundenen Augen nach Gehör mit dem
Auto fährst. Das kann eine Zeit lang gut gehen. Du siehst und erkennst
dann allerdings nicht, warum es wieder mal nicht gut gegangen ist.
Okay, ich habe die 3.3V Pins wieder getrennt.
Was allerdings ein Problem ist, ist dass diese ganze Geschichte nur eine
Komponente von einem größerem Open-Source Projekt ist, welches ich
entwickle.
Besagtes Projekt läuft auf einem RaspberryPi und es wäre ganz nett
gewesen eine Möglichkeit zu haben die GPIO-Pins des Pis erweitern zu
können.
Der Pi wäre dann der Master und der ESP würde als GPIO Erweiterung
funktionieren. Die Master-Komponente müsste ich allerdings nochmal in
Java neu schreiben. Der Aufbau hier war eigentlich nur für mich gedacht,
damit ich mich mal etwas in das Thema SPI einfinden kann.
Ich baue die Komponente jetzt mal lieber nochmal direkt mit Java auf der
Master Seite. Bevor ich hier die Arbeit doppelt mache.
Wichtig ist vor allem, dass man das ganze am Ende auch als dritter
reproduzierbar nachbauen kann.
Alexander L. schrieb:> Besagtes Projekt läuft auf einem RaspberryPi und es wäre ganz nett> gewesen eine Möglichkeit zu haben die GPIO-Pins des Pis erweitern zu> können.
Der Raspberry Pi kann sicherlich auch I2C, und für I2C gibt es fertige
ICs, die man als Portexpander verwenden kann. Die müssen dafür nicht
eigens programmiert werden und sind deutlich unkomplizierter zu
handhaben als ausgerechnet ein ESP32.
Hier ein willkürlich ausgesuchtes "Tutorial" dazu:
https://tutorials-raspberrypi.de/raspberry-pi-gpios-erweitern-mittels-i2c-port-expander/
@kirnbichler Das stimmt zwar, allerdings ist SPI wesentlich schneller
als I2C. An diesen Erweiterungskarten hängen im Worst Case schnell
laufende Schrittmotoren und der Pi unterstützt für I2C leider nur eine
Bandbreite von 400kBit/s. Wobei man die Step-Pin auf auf den nativen
Pi-Pins lassen könnte und nur Direction und Enable auf die Karte legt.
Das würde vermutlich gehen. Aber es wäre schon irgendwie cooler, wenn
auch die Step-Pin dort liegen könnte. Ist halt die Frage ob das den
Aufwand wert ist.
Alexander L. schrieb:> Hab ich da was übersehen?
Dass das USB Kabel und ESP Modul wahrscheinlich nicht genug Strom für
das Relais liefern. Die Stromaufnahme des ESP Moduls alleine ist schon
für viele USB Kabel zu viel. Kurzzeitig brauchen die Module etwa 500 mA.
Mit einem Oszilloskop könntest du die Stabilität der Stromversorgung
prüfen.
Deine GND Verbindungen über das Steckbrett und Dupont Kabel würde ich
durch gelötete Kupferkabel ersetzen, welche erheblich besser leiten. Wie
viel Spannung auf dieser GND Verbindung abfällt, könntest du auch wieder
mit einem Oszilloskop prüfen. Ein Multimeter taugt dazu nicht, denn es
geht um hohe Frequenzen die sich zum DC Anteil überlagern.
Schrittmotor-Signale über einen per SPI angebundenen Port-Expander von
einem Raspberry Pi auszugeben ist Unsinn, das wird nur umständlich (wenn
überhaupt) irgendwie stabil und bleibt immer langsam. Vernünftiger
funktioniert das so wie hier mit externem µC der sich um das Timing
kümmert https://github.com/scottalford75/Remora oder gleich FPGA z.B.
mesa 7i90, 7c80 oder 7c81.
Alexander L. schrieb:> @stefanus Das Relay kommt laut Datenblatt mit 3,3V klar und hat ne> Flyback Diode. Hab ich da was übersehen? Noch steht alles.
Ja, die Stromaufnahme beträgt 120 mA und es muss 03 drauf stehen. Dann
sollte es klappe(r)n.
Alexander L. schrieb:> ESP als GPIO Erweiterung
Technischer Overkill.
Nimm doch handelsübliche LVTTL Schieberegister wie der Rest der Welt.
Die kannst du auch per SPI ansteuern.
Andreas S. schrieb:> Oder mit einem speziell für solche Anwendungen entwickelten Schritt- und> Rampengenerator, z.B. Trinamic TMC429, TMC4210 oder TMC4361:>> https://www.trinamic.com/products/integrated-circuits/
oder gleich Arduino-kompatibel, Rampengenerator mit eingebauter
Schrittmotor-Endstufe in Form eines Nucleo mit STM Powerstep01 (falls
das wieder lieferbar ist). Damit kann man alles was mit Schrittmotoren
von der Leistung her Sinn macht ansteuern.