Wann geben Sie die Kontrolle über SDA um eine i2c-Ack herum frei und erlangen sie wieder?

Ich habe ein seltsames Verhalten mit der Wire-Bibliothek von Energia, also dachte ich, ich würde versuchen, i2c selbst zu machen.

Ich schreibe meine eigene (bit-bang) Implementierung von i2c und halte es ziemlich einfach. Im Moment möchte ich nur ein bestimmtes i2c-Gerät erkennen. Hier ist mein grundlegender Algorithmus.

  1. Beginnen Sie die Nachricht, indem Sie SDA von High auf Low treiben, während SCL hoch bleibt.
  2. Senden Sie die 7-Bit-Adresse Bit für Bit, indem Sie SDA auf High oder Low treiben, während SCL Low ist, und dann SCL auf High ändern, damit das Slave-Gerät jedes Bit liest.
  3. 1 Bit schreiben oder lesen senden.
  4. Erhalte Ack vom Slave.
  5. Beenden Sie die Nachricht, indem Sie SDA von Low auf High treiben, während SCL High bleibt.

Ich weiß, dass das obige vielleicht etwas zu stark vereinfacht ist, aber ich wollte die Dinge nur in einen Zusammenhang bringen. Ich habe Probleme mit Schritt 4 und kenne den genauen Zeitpunkt, wann ich die Kontrolle über die SDA-Leitung während einer Bestätigung freigeben und wiedererlangen muss.

Nachdem also das letzte Lese-/Schreibbit auf SDA gesetzt und SCL auf HIGH gesetzt wurde, muss ich wissen, wie die Reihenfolge der Operationen ist, um eine Bestätigung vom Slave zu erhalten.

Ich habe jede erdenkliche Kombination ausprobiert, aber es scheint nicht richtig zu funktionieren. Es scheint, dass ich Folgendes tun sollte:

setMode(SDA, INPUT);                //Release the SDA line to the slave device
digitalWrite(SCL,LOW);              //Pulse the SCL line
digitalWrite(SCL,HIGH);
int ack = digitalRead(SDA) == LOW;  //Read from the SDA line
setMode(SDA, OUTPUT);               //Seize control of the SDA line

Die obige Sequenz scheint nicht zu funktionieren. Mein Digital Analyzer erkennt meine Kommunikation nicht so, wie es sollte.

Alle Korrekturen in meinen Annahmen oder Anpassungen am obigen Code wären sehr hilfreich.

Zur weiteren Klarstellung:

Ich verwende eine Entwicklungsumgebung namens 'Energia'. Es ist eine Abzweigung von Arduino und wird verwendet, um den Prozess der Programmierung von TI MSP430x-Prozessoren zu „vereinfachen“. Wie auch immer, es scheint kein Konzept des 'OpenCollector'-Modus zu haben.

Es ist entweder Input, Output oder Input_Pullup. Ich frage mich, ob Input_Pullup nicht ihre Version des OpenCollector-Modus ist. Ich werde das versuchen. Hier gibt es eine interessante Diskussion über Input, Output, Input_Pullup:

Energiekonstanten

Sie "geben die Kontrolle über SDA nicht frei". Beide Pins müssen Open-Collector sein, was bedeutet, dass Ihr Gerät nur niedrig fährt. Anstatt hoch zu fahren, geht es einfach hoch-Z, wodurch die Pull-up-Widerstände die Leitung hochziehen können, es sei denn, ein anderes Gerät treibt niedrig (Slave sendet ACK). Es hört sich so an, als müssten Sie sich über I2C informieren.
Wenn Sie zufällig keinen Open-Collector verwenden können, besteht die Alternative darin, den Pin-Ausgangsstatus auf Low zu setzen und dann die Pin-Modi zwischen Ausgang für 0 und Eingang für 1 umzuschalten.
Was meinst du mit "scheint nicht zu funktionieren"? Sie müssen eine Oszilloskop-Spur anzeigen.
Also denke ich, digitalWrite (SDA, LOW); sagt meiner App, dass ich möchte, dass der Pin niedrig ist, wenn ich ihn steuere. pinMode (SDA, OUTPUT) übernehme ich die Kontrolle über den Pin (erzwingt ihn auf Low), und pinMode (SDA, INPUT) gibt mir die Kontrolle über den Pin (so dass ich über die Pull-up-Widerstände auf HIGH gehen kann)? Ich werde es versuchen. Danke DoxyLover !!! Geben Sie Ihren Vorschlag als Antwort ein und wenn er funktioniert, markiere ich ihn als DIE richtige Antwort!!

Antworten (2)

Die meisten Ihrer Probleme werden wahrscheinlich darauf zurückzuführen sein, dass Sie diese Linien hoch setzen, anstatt sie schweben zu lassen. SDA und SCL gehen hoch, weil ein Widerstand sie auf +V zieht, nicht weil sie hoch getrieben werden. Vielen ist nicht klar, dass die Uhrenlinie auch so betrieben werden soll.

Es gibt noch etwas anderes an der Art und Weise, wie Sie Ihre Logik beschreiben, was mich denken lässt, dass Sie, während Sie sehen, dass SCL als Ereignis, das die Daten zwischenspeichert, auf niedrig übergeht, Sie zu glauben scheinen, dass Sie SCL danach auf hoch zurücksetzen. Ich ermutige Sie, sich das Uhrenereignis eher so vorzustellen:

  • die Daten einrichten
  • erhöhe die Uhr
  • Warten Sie eine angemessene Zeit
  • senken Sie die Uhr

So wie Sie es tun, können Sie auf folgende Weise in Schwierigkeiten geraten:

  • Sie schreiben SDA - sagen wir, es ist niedrig.
  • Sie erhöhen die Uhr, also ist SCL jetzt hoch
  • Sie geben SDA frei, weil Sie es lesen möchten.
  • SDA geht hoch, wenn kein ACK vorhanden ist

Überraschung! Sie haben gerade eine STOP-Bedingung erstellt, ohne es zu merken.

Ja, genau das passiert laut meinem digitalen Analysator ... Ich komme zum ACK-Bit und dann sehe ich, wie ein Stopp und ein Start passieren.
Wenn keiner der Slaves auf einem I2C-Bus Clock-Stretching verwendet, gibt es keinen wirklichen Nachteil, wenn der Master die Clock aktiv in beide Richtungen treibt. Wenn Slaves Clock-Stretching verwenden, muss der Master natürlich nicht nur einen passiven Pullup verwenden, wenn er die Clock freigibt, sondern auch warten, bis die Clock bei jedem Loslassen tatsächlich hoch geht, und die Tatsache berücksichtigen, dass Slave-Geräte dies nicht tun Es ist nicht erforderlich, gültige Daten auf SDA zu speichern, bis SCL veröffentlicht wird.
Diejenigen, die SCL fahren, neigen dazu, zu "lernen", dass sie es immer tun können, insbesondere wenn sie nur EEPROMs, Temperatursensoren und alles ohne einen Mikrocontroller im Inneren verwenden. Dann, eines Tages, finden sie es anders heraus! Also erinnere ich die Leute gerne daran, was die ursprüngliche Absicht war.

Immer wenn ein Bit übertragen wird, treibt der Schreiber SDA (oder auch nicht), unmittelbar nachdem SCL auf Low geht, und der Leser liest den Zustand von SDA, wenn SCL auf High geht. (Das Hochgehen von SCL kann durch den Slave mit Clock-Stretching verzögert werden; Sie müssen warten, bis SCL tatsächlich hoch geht.)

Ihr Code muss SCL lange genug pulsieren, damit der Slave genügend Zeit hat, den Wert zu setzen (mindestens 4,7 µs).

Das Umschalten von SDA in den Ausgabemodus könnte es nach unten ziehen, wenn dies der letzte vorherige Wert war. Dies ist nicht erlaubt, wenn SCL hoch ist (es sei denn, Sie möchten tatsächlich einen wiederholten Start durchführen).

Sehr gut. Danke für diesen Rat/Info.