Forum: Mikrocontroller und Digitale Elektronik I2C/TWI kommunikation. Slave antwortet nicht.


von J. T. (chaoskind)


Angehängte Dateien:

Lesenswert?

MoinMoin,

ich versuche mich grad an einer I2C Kommunikation mit einem LSM6DS0. 
Master ist ein Atmega2560.(3Achsen-Gyro und 3Achsen 
Beschleunigungssensor von ST)
Datenblatt: 
http://www.st.com/st-web-ui/static/active/en/resource/technical/document/datasheet/DM00101533.pdf.

Hierbei habe ich folgendes Problem bzw 2 Probleme. Wenn ich versuche 
einen Wert zu lesen (dazu auch Seite29 vom Datenblatt) Sende ich erst 
einen Startsignal, dann die I2C-Adresse von Sensor+W. Als nächstes Sende 
ich die Adresse vom Register, das ich lesen will. Dann sende ich eine 
RepeatedStartCondition und dann die I2C-Adresse+R. Jedoch "liest" er 
immer nur die I2C-Adresse+R zurück, also das was ich als letztes ins 
TWDR geschrieben hab. Ich vermute also, das er garnicht erst liest. 
Obwohl im Protokoll vom LogicAnalyzer ein Read auftaucht.

Das 2te Problem ist, das er sich beim 2ten Ausleseversuch aufhängt, bei 
der Abfrage ob TWINT gesetzt wurde. Das konnte ich soweit zurückfolgen, 
dass es scheinbar an einer fehlerhaften StopCondition am Ende der ersten 
Übertragung liegt. Die Stopcondition wird gesendet, aber danach ist 
TWINT immer noch gesetzt. Wenn ich es danach noch einemal explizit von 
lösche(durch 1 reinschreiben) bleibt es auch nach der Stop gelöscht, und 
die weiteren Abfragen klappen. Aber sollte es nicht eigentlich mit der 
StopCondition getan sein?

Der Quelltext ist im Anhang, bei TWI_READ-Funktion beginnt bei Zeile 
198.

Mit freundlichen Grüßen und Hoffnung auf Hilfe,
Chaos

von J. T. (chaoskind)


Angehängte Dateien:

Lesenswert?

Hier noch ein Bild vom LA. P.S. Der Sensor selbst ist auf einem 
Sensorshield X-Nucleo-IKS0A1 und der 2560 ist mal ArduinoMEGA2560 
gewesen. Also die Hardware sollte es nicht sein

von Tim (Gast)


Lesenswert?

J. T. schrieb:
> Hierbei habe ich folgendes Problem bzw 2 Probleme. Wenn ich versuche
> einen Wert zu lesen (dazu auch Seite29 vom Datenblatt) Sende ich erst
> einen Startsignal, dann die I2C-Adresse von Sensor+W. Als nächstes Sende
> ich die Adresse vom Register, das ich lesen will. Dann sende ich eine
> RepeatedStartCondition und dann die I2C-Adresse+R.

Soweit richtig.
Dann wartest du auf TWINT und liest TWDR. Falsch.
Das TWI möchte zu dem Zeitpunkt (statuscode $40) von dir wissen
ob es ein Ack oder ein Nack nach dem als nächtes zu lesenden Datenbyte
senden soll.
Also TWINT ( und TWEN) und TWEA setzen und eine runde warten.
Dann hast du die daten im TWDR.

> Obwohl im Protokoll vom LogicAnalyzer ein Read auftaucht.

Du setzt (1 << TWINT) | (1 << TWEN) | (1 << TWSTO).
Das ist illegal. Das Twi mach dann ein Read + NACK + Stop.

Tipp:
Bau dir eine ISR die auf grund des Statuscodes vom TWI entscheidet
was als nächtes zu machen ist. Genau dafür gibt es die nämlich.

von J. T. (chaoskind)


Lesenswert?

Kleine Korrektur, das Problem bei Problem2 scheint zu sein, dass die 
StopCondition nicht beendet wird. Ich habs grad nochmal durchgesteppt.

Aber wenn ich dann nochmal TWINT und TWEN setze, damit also TWSTO 
lösche, dann geht es (Auskommentierte Zeile 257)

von J. T. (chaoskind)


Lesenswert?

Tim schrieb:
> Soweit richtig.
> Dann wartest du auf TWINT und liest TWDR. Falsch.
> Das TWI möchte zu dem Zeitpunkt (statuscode $40) von dir wissen
> ob es ein Ack oder ein Nack nach dem als nächtes zu lesenden Datenbyte
> senden soll.
> Also TWINT ( und TWEN) und TWEA setzen und eine runde warten.
> Dann hast du die daten im TWDR.

Danke dir erstmal für deine Antwort. Dazu hatte ich Atmega-Datenblatt 
gelesen, dass das TWEA nur benötigt wird, wenn mehrere Daten gelesen 
werden.

Ich werds mal versuchen und mich dann zurückmelden.

Ah vergessen abzuschicken.

Der Fehler war tatsächlich, das ich nach dem Übertragen SLA+R nicht ein 
zweites Mal TWINT und TWEN gesetzt habe, nach dem Stautscode 0x40. Genau 
wie du gesagt hast, also vielen vielen Dank dafür, darauf wäre ich nach 
den Datenblättern nie gekommen. Das TWEA ist übrigens unnötig, wenn du 
nur einen Wert/ein Byte lesen willst. Gerade ausprobiert.

MfG Chaos

P.S.
Das mit der ISR wird als nächstes kommen, ich wollte aber überhaupt 
erstmal einen Mucks aus dem doofen Teil rausbekommen ;-)

von J. T. (chaoskind)


Lesenswert?

Ich muss mich nochmal überschwenglich bedanken. Drei Tage hab ich 
rumprobiert und geflucht. Und nun zaubert es mir ein tiefentspanntes 
Lächeln ins Gesicht, wenn sich die Zahlen auf der Console in 
sinnvollerweise ändern, wenn ich das Ding beweg. Also noch sind die 
Signale sehr verrauscht, aber jetzt wo ich weiß wie es geht, kann ich 
das ja alles mal ausprobieren, was da im Datenblatt so über High und 
Lopässe schwadroniert wurde *gg

Also nochmal vielen Dank!!

von J. T. (chaoskind)


Lesenswert?

Tim schrieb:
> Du setzt (1 << TWINT) | (1 << TWEN) | (1 << TWSTO).
> Das ist illegal. Das Twi mach dann ein Read + NACK + Stop.

Hierzu aber doch noch eine Frage. Genau das soll man laut Datenblatt ins 
TWCR schreiben, um eine Stopcondition zu erzeugen. Und damit klappt es 
jetzt auch.
Oder ist die Stopcondition generell beim Status 0x40 illegal?

von Tim (Gast)


Lesenswert?

Nach dem SLA+R mit ACK vom Slave kommt das TWI mit Status $40.
Es möchte jetzt wissen ob es 1 (TWEA auf 0) oder mehrere Bytes
(TWEA auf 1) lesen soll. Nach Freigabe via TWINT holt das TWI dann 1 
Byte vom Slave sendet ACK/NACK==TWEA und schreit wieder TWINT.
Dann TWDR auslesen und status auf folgendes Prüfen:
- Statuscode $58 wenn das letze Byte gelesen wurde (TWEA war 0)
  und du darfst STOP/Restart/ senden.
- Statuscode $50 wenn noch mindestens ein weiteres Byte gelesen
  werden soll (TWEA war 1) und du darfst NUR ACK/NACK (TWEA) senden.

So kannst du auch mehrere Register am stück lesen.
(Einfach TWEA auf 1 so lange du willst) Die meisten
I2C Chips erhöhen die Registeradresse bei jedem read selbst

> Oder ist die Stopcondition generell beim Status 0x40 illegal?
Laut "Status Codes for Master Receiver Mode" ist STA/STO immer 0.
ergo illegal. Kann funktionieren muss aber nicht.

> Das TWEA ist übrigens unnötig, wenn du
> nur einen Wert/ein Byte lesen willst. Gerade ausprobiert.

Jo, ich weiss ja nicht wie viele du lesen willst.
Üblich ist:
START, SLA+W, Register, RESTART, SLA+R, read+ACK, read+ACK,..... 
READ+NACK, STOP


> Das mit der ISR wird als nächstes kommen,

Tipps:
- Am anfang TWSR lesen und dann danach entscheiden.
  (einfach das Datasheet runterprogrammieren)
- ALLE Fehler Abfangen.
- Bau eine Watchdog ein
- Bei Fehler TWSR Speichern. Hilft sehr beim Debuggen.

Dann läuft das Ding unauffällig im Hintergrund.

von J. T. (chaoskind)


Lesenswert?

Jau das werd ich mir dann mal als nächstes zur Brust nehmen. Danke für 
die Tips, in den Watchdog müsst ich mich dann auch erstmal einlesen, den 
hab ich nämlich auch noch nie benutzt. Aber ich denke das wird schon. 
Was ich bisher so nebenbei über ihn mitbekommen hab, klang jetzt nicht 
soooo nach Raketenwissenschaft.

Mit solchen Antworten wie deinen fängt das Forum ja wieder an, richtig 
Spass zu machen =). Kompakt, zielgerichtet, alles drin, was man wissen 
muss!

von Tim (Gast)


Lesenswert?

Das mit Watchdog bezog sich nicht auf den Hardware Wauwau,
Sondern darauf das du die TWI-Transaktionen auf Zeitüberschreitung
überwachst.
Geht relativ einfach wenn du einen Timer IRQ hast der regelmässig kommt.

von J. T. (chaoskind)


Lesenswert?

Tim schrieb:
> Das mit Watchdog bezog sich nicht auf den Hardware Wauwau,
> Sondern darauf das du die TWI-Transaktionen auf Zeitüberschreitung
> überwachst.
Achso!

> Geht relativ einfach wenn du einen Timer IRQ hast der regelmässig kommt.
Ja das lässt sich ja relativ einfach einrichten. Nen Millisekundentick 
hab ich eh meist irgendwo rumfliegen.

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
Noch kein Account? Hier anmelden.