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.
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?
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.
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.
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.
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.
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 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.
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.
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.
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.
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.
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?
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?
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.
@wangnick Das sollte eigentlich passen. Das kann nur auftreten, wenn zwei Read-Requests hintereinander kommen. Dabei gibt es zwei verschiedene Fälle:
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.
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.
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.
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.
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.
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.
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:
@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.
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.
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.
Oder mit einem speziell für solche Anwendungen entwickelten Schritt- und Rampengenerator, z.B. Trinamic TMC429, TMC4210 oder TMC4361:
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.