I2C mit Startbyte am Uno

Hallo,
ich suche nun schon seit ein paar Tagen nach Hinweisen und kann leider nichts finden.
Folgendes Problem:
Ich habe ein Modul, dass ich testen soll. Auf diesem Modul ist ein MSP430, in dem die I2C-Schnittstelle per Software umgesetzt wurde. Das zu testende Modul ist ein Slave.
Ich muss jetzt einen I2C-Master erstellen und dies wollte ich mit einem Arduino versuchen, da ich auch noch mit der Clock-Frequenz sehr weit runter (4kHz) muss.
Da der Kollege im MSP die Schnittstelle per Software umgesetzt hat, erwartet er folgenden Aufbau der "Telegramme"

  • Startbedingung
  • Startbyte
  • kein Acknowledge
  • wiederholte Starbedingung
  • Adresse
  • Lesen oder Schreiben
  • ...
    Nun ist meine Frage, wie ich das Startbyte mit der Wire-Bibliothek umsetzen kann?
    Ich habe schon versucht mit Wire.requestFrom zu tricksen, indem ich 0 Bytes lesen. Aber leider bekomme ich dann nach dem Byte eine Stoppbedingung und erst dann wieder eine Startbedingung.
    Das zu testende Modul erwartet leider nach jeder Stoppbedingung wieder das Startbyte und so drehe ich mich im Kreis, da ich nach dem Startbyte kein Acknowledge bekomme.

Wäre für jeden Tipp dankbar!

Schöne Grüße

Ich weiss ja nicht, was bei Dir ein Startbyte ist, aber wenn die Abfolge korrektes I2C sein soll, dann muss das die Adresse sein (mit Lese-/Schreib-Bit).

Wenn es die Adresse ist, dann geht das folgendermassen:

Wire.beginTransmission(address);
Wire.endTransmission(false);
Wire.requestFrom(address, 2);

Das Konzept sollte auch mit Schreiben funktionieren, aber das wäre dann schon fast eine Vergewaltigung des Standards.

Das Startbyte wurde eingeführt, um Controller "zu wecken". Früher brauchten die Controler ein wenig Zeit, um in Gange zu kommen.
Mit dem Startbyte hatten sie ein "Byte" Zeit um zu starten. Danach konnten dann die Daten aufgenommen werden. Dies war und ist nötig, wenn die Schnittstelle eine Softwareschnittstelle ist.
Das Byte ist folgendes 0000 0001. Dies muss vor der eigentlichen Adresse gesendet werden.

https://www.i2c-bus.org/addressing/start-byte/

Das hört sich nach so einer Art Broadcast an, ist es aber gar nicht, wenn man die Beschreibung liest. :wink:
Denn nach meinem Verständnis müsste ein

Wire.beginTransmission(address);

von dem "StartByte" und einem erneuten Transmission-Beginn gefolgt werden?

Formal ist das Startbyte ein Read von Adresse 0, sollte also kein Problem sein.

EDIT: der Rest ist für ein Write, paßt also nicht für ein Startbyte :frowning:

Wire.beginTransmission(0);
Wire.endTransmission(false);

Danach den eigentlichen Transfer mit der richtigen Adresse abwickeln.

imho gar nicht, da nach der Adresse+RW ein Ack gesandt wird und das in deiner Aufstellung nicht vorkommt.

Der liebe Kollege soll sich seinen Master auch schreiben und dessen Code übernimmst du dann.

Ein ACK kann nur von einem Slave generiert werden. Wenn kein Slave angesprochen wird, dann gibt es kein ACK und die Übertragung wird sowieso abgebrochen. Also genau das was verlangt wird. Ob danach ein Start oder wiederholter Start erfolgt bleibt eigentlich egal, da dieser Unterschied nur die multi-master-arbitration betrifft.

Guten Morgen,
leider mag Wire die Adresse 0 so nicht.

Wire.beginTransmission(0);
Wire.endTransmission(false);

Die Zeilen werden leider nicht ausgeführt. Wahrscheinlich, da die ersten Adressen reserviert sind.

Die Zeilen werden schon ausgeführt, so funktioniert ein I2C Scanner. Es wird nur ein Fehler gemeldet, nämlich daß sich kein Slave meldet. Zum Startbyte paßt das aber leider nicht, denn das erwartet ein Read, kein Write.

Vorschlag:

  1. Testen requestFrom(0, 0); oder irgendeine Anzahl. Wegen fehlendem ACK der Adresse sollte das immer einen Fehler liefern, der hier aber egal ist.
    Mögliches Problem: der Bus bleibt nicht offen, d.h. die nächste Übertragung startet mit Start und nicht mit wiederholtem Start.

  2. Schreiben von 0 Bytes auf Adresse 0 und Bus offen lassen.
    Mögliches Problem: ist Write statt Read.

  3. SoftWire Bibliothek benutzen und ggf. erweitern.
    Die Wire Bibliothek wird ziemlich sicher nicht erweitert, da dies für jeden einzelnen Controller geschehen müßte.

Dann werde ich wohl mal schauen, ob ich irgendwie die Wire-Bibliothek anpassen bzw. erweitern kann.
Leider habe ich da noch nicht so die Erfahrung.
Ich muss so etwas irgendwie hinbekommen:
image

Merkwürdigerweise kann ich jedoch nichts auf dem Scope sehen, wenn ich folgenden Code ausführe.

TWBR = (F_CPU/(speed*1000) - 16)/(2*64);
      //Wire.requestFrom (0x01, 1, false);
      //Wire.write (0x01);
      //Wire.end ();
      //Wire.endTransmission ();
      Wire.beginTransmission (0x00);
      Wire.endTransmission (false);
      Wire.beginTransmission (0x22);
      //Wire.begin (0x22);
      //Wire.write (0x22);
      Wire.write (0x05);
      Wire.write (0x19);
      Wire.endTransmission ();

Dies auskommentierten Zeilen kommen durch mein rumprobieren.

Dann hast Du keinen Slave, der auf die Adresse 0x22 reagiert und daher wird die Übertragung nach der Adresse abgebrochen. Der von endTransmission() gelieferte Code sollte den Fehler 2 melden.

Der Slave antwortet nicht auf 0x22, da das Startbyte und der wiederholte Start fehlt.
Werde mal die Codes ausgeben.

Dann würde ich lieber den Slave verändern!

Mal mit DS3231 probiert:

  Wire.beginTransmission( 0 );
  //Wire.write(0); // set DS3231 register pointer to 00h
  Wire.endTransmission(false);
  Wire.requestFrom(DS3231_I2C_ADDRESS, 3);
  *second = bcdToDec(Wire.read() & 0x7f);
  *minute = bcdToDec(Wire.read());
  *hour = bcdToDec(Wire.read() & 0x3f);

Dein Bild in #10 kann ich nicht gut erkennen, sieht doch abgesehen von der Adresse ähnlich aus, oder?

Übrigens Adresse: Wire nimmt nur die linken sieben Bit, aus 0x68 wird 0xD0 und 0xD1 im Scope.

Du hast recht, eigentlich wäre es für mich das einfachste, wenn der Slave angepasst wird.
Leider wird das Teil seit 2008 so gebaut und nun gibt es ein Update, dass ich testen soll. Dummerweise müssen die alten und neuen auf der Schnittstelle kompatibel bleiben.

@agmue Leider kommt nach dem Sender der 0 eine Stoppbedingung. Und leider bekommt dies mein Slave mit und sagt dann: "Ah ein Stopp. Alles wieder von vorne bitte" :woozy_face:

Wenn ich das richtig in der Wire.cpp bzw. twi.c sehe, erkennt die Routine, dass kein Acknowledge gekommen ist und sendet daher ein Stopp. Auch wenn man bei Wire.endTransmission ein false übergeben hat.

UNO, ATtiny95 und ESP32 als I²C-Slave sind kein Problem, daher stelle ich die Frage, ob eine Verwendung der I²C-Hardware überhaupt sinnvoll ist. Bei 4 kHz geht das eventuell auch mit normalen Pins.

Könntest Du bitte das Bild in #10 besser aufgelöst zeigen?

Leider habe ich das Bild aus #10 nicht besser. Habe den Screenshot vom Kollegen bekommen, als ich ihn fragte, wie die Telegramme aussehen sollen.
Habe mir auch schon die Bibliothek SoftwareWire angeschaut. Ohne Anpassungen sieht das Ergebnis genau so aus, wie mit der Wire-Bibliothek.
Bin gerade dabei, zu schauen, welche sich einfacher anpassen lässt.

wohl eher die SoftwareWire damit du alles im Griff hast.

Aber in Deinem Kopf gibt es doch ein Bild, wie Du es Dir vorstellst, das könntest Du visualisieren.