I2C-Bus verstopft?

Hallöle.

Ich mal wieder mit nem Problem.

Folgender Aufbau: in einem Roboter gibt es ein NodeMCU und einen Arduino Nano.
Aufgabenteilung: NodeMCU empfängt Kommandos von einem Mobilgerät, steuert anhand der Berfehle Motortreiber-> das funktioniert.
Zusätzlich reicht der NodeMCU die erhaltenen Befehle an den Nano per I2C weiter, der steuert einen RGB-Strip entsprechend. Das passiert sekündlich.
Ausserdem liest der Nano von Zeit zu Zeit einen Analogpin aus (da hängt ein Spannungsteiler dran-> Akkuüberwachung) und speichert das Ergebnis.
Wiederum von Zeit zu Zeit (alle paar Sekunden) fragt der NodeMCU den Nano nach diesem Wert- woraufhin der ihn auch sendet.
Das Problem ist: ab und zu scheint sich der I2C-Bus aufzuhängen.
Manchmal (aber nich immer) kommen am NodeMCU Werte an, die der Nano nich gesendet hat, aber oft passiert auf der Leitung einfach gar nix mehr.
Merkwürdig ist: weder der Nano noch der NodeMCU bleiben wirklich stehen- es scheint nur I2C betroffen zu sein....

Da teilweise unrichtige Werte als "AkkuStand" beim NodeMCU ankommen, teilweise auch gar nichts (nach nem Neustart wiederum geht es, erstmal), gehe ich von einem Puffer-Problem (Überlauf oder ähnlich) aus.....

So fragt der NodeMCU den Akkustand ab:

void frageAkku()                                 //******************* Akkustand vom Nano abfragen *********************************
{
  Serial.println("Frage Akku ab");
  Wire.beginTransmission(18);       // Kontaktaufnahme zum Nano 
  Wire.write(99);                   // Code 99 senden = Akkufüllstand
  Wire.endTransmission();           // und abschicken
  Wire.requestFrom(18,1);           // Akkufüllstand abfragen, nur ein Byte
    while ( Wire.available() )
   { 
     akkuProzent = Wire.read();
     Serial.print("Akku: ");
     Serial.println(akkuProzent);
     String Akku=String(akkuProzent);
   //  server.send ( 200, "text/plain",Akku);
   }

Bis zur ersten seriellen Ausgabe funktioniert es immer.

Die Fahrbefehle werden so an den Nano weiter gereicht (das passiert sekündlich):

void sendeFahren()                            //********************** Fahrkommando via I2C an Nano senden *************
 {
  if(nanoTipAlt!=nanoTip)           // nur bei neuem Fahrkommando
  {
  Wire.beginTransmission(18);       // Nano hat Adresse 18
  Wire.write(nanoTip);              // Fahrbefehl weiterreichen
  Wire.endTransmission();
  Serial.println(nanoTip);
  nanoTipAlt=nanoTip;
  }

Der Nano handlet die ganze Geschichte so:

void wasEmpfangen()
{
  if (Wire.available()) 
  { 
   byte x = Wire.read();    // Zahl lesen
   Serial.print("Kommando: ");
   Serial.println(x);
   if(x<20)
    {
      fahrKommando=x;
    }
   else
   {
    anFrage=x;
   }
  
   
   }
  }

  void datenAnfrage()
  {
    if(anFrage==99)
    {
      Wire.write(akkuProzent);
      Serial.print("Antworte: ");
      Serial.println(akkuProzent);
    }
  }

Der NodeMCU schickt nur Zahlen von 1-99..
Habe ich die serielle Konsole vom NodeMCU offen, sehe ich, wie er offenbar die Anfrage zum Nano schickt.
Meist kommt einige Male die Antwort zurück, dann nicht mehr. Mitunter jedoch eine falsche...
Die Konsole vom Nano zeigt an, dass, so lange es einwandfrei geht, alles funktioniert- aber irgendwann empfängt er offenbar keine Kommandos mehr.

Jemand eine Idee, was da los ist, und wie man das in Griff bekommen kann?

Hast du zwischen dem Nano und NodeMcu einen Levelshifter für I2C ?

Der Nano handlet die ganze Geschichte so:

Bedenke:
Der Callback wird im ISR Kontext aufgerufen.
Darum sind dort Serial und alle andere Aufrufe sehr bedenklich, bis verboten.

Besondere Aufmerksamkeit ist dort gefordert.

@HotSystems: ja, da ist ein Levelshifter zwischen.
Der wird, auf der einen Seite, vom NodeMCU mit 3.3V, auf der anderen Seite von nem Stepdown mit 5V versorgt- hmmmmm, kann dort das Problem liegen?
Massen sind alle verbunden, aber der Nano hängt nicht am Stepdown-der wird direkt aus dem Akku versorgt....

@combie: Danke für den Hinweis- die sind eigentlich nur zu Debug-Zwecken drin (ohne die Ausgaben hätt ich das Problem nich eingrenzen können, die hab ich, nach und nach, immer näher rangerückt)- aber ich nehm die mal alle raus, ich sehe ja an den Lichtern, obs funktioniert...

hmmmmm, kann dort das Problem liegen?

Pullup zu groß, könnte auch noch sein

Wire.write(akkuProzent);

Ist das nicht zu wenig? An welche Adresse wird da was geschickt? Oder übersehe ich was?
Wenn es die ISR ist, muß da nicht immer was geschickt werden?

Nicht zum Problem gehörig, aber für mich verwunderlich:

  Wire.requestFrom(18,1);           // Akkufüllstand abfragen, nur ein Byte
    while ( Wire.available() )
   {

Warum while bei einem Byte?

Sodele- ich hab mal weiter geforscht, und nach und nach alles andere im Programm deaktiviert.
Ganz offenbar spuckt mir die FastLed-Lib in die Suppe. >:(
Deaktiviere ich die LED-Ausgaben nämlich, läuft die Sache.

Mir fällt keine andere Lösung ein, als alles umzuschreiben, so dass der Nano den Master spielt- dann kann ich dann serielle Daten austauschen, wenn die FastLed nichts zu tun hat.

Oder gibts da noch irgendeinen anderen Trick?

Hast Du das Serial schon aus der ISR rausgeworfen, wie combie geschrieben hat?

Gruß Tommy

Auch das hatte ich deaktiviert, zum testen (komischerweise hat es nie gestört)- aber um das auszuschliessen: ja, auch das.

(komischerweise hat es nie gestört)

Sobald die FiFo voll ist, handelst du dir damit eine Blockade ein!

Denn in der I2C ISR sind die Interrupts gesperrt.
Serial benötigt aber selber Interrupts, um seine FiFo zu leeren.

FastLED sperrt übrigens auch die Interrupts, um das Timing für die LEDs einzuhalten.

Nimm eine digitale Signalleitung vom Slave zum Master die signalisiert wann ein Zugriff 'passt'.

Signal setzen, mal ein paar hundert Millisekunden die LEDs in Ruhe lassen und in der Zeit vom Master bedient werden.

Der Master startet sein I2C Ding wenn er die steigende Flanke des Signals sieht.

Wenn das den normalen Ablauf zu stark bremst oder in der Animation ruckelt,
kannst du eine weitere Leitung, diesmal vom Master zum Slave, benutzen,
mit der der Master signalisiert dass er gerne zugreifen würde.

Der Slave muss dann nur wenn nötig kurz innehalten.

Dass die Knoten jeweils die Signale wieder wegnehmen ist logisch, oder?

Rabenauge:
Oder gibts da noch irgendeinen anderen Trick?

Bei blockierten Interrupts denke ich an WS2812. Beim nächsten Projekt dann doch mal über LEDs mit Takt- und Datenleitung getrennt wie APA102 nachdenken. Dann funktioniert auch eine IR-Fernbedienung.

Eine Signal- oder Meldeleitung (siehe #11) habe ich schon erfolgreich eingesetzt.

Danke euch-ihr seid, wie immer, Spitze. :slight_smile:

Ja, es sind WS2812. Der Grund, warum diese, ist ganz einfach: die lagen hier so rum.... :slight_smile:
Eigentlich sollte das Ganze nix weiter werden, als ein Roboter-Chassis (mit Ketten) um eben dieses mal eine Weile zu testen.
Naja-dann kam der Spieltrieb eben durch, und zufällig kam mir ein NodeMCU in die Finger-wieso also nicht gleich ne App basteln und das Ding per Handy steuern- Licht wäre auch cool.....und schon uferts wiedermal aus, hehe....inzwischen liegt hier noch ein Servo rum, ein Sharp-IR-Entfernungsmesser, ein Kompass und ein BMP 280 (wobei noch nicht sicher ist, ob der ganze Krempel da wirklich alles verbaut wird, ich weiss selber, dass ich schon wieder völlig übertreibe).... :o

Inzwischen läuft die Sache-der Trick mit der zusätzlichen Busy-Leitung hat funktioniert.
Zwar hab ich jetzt ein lausiges Timing (teilweise wird der Akku-Füllstand vom NodeMCU nur alle paar Minuten überhaupt mal abgefragt, und auch die Beleuchtung reagiert mitunter erst mit mehreren Sekunden Verzögerung), aber da hab ich schon Ideen, wie ich das in Griff kriegen sollte.
Wichtig ist ja erstmal, dass es zuverlässig läuft.