Forum: Mikrocontroller und Digitale Elektronik AVR i2c: "Empfang abbrechen" am Master


von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Hallo allerseits,

ich versuche gerade folgende Situation anhand des Datenblattes zu 
verstehen, was mir nicht richtig gelingen will:

zwei ATmega328P über I2C verbunden. Der Slave ist eigentlich reiner 
"Befehlsempfänger", liefert also keine Daten. Aber er benötigt für 
gewisse empfangene Befehle eine (unbekannte) Zeit, diese zu verarbeiten, 
kann solange also keinen weiteren Befehl über I2C empfangen (um genau zu 
sein: den nächsten schon, den übernächsten quittiert er per NAK)

Um das "flüssig" zu gestalten, habe ich mir eine Art "Busy-Flag" 
überlegt: die einzige Lese-Operation die der Slave kennt, ist das 
busyFlag lesen.

bevor der Master also einen Befehl absendet, macht er zuerst ein 
i2c-read, prüft ob das busy-Flag gesetzt ist, und wiederholt diese 
Prüfung solange, bis der Slave bereit ist.

Um Overhead zu sparen, würde ich das gerne als fortlaufende 
Leseoperation ausführen. also eine START-Condition, viele 
Lese-Operationen, solange bis BusyFlag = 0, danach ein RESTART im 
Write-Mode, und befehl senden.

Das ist jetzt etwas knifflig, was das ACK/NAK des Slaves betrifft: Der 
master muss eigentlich immer ein ACK senden, da er erst nachher das 
empfangene Byte prüfen kann. Der Slave muss daher auch immer ein ACK 
erwarten.

Wenn jetzt das Busy-Flag gelöscht ankommt, will der Slave eigentlich 
weitersenden, da der Master vorher ein ACK gesendet hat. Ich würde jetzt 
aber gerne ein RESTART+WRITE senden.

Wenn ich das tue, bleibt mir irgendwie der Bus hängen.

Leider finde ich diese Kombination im Datenblatt so nicht, das einzige 
was irgendwie passen würde wäre ein Bus Error. Das scheint es aber nicht 
zu sein.

bevor ich mühsam mit dem Oszi auf den Bus losgehe, und beginne Bits zu 
zählen: Hat jemand eine Idee, woran das liegen kann, bzw. wie man das 
sauber macht?

Danke, Michi

von Joachim B. (jar)


Lesenswert?

Michael R. schrieb:
> Der Slave ist eigentlich reiner
> "Befehlsempfänger", liefert also keine Daten.

Michael R. schrieb:
> bevor der Master also einen Befehl absendet, macht er zuerst ein
> i2c-read, prüft ob das busy-Flag gesetzt ist, und wiederholt diese
> Prüfung solange, bis der Slave bereit ist.

verstehe ich noch nicht ganz

wenn der AVR I2C slave busy senden soll dann ist er kein reiner 
Empfänger.

Ich vermute mal es ist ein "ähnliches" Problem wie ich am I2C EEPROM 
hatte.

Alle AT24C32/64 Libs arbeiteten nach einem write mit delay_ms(5); das 
nervte irgendwie.

Dann dachte ich an i2c clock stretching, aber wie feststellen und fand 
den Weg das der I2C solange blockiert ist also bei weiterer Abfrage ein 
error liefert und wartete bis der error weg war, das verkürzte 
Schreiboperationen im I2C EEPROM deutlich.

Also statt auf NotBusy zu warten, warte doch einfach bis ein Zugriff 
keinen Error mehr liefert

bzw. statt warten eine ISR mit Flagabfrage state machine

von (prx) A. K. (prx)


Lesenswert?

Wenn beide Seiten bei I2C mit Interrupts arbeiten geht das auch 
wesentlich einfacher: Der Slave schaltet seinen I2C Interrupt ab, wenn 
er nicht mehr bereit ist, und ein, wenn er es wieder ist. Der Master 
bleibt dann ggf. im Clock Stretching hängen. Dank Interrupts 
verschwendet niemand dabei Zeit.

von (prx) A. K. (prx)


Lesenswert?

Michael R. schrieb:
> Wenn jetzt das Busy-Flag gelöscht ankommt, will der Slave eigentlich
> weitersenden, da der Master vorher ein ACK gesendet hat. Ich würde jetzt
> aber gerne ein RESTART+WRITE senden.

Schon mit STOP + START statt REPEATED START versucht?

von Tom (Gast)


Lesenswert?

Joachim B. schrieb:
> wenn der AVR I2C slave busy senden soll dann ist er kein reiner
> Empfänger.

Gut erkannt, wobei ein I2C-Slave immer gesendet wird. Von sich aus tut 
der gar nichts ;-)

Michael R. schrieb:
> die einzige Lese-Operation die der Slave kennt, ist das
> busyFlag lesen.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Joachim B. schrieb:
> wenn der AVR I2C slave busy senden soll dann ist er kein reiner
> Empfänger.

Stimmt. "reiner Empfänger" war bezogen auf Datenaustausch: er muss nie 
Daten zurückliefern.

Joachim B. schrieb:
> clock stretching

ist gefühlsmäßig der falsche Weg: Clock stretching kommt eher zum 
Einsatz, wenn der Slave nicht mit der Datenrate mithalten kann.

Joachim B. schrieb:
> Also statt auf NotBusy zu warten, warte doch einfach bis ein Zugriff
> keinen Error mehr liefert

War auch meine erste idee, hat aber einen Schönheitsfehler: Damit kann 
ich nicht mehr zwischen "Slave busy" und "Slave tot" unterscheiden

A. K. schrieb:
> Wenn beide Seiten bei I2C mit Interrupts arbeiten geht das auch
> wesentlich einfacher: Der Slave schaltet seinen I2C Interrupt ab, wenn
> er nicht mehr bereit ist, und ein, wenn er es wieder ist. Der Master
> bleibt dann ggf. im Clock Stretching hängen. Dank Interrupts
> verschwendet niemand dabei Zeit.

siehe oben, "busy != tot". Clock stretching hilt nix, ist auch 
softwaremäßig schwer umsetzbar (oder versteh ich da was falsch? Wie mach 
ich clock stretching am Slave?)

A. K. schrieb:
> Schon mit STOP + START statt REPEATED START versucht?

Ja, hängt auch.

Für eine detaillierte Analyse ist es mir im moment zu heiß :-). Was 
jedenfalls funktioniert: "single read" d.h. Master will ein byte, Slave 
quittiert ein byte, läuft halt auf eine unnötige Adressierung hinaus. 
Wobei das mit STOP+START als auch mit REP.START funktioniert.

Was auch funktionieren sollte: Sobald der Slave ein "busy=0" liefert, 
fordert der Master noch ein dummy byte mit "expect NAK" an, was der 
Slave auch liefern könnte.

Aber ich glaube ich habe einen Denkfehler; irgendwas in meiner State 
machine im Slave ist krank. ich muss mir hier debug-möglichkeiten 
schaffen...

von (prx) A. K. (prx)


Lesenswert?

Michael R. schrieb:
> softwaremäßig schwer umsetzbar (oder versteh ich da was falsch? Wie mach
> ich clock stretching am Slave?)

Passiert automatisch in der Hardware des Slave. Die hängt SCL 
automatisch so lange auf low, bis die State Machine von der Software 
aktualisiert wird.

Ohne dieses Verfahren sind AVR-Slaves bei einigen MHz Takt nicht sicher 
in der Lage, einen I2C Takt von 100kHz per C-Interrupt zu verarbeiten, 
zumal wenn noch andere Interrupts im Spiel sind. Mit Clock Stretching 
löst sich das Problem in Luft auf, weil völlig selbsttätig abgebremst 
wird, bis die ISR reagiert.

Voraussetzung ist jedoch, dass der Master Clock Stretching korrekt 
berücksichtigt. Der RPi beispielsweise tut es nicht, der Bus Pirate 
ebensowenig. Ein AVR Master hingegen schon.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

So, ich hab mich jetzt "durchdebuggt", und hatte zwar keinen Fehler in 
der Implementierung, aber einen Denkfehler:

Wenn ich ein busy-Flag empfange, hab ich ja vorher schon ein weiteres 
Byte angefordert (per ACK), und diesesjenige welche ist auch schon 
unterwegs. Also kann ich hier natürlich nicht mitten in die bereits 
laufende Übertragung hinein ein STOP senden. Der AVR ignoriert das auch, 
quittiert aber nichtmal mit irgendeinem Statuscode.

Die Lösung ist eigentlich einfach: Sobald ich ein BusyFlag von 0 
empfange, muss ich das nächste "dummy-mäßig" auch noch empfangen, aber 
mit NAK quittieren, abwarten und dann kann ich sauber ein STOP machen.

Allerdings hat mir das hinten und vorne nicht wirklich geholfen, die 
ganze BusyFlag-idee war von anfang an Topfen.

ich machs jetzt ganz normal per NACK-Erkennung beim Adressieren, und das 
tut wunderbar.

Manchmal verrennt man sich halt :-)

von Peter D. (peda)


Lesenswert?

Schau Dir mal an, wie das in EEPROMs (24Cxx) gemacht wird. Wenn die mit 
Schreiben beschäftigt sind, senden die einfach ein NACK auf die Adresse.

von Klaus (Gast)


Lesenswert?

Peter D. schrieb:
> Schau Dir mal an, wie das in EEPROMs (24Cxx) gemacht wird. Wenn die mit
> Schreiben beschäftigt sind, senden die einfach ein NACK auf die Adresse.

Was in Wirklichkeit heißt, sie tun garnichts. Ein NAK braucht man nicht 
senden, der Pullup am Bus macht das NAK.

MfG Klaus

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Peter D. schrieb:
> chau Dir mal an, wie das in EEPROMs (24Cxx) gemacht wird. Wenn die mit
> Schreiben beschäftigt sind, senden die einfach ein NACK auf die Adresse.

Genauso mach ichs jetzt.

Klaus schrieb:
> Was in Wirklichkeit heißt, sie tun garnichts. Ein NAK braucht man nicht
> senden, der Pullup am Bus macht das NAK.

Richtig, und das ist auch das was mich ein bisschen daran stört: man 
kann nicht unterscheiden ob busy oder tot oder gar nicht vorhanden 
oder....

aber - irgendeinen Tod muss man sterben ;-)

von Peter D. (peda)


Lesenswert?

Michael R. schrieb:
> man
> kann nicht unterscheiden ob busy oder tot oder gar nicht vorhanden
> oder....

Doch.
Wenn die max Schreibzeit mit 10ms angegeben ist und er sich dann immer 
noch nicht meldet, ist keiner angeschlossen.

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.