Moin, gibt es vielleicht doch Beispiele für eine gelungene und "normale" I2C Slave Implementierung auf dem ESP32, idealerweise für die Arduino IDE, gerne aber auch direkt per IDF? Mit "normal" meine ich, dass der Slave vom Master direkt und ohne speziellen Wrapper angesprochen werden kann, wie es dieser Workaround erfordert: https://github.com/gutierrezps/ESP32_I2C_Slave Ziel ist ein I2C Slave, der von beliebigen Mastern aus z.B. klassisch per Register angesprochen werden kann. Hintergrund: Espressif hat bis heute den Slave Modus beim ESP32 nur unvollständig implementiert und dokumentiert (https://github.com/espressif/esp-idf/issues/2202), v.a. in Bezug auf Interrupts (https://github.com/espressif/esp-idf/issues/3099). Die Wire library von Espressiv kennt kein onRequest() (https://github.com/espressif/arduino-esp32/issues/118). Es gibt zwar schon Leute, die an Lösungen arbeiten, bei denen geht aber seit Jahren nichts voran (z.B. https://github.com/espressif/esp-idf/pull/2096). Alles, was die Espressiv API für Slaves anbietet (https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/i2c.html#communication-as-slave) sind die Funktionen i2c_slave_read_buffer() und i2c_slave_write_buffer(). Bei denen besteht aber wohl das Risiko, unvollständige Pakete zu erhalten oder zu senden (vgl. https://github.com/gutierrezps/ESP32_I2C_Slave "This usage of the API functions raise some problems.") Die angesprochene Library löst das mit einem Datenwrapper, der die Integrität der Pakete sicherstellen soll, aber auf Seiten des Masters voraussetzt, dass die Pakete eben entsprechend verpackt werden. Das geht vielleicht noch in geschlossenen Projekten, für einen Slave, der wie jedes andere I2C-Gerät von beliebigen Mastern ansprechbar sein soll, kommt das aber nicht in Frage. Andere Lösungsansätze? Ein Kommentar bei einem der o.g. issues (https://github.com/espressif/esp-idf/issues/3099#issuecomment-467725985) deutet eine Lösung mit einem "high priority task blocked on i2c_slave_read_buffer" an, dazu konnte ich aber nichts weiter finden. Ich stelle mir das so vor, dass ein solcher Task ähnlich wie ein Interrupt wirkt und implementiert werden kann, denn er schläft bis Daten vom Master angekommen sind und blockiert dann aufgrund seiner Priorität den Haupttask. Bisher habe ich aber noch keine Erfahrung mit Multitasking und inter-task Kommunikation auf dem ESP32. Ich arbeite mich da gerne rein, möchte Sackgassen aber vermeiden, denn diese Kommentare z.B. klingen leider wenig optimistisch: https://github.com/espressif/arduino-esp32/issues/118#issuecomment-812974529 , https://github.com/espressif/arduino-esp32/issues/118#issuecomment-823695741 Ich freue mich daher über eine Einschätzung aus berufenerem Munde, ob das so klappen könnte. Mir wäre bei der Lösung auch nicht klar, wie ein request von einem normalen receive unterschieden wird und wie es mit dem clock stretching aussieht. Außerdem wäre mir nicht klar, wie dieses Blocking genau aussehen würde, denn geblockt werden darf ja nur der high priority task, nicht der Haupttask mit niedrigerer Priorität. Gruß Jan
Danke für die Erkärungen. Ich habe das gleiche Problem. Ich wollte das ESP32 als slave benutzen. Jedoch sehe ich Probleme wie du jetzt. Vermutlich werde ich dann den ESP32 als Master mit der ARDUINO-Bibliothek benutzen das scheint mir an effektivsten zu sein. Mein anderer Up muss dann wohl gehorchen....
Kurze Info: Wurde vor ein paar Tagen gefixt: https://github.com/espressif/arduino-esp32/pull/5746 Dauert wohl noch bis es dann in einem Release landet, der dann wiederum auf PlatformIO landen muss, für Leute die das einsetzen. Btw als WO besteht noch dieser hier: https://github.com/gutierrezps/ESP32_I2C_Slave
:
Bearbeitet durch User
ESP4096 S. schrieb: > Dauert wohl noch bis es dann in einem Release landet, der dann wiederum > auf PlatformIO landen muss, für Leute die das einsetzen. Heute endlich erschienen: https://github.com/espressif/arduino-esp32/releases/tag/2.0.1 "Wire-Slave is now implemented" - Halleluja! Die Doku https://docs.espressif.com/projects/arduino-esp32/en/latest/api/i2c.html#i2c-slave-mode spricht allerdings immer noch von einer nach Workaround klingenden Funktion Wire.slaveWrite(). Aus der kurzen Beschreibung und dem unten auf der Seite stehenden Beispiel werde ich ad hoc nicht ganz schlau. Ist wohl erst mal ausprobieren angesagt. vg Jan
Jan schrieb: > Ist wohl erst mal ausprobieren angesagt. Bitte berichte, was du dabei heraus findest. Ich nutze den ESP32 noch nicht, bin aber sehr gespannt darauf.
Ich befürchte, eine flexible Lösung wie bei anderen Controllern wird man nie erreichen. Das I2C-Interface ist eigentlich wie eine Art "Sequenzer" aufgebaut, und man kann das nicht einfach auf Byte-Ebene runterbrechen. Das gilt übrigens auch für den Master-Mode, wo sich auch nur eine komplette Übertragung mit Start und Stop einstelen lässt. "Einfach mal so" eine Startkondition + Adressbyte senden und dann schauen, wie man weiter verfährt ist nicht vorgesehen. Und wenn man mehr Daten als die internen Puffer übertragen will, muss man ständig überwachen oder DMA nehmen. Gleiches gilt übrigens auch für SPI. Für mich ist das insoweit ärgerlich, dass ich meine HAL Highlevel-Bibliotheken, die auf "i2c_send_start()", "i2c_send_byte(data)" etc. aufbauen hier nicht mehr nutzen kann. Inzwischen habe ich mir mit einem Software-I2C beholfen, aber eine optimale Lösung ist das nicht. Dazu möchte ich noch anmerken, dass die ESP32 Dokumentation lückenhaft ist und dazu noch jede Menge Fehler beinhaltet. Jörg
Stefan ⛄ F. schrieb: > Jan schrieb: >> Ist wohl erst mal ausprobieren angesagt. > > Bitte berichte, was du dabei heraus findest. Dann tue ich das doch mal: Es geht jetzt (yippie!) und das bisher ziemlich reibungslos, zumindest was das Kompilieren eines typischen Wire-Sketches angeht. Im Test stellt sich dann aber heraus, dass die Daten vom Slave immer um einen Zyklus versetzt zu spät kommen. Das hat mit der Ausnahme zu tun, die Jörg schon angedeutet hatte: Joerg W. schrieb: > "Einfach mal so" eine Startkondition + Adressbyte senden und dann schauen, wie man > weiter verfährt ist nicht vorgesehen. Sprich: Beim requestEvent() haut der Slave einfach raus, was bisher in den Buffer geschrieben wurde. Alle Wire.write() innerhalb vom requestEvent() kommen zu spät und werden erst im nächsten Zyklus rausgeschickt. Im Prinzip kann requestEvent() also komplett leer bleiben, den Buffer kann man im Hauptprogramm füllen, sobald man weiß, was rein soll. Heißt aber: Spontanes Reagieren im Interrupt, z.B. Versenden von Default-Daten falls vorher keine spezifischen angefordert wurden oder Messwert erst zum Zeitpunkt des Requests auslesen, geht also nicht ohne Workarounds. Hier eine funktionierende Implementierung des requestEvent() mit bedingter Kompilierung für AVR/ESP32: https://github.com/ftjuh/AccelStepperI2C/blob/b00b994dbfd08128db3c431e701d63821b1d35fc/firmware/firmware.ino#L900 Hier die Stelle, wo für den ESP32 der Buffer vorab gefüllt wird: https://github.com/ftjuh/AccelStepperI2C/blob/b00b994dbfd08128db3c431e701d63821b1d35fc/firmware/firmware.ino#L852 (Rückmeldungen willkommen, ich habe wenig Erfahrung mit C++, das Projekt ist noch work in progress). Joerg W. schrieb: > Dazu möchte ich noch anmerken, dass die ESP32 Dokumentation lückenhaft > ist und dazu noch jede Menge Fehler beinhaltet. Damit hadere ich auch. Was genau slaveWrite() vs. Write() macht wird mir [anhand der Doku und des Beispielcodes](https://docs.espressif.com/projects/arduino-esp32/en/latest/api/i2c.html#id2) nicht klar. Außerdem ist [das Beispiel](https://docs.espressif.com/projects/arduino-esp32/en/latest/api/i2c.html#example-application-wireslave-ino) irreführend, da dort innerhalb von onRequest() Daten (mit Wire.print(), i.e. Wire.write()) geschrieben werden, was aber den irreführenden Eindruck macht, die würden dann auch tatsächlich mit diesem Interrupt verschickt (s.o.) vg Jan
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.