ATMEGA TWI / I2C Slave - Wie implementiert man Clock-Stretching?

Ich programmiere einen TWI-Slave basierend auf einem ATMEGA644PV.

Es funktioniert im Allgemeinen, der Master kann Daten vom Slave senden und lesen. So weit, ist es gut.
Aber bei manchen Leseanfragen benötigt der Slave "mehr Zeit", um die Daten vorzubereiten. Ich möchte Clock-Stretching verwenden, um den Master warten zu lassen, bis die Daten bereit sind.

Das ATMEGA-Datenblatt weist darauf hin:

Der Slave kann die SCL-Low-Periode verlängern, indem er die SCL-Leitung auf Low zieht. Dies ist nützlich, wenn die vom Master eingestellte Taktrate für den Slave zu schnell ist oder der Slave zusätzliche Zeit für die Verarbeitung zwischen den Datenübertragungen benötigt.

Das ist genau das, was ich will, aber ich verstehe nicht, wie ich das auf der Treiberebene implementieren soll. Ich sehe keine Möglichkeit, der I2C-Slave-Hardware anzuzeigen, dass sie nicht sofort ACK, sondern stattdessen die SCL für einen Zeitraum meiner Wahl ziehen soll.

Nach dem, was ich bekomme, kann ich dem Slave nur sagen, dass er ACK oder - nun ja - überhaupt nicht ACK geben soll, nachdem er angesprochen oder ein Datenbyte übertragen wurde.

Übersehe ich hier etwas Offensichtliches? Dies ist das erste Mal, dass ich I2C aus der Sicht eines Sklaven betrachte.

Antworten (2)

Die Atmel Atmega-Prozessoren (einschließlich des Atmega644) führen automatisch eine Taktdehnung durch, wenn die I2C-Schnittstelle eine von der Software ausgeführte Aktion benötigt.

Diese Aktion könnte auftreten, wenn ein Slave ein Datenbyte empfangen hat und die Daten aus dem Datenregister entfernt werden müssen, bevor das nächste Byte empfangen werden kann, oder wenn Daten zum Senden benötigt werden. Dies geschieht immer dann, wenn das TWINT-Flag gesetzt ist.

Das Datenblatt hebt die Tatsache nicht besonders hervor, wird aber an einigen Stellen erwähnt (z. B. in Abschnitt 19.5.5 auf Seite 207 im Datenblatt 02/12).

Ich habe nur das Datenblatt 9/2015, aber ich glaube, ich habe gefunden, was Sie meinen. "Während das TWINT-Flag gesetzt ist, wird die niedrige SCL-Periode verlängert." Das habe ich total vermisst. Und da das Flag immer manuell gelöscht werden muss, ist das sinnvoll. Nachdem ich also die SLA + R-Adressierung erhalten habe, werde ich einen Rückruf von meinem Treiber implementieren, um den Ausgabepuffer zu füllen, BEVOR das Flag gelöscht wird. Danke für den Hinweis, ich wusste, dass es etwas mehr oder weniger Offensichtliches war.

Sehen Sie sich das folgende Schema an, um die am häufigsten verwendete Schnittstelle zwischen I2C-Master- und Slave-Geräten zu sehen. Diese Schnittstelle verwendet kein Clock-Stretching. Der Master erzeugt alle Taktsignale auf SCL mit SW2 (und der Slave empfängt nur diese Taktsignale).
Daten können in beide Richtungen übertragen werden – vom Master zum Slave mit SW1 oder vom Slave zum Master mit SW3. Natürlich müssen sich beide Seiten darüber einigen, wer die SDA-Datenleitung kontrollieren darf, um Kollisionen zu vermeiden. Mit "Steuerung" meine ich, dass der Schalter geschlossen ist und die Datenleitung gegen Masse kurzschließt. Ein offener Schalter ermöglicht es der SDA-Leitung, über den Pull-up-Widerstand auf Versorgungsspannung anzusteigen. Ein geschlossener Schalter hat die "Kontrolle" der SDA-Leitung und zieht sie auf Masse (niedrig). Bei einem inaktiven Bus sind alle Schalter geöffnet.

schematisch

Simulieren Sie diese Schaltung – Schema erstellt mit CircuitLab Im obigen Schema taktet der Master SW2 mit einer Rate von 100.000 Zyklen pro Sekunde (oder 400.000 für Hochgeschwindigkeit) und erwartet, dass der Slave Schritt hält. In einem taktgestreckten System initiiert der Master einen Taktzyklus durch Schließen von SW2 und öffnet SW2 kurze Zeit später (was normalerweise diesen Taktzyklus beenden würde). Aber es überwacht die Taktleitung mit BUF4, um zu sehen, ob R2 tatsächlich in den Leerlauf-High-Zustand zurückgekehrt ist. Wenn der Slave-Schalter SW4 die Taktleitung niedrig hält, ist das eine Taktstrecke, die weitere Datenübertragungen aufhält:

schematisch

Simulieren Sie diese Schaltung Ein Slave-Gerät hat sehr oft keine Möglichkeit, eine Taktdehnung durchzuführen, weil SW4 nicht existiert, oder wenn es existiert, gibt es keine Möglichkeit, es zu schließen. Aber jeder Mikrocontroller hat GPIO-Pins, die die SW4-Funktion ausführen können - auf Masse ziehen. Das Timing von SW4 ist kritisch: Es muss nur niedrig gezogen werden, während SW2 ebenfalls niedrig zieht, um die Slave-Clock-Stretch-Funktion auszuführen. Der Pseudocode zum Steuern des GPIO-Pins (SW4) auf dem Slave lautet also wie folgt:
Initialize GPIO pin to be an input (read). When Slave must clock-stretch, continually monitor GPIO pin, looking for "low". While SCL is low, change GPIO to be output pin, set to logic "0". Keep low until Slave is ready to continue. Once Slave is ready, change GPIO to be input, clearing the clock-stretch.

Die ACK- oder NACK-Datenbitübertragung wird hauptsächlich verwendet, um sicherzustellen, dass Master und Slave am Leben und synchron sind.

Danke für die Rückmeldung. Aber ich verwende das Atmega-Hardware-TWI-Modul. Dies überschreibt die GPIO-Funktionalität der Pins, daher habe ich keine direkte Kontrolle über sie. Die Frage war eher, wie ich das TWI-Modul verwenden/sagen soll, dass ich die Uhr verlängern möchte. Der allgemeine Grundsatz ist mir bekannt.
@Rev1.0 Sie können jeden GPIO- Pin als Pulldown-Clock-Stretcher verwenden - Sie hatten nicht die Absicht (und würden Ihnen nicht raten), den I2C-Clock-Pin als diesen GPIO zu verwenden. Verwenden Sie einen anderen GPIO-Pin.
Ja, es wäre wahrscheinlich möglich, einen separaten GPIO zu verwenden. Ich habe das Problem jedoch bereits gemäß Kevins Antwort gelöst. Die gewünschte Lösung bestand darin, die Funktionen des TWI-Hardwaremoduls zu verwenden, um die Uhr zu verlängern, was jetzt funktioniert. Trotzdem danke.