Hi,
ich befasse mich gerade mit I2C und versuche mich an einer eigenen
Implementierung einer Bibliothek für Atmel AVRs. Nun kann es ja dazu
kommen, dass der Bus "verstopft" ist, wenn z.B. der Master inmitten
eines Transfers neugestartet wird und so vergisst, dass er eigentlich
noch SCL clocken müsste.
Dies wird z.B. hier
(http://www.analog.com/static/imported-files/application_notes/54305147357414AN686_0.pdf)
beschrieben. Dort wird auch gleichzeitig eine Lösung vorgestellt, die da
lautet:
> The procedure is as follows:> 1) Master tries to assert a Logic 1 on the SDA line> 2) Master still sees a Logic 0 and then generates a clock> pulse on SCL (1-0-1 transition)> 3) Master examines SDA. If SDA = 0, go to Step 2; if> SDA = 1, go to Step 4> 4) Generate a STOP condition
Soweit auch alles klar. Allerdings verstehe ich den nächsten Satz nicht:
> Note that this process may need to be repeated because> the cleared SDA line may have been cleared for the next> bit, which was a 1.
Kann mir das jemand erklären? Anscheinend fehlt es mir hier an
Vorstellungsvermögen, aber was genau ist hier das nächste "bit"?
Vielleicht könnt ihr mir auf die Sprünge helfen. Wie handhabt ihr das
Ganze?
Vielen Dank!
Ich verstehe den Text so, dass beim Senden der STOP-condition der Slave
noch ein Datenbit 0 ausgibt, wodurch die STOP-condition nicht am Bus
durchkommt.
Ich mache das immer so, dass ich einfach nach beim Initialisieren des
I2C 9 mal eine 1 sende (z.B: I2C Receive) und danch ein STOP ausgebe.
Damit bekommt der Slave sicher ein NAK geschickt und sollte danach
eigentlich schweigen. Die STOP-condition setzt dann den Bus zurück.
Das wird in folgendem Beitrag ausführlicher diskutiert:
http://www.microchip.com/forums/m175368-print.aspx
Gruss
Mike
Irgendwie scheint es da mehrere Ansätze zu geben. Interessanterweise
heißt es in der offiziellen Spezifikation in Punkt 3.1.16:
> If the data line (SDA) is stuck LOW, the master should send nine clock> pulses. The device that held the bus LOW should release it sometime within> those nine clocks. If not, then use the HW reset or cycle power to clear> the bus.
Das erscheint mir am Einfachsten in der Implementierung. Gibt es
Probleme, die damit nicht gelöst werden?
I2C schrieb:> Irgendwie scheint es da mehrere Ansätze zu geben.
Die oben genannte Prozedur ist doch eigentlich das Gleiche. Sie versucht
nur ein paar Pulse zu sparen, sollten weniger als 9 nötig sein. Ob das
der Bringer ist?
MfG Klaus
Klaus schrieb:> Die oben genannte Prozedur ist doch eigentlich das Gleiche. Sie versucht> nur ein paar Pulse zu sparen, sollten weniger als 9 nötig sein. Ob das> der Bringer ist?
Naja, nicht unbedingt, da sie auf das Senden der STOP Condition
verzichtet. Je nach Implementierung der State Machine kann das ja
durchaus etwas ausmachen.
Ich verstehe nur nicht wie ich eine STOP Condition generieren kann, wenn
SDA schon high ist. Eine STOP Condition ist ja definiert als Low-High
Übergang von SDA während SCL high bleibt. Wenn aber SDA schon high ist,
sehe ich nicht wie ich einen Low-High Übergang hinbekommen soll, ohne
vorhergehenden High-Low Übergang, was ja einer START Condition
entspräche.
Übersehe ich hier etwas?
> Ich verstehe nur nicht wie ich eine STOP Condition generieren kann, wenn> SDA schon high ist. Eine STOP Condition ist ja definiert als Low-High> Übergang von SDA während SCL high bleibt. Wenn aber SDA schon high ist,> sehe ich nicht wie ich einen Low-High Übergang hinbekommen soll, ohne> vorhergehenden High-Low Übergang, was ja einer START Condition> entspräche.>> Übersehe ich hier etwas?
Ja, der Master muss den Bus natürlich aktiv ansteuern.
In folgender Reihenfolge:
1. 0->SCL, 1->SDA
2. 0->SCL, 0->SDA
3. 1->SCL, 0->SDA
4. 1->SCL, 1->SDA
Der Schritt von 3 nach 4 ist die STOP-condition.
START-condition wäre SDA von 1 auf 0 bei gleichzeitig SCL High. Ein
Pegelwechsel auf SDA bei SCL Low löst kein START aus.
Mike schrieb:> 1. 0->SCL, 1->SDA> 2. 0->SCL, 0->SDA> 3. 1->SCL, 0->SDA> 4. 1->SCL, 1->SDA
Könntest du das eben nochmal etwas ausführen? Worauf genau war das
bezogen?
I2C schrieb:> Mike schrieb:>> 1. 0->SCL, 1->SDA>> 2. 0->SCL, 0->SDA>> 3. 1->SCL, 0->SDA>> 4. 1->SCL, 1->SDA>> Könntest du das eben nochmal etwas ausführen? Worauf genau war das> bezogen?
Auf Deine Frage: wie erzeuge ich eine STOP-Condition, wenn SCL und SDA
high sind, ohne vorher eine START-Condition zu erzeugen.
Ganz einfach: im ersten Schritt (1.) SCL von High nach Low bringen.
Ist der Bus IDLE, so hat dies keine Bedeutung (ist insbesondere keine
START-Condition). Ist der Bus belegt, so ist das einfach das Ende eines
Bits.
Solange nun SCL auf Low ist, darf ich mit SDA machen, was ich will - in
diesem Fall also SDA auf Low (2.) bringen.
Und kann jetzt die STOP-Condition problemlos erzeugen: SCL auf High
gehen lassen (3.), danach SDA von Low auf High umschalten (4.)