I2C-Lese- / Schreibfehler bei starker Interruptlast

10

In meinem System verwende ich I2C und stelle fest, dass die I2C-Kommunikation unter starker Interruptlast (von anderen Quellen) leicht unterbrochen wird. Ist dies das erwartete Verhalten für I2C? Ich hätte trotz Interrupt-Last erwartet, es wäre immer noch in Ordnung, da I2C nicht gerade eine zeitkritische Schnittstelle ist, die Uhr wird mit Daten versorgt.

Aktualisieren:

Der Prozessor ist STM32. Die Interrupts sind auf ADC zurückzuführen. Ich kann Interrupts während der Leseereignisse nicht deaktivieren. Daher muss ich eine Lösung finden, mit der ich die i2c-Kommunikation stabiler gestalten kann. Der STM32 ist Master und der Slave ist ein anderes Gerät (Beschleunigungsmesser).

Update2:

Wenn ich einen Logikanalysator mit einem kleinen fliegenden Kabel an die Uhr anschließe, verschwindet das Problem. Interessanterweise gibt es keine Interrupt-Last, Lese-Schreib-Funktion funktioniert gut, wenn Interrupt-Last vorhanden ist, ist dies nicht der Fall. Wenn ich jedoch die Sonde an die Uhr anschließe, funktioniert das Lesen und Schreiben auch unter Interrupt-Last. Ich denke, irgendwo gibt es ein Kapazitätsproblem.

Ktc
quelle
1
Ihre Frage ist sehr allgemein gehalten, da alles vom Design Ihres Systems abhängt. Wie I2C funktioniert, hängt wirklich von den Geräten am Bus ab. Kannst du sie ignorieren und zu später kommen? In einem FPGA können Sie eine Logik entwerfen, die viel für Sie erledigt und dies vermeidet. Auch hier benötigen wir weitere Informationen über den Mikrocontroller und welche anderen Dinge Sie haben. Normalerweise besteht eine gute Lösung darin, ein RTOS zu verwenden und die Aufgaben richtig zu gestalten.
Gustavo Litovsky
Zwei Dinge, auf die Sie achten müssen: Spannungsabfall an den Klimmzügen oder an der Stromversorgung Ihres i2c-Masters und -Slaves oder Emi- oder Kapazitätsprobleme. Meinen Sie mit dem Laden von Interrupts, dass Ihr Master anhält, um einen Interrupt zu behandeln? Einige Chips erlauben keine unendliche Dehnung der Uhr.
Passant
@GustavoLitovsky Sie haben Recht, aber 80% der CPU-Zyklen bedienen ADC-Interrupts und es ist nicht genügend Zeit vorhanden, um einen Lesezyklus während des Nicht-ISR-Fensters durchzuführen. Der Lesevorgang wird also unterbrochen, egal wie gut ich das Betriebssystem entwerfe.
Ktc
@ Passant hast du vielleicht recht. Das Problem verschwand, als ich die Sonde des Logikanalysators an die Taktleitung anschloss.
Ktc
Was ist Ihr aktueller Wert für die Klimmzüge? Haben Sie versucht, sie auf einen anderen Wert zu ändern? (Versuchen Sie 10k oder 4k7 oder 2k nur für eine erste Vermutung)
Tom L.

Antworten:

9

Dies ist ein Softwareproblem, Sie verbringen zu viel Zeit mit der Wartung von Interrupts und Ihre I2C-Routine ist nicht in der Lage, damit umzugehen (das sind also zwei Dinge, die nicht richtig sind). Ich habe mehrere ähnliche Situationen durchgemacht.

Erstens: Sie müssen in den Interrupts so wenig wie möglich tun, nur die Daten lesen und speichern, keine Verarbeitung durchführen, die Sie außerhalb des ISR durchführen könnten, Mathematik kann eine Menge CPU-Zyklen dauern und die CPU kann nichts anderes tun während in dieser Unterbrechung.

Zweitens: Untersuchen Sie DMA, um Dinge zu automatisieren, sodass Ihre Interrupts fast zu einem automatisierten Hintergrundprozess werden.

Drittens: Wenn I2C wichtig ist, setzen Sie DAS auch in einen Interrupt, aber stellen Sie sicher, dass Sie die Prioritäten herausarbeiten!

Viertens: Finden Sie heraus, warum Ihre I2C-Routine fehlschlägt. I2C selbst kann sehr zeitweiligen Timings, Pausen und Wartezeiten usw. standhalten, sodass Ihre Routine möglicherweise geändert werden muss, um dies zu ermöglichen.

Fünftens: Wenn Sie Interrupts "verketten" können, können Sie möglicherweise feststellen, dass Sie die ADC-Lesevorgänge effizienter warten oder den ADC in einen anderen Modus versetzen können, in dem er vor der Unterbrechung mehr Arbeit für Sie erledigt (z. B. warten, bis alle Messwerte verfügbar sind). Lesen Sie dann alles mit einem Schlag und nicht 8 separate Interrupts für 8 separate ADC-Kanal-Lesevorgänge.

Sechstens: Verwenden Sie ein Oszilloskop oder einen Logikanalysator und sparen Sie E / A-Pins auf der Platine, um zu verfolgen, wie viel Zeit Sie in jedem Codebit verbringen, um festzustellen, ob Sie es beschleunigen können. (Setzen Sie den Pin hoch, wenn Sie eine Funktion / ISR eingeben, und setzen Sie ihn beim Beenden wieder niedrig.)

Siebtens: Entscheiden Sie, ob es wirklich schlimmer wird, wenn Sie den ADC wirklich so oft lesen müssen. Es ist nicht intuitiv, aber manchmal führt ein langsameres Laufen tatsächlich zu besseren Ergebnissen, indem das Signal für Sie gemittelt und Spitzen / Transienten reduziert werden, die Probleme verursachen oder zusätzliche Verarbeitung zum Entfernen erfordern können. Wir haben eine PID-Routine für die Motorsteuerung verbessert, indem wir sie einfach um 1/4 der Geschwindigkeit ausgeführt haben, wodurch eine Menge CPU-Zeit eingespart wurde.

John U.
quelle
Danke für Vorschläge. Das Problem deutet irgendwie auf Hardware hin.
Ktc
4

Ein Bussklave, der mit anderen Dingen beschäftigt ist, kann sich strecken, um Zeit zu gewinnen, bis er das Ende der Kommunikation fortsetzen kann. Dies geschieht, indem der ACK / NACK-Takt nicht sofort gesendet wird und die Kommunikation in einem Zwischenzustand gehalten wird, bis sie zur Beantwortung bereit ist.

Das Dehnen der Uhr ist der geeignete Weg, um mit dieser Art von Situation umzugehen. Ein Gerät, das sich nicht dehnt und andere schlechte Dinge tut (Bus hängen / neu starten, eine gültige Adresse oder einen gültigen Befehl NACKs usw.), kann problematisch sein und den Master zusätzlich belasten, um die Dinge in Ordnung zu halten (es muss Befehle wiederholen , NACKs usw. im Auge behalten)

Adam Lawrence
quelle
Sie haben Recht, aber das Problem ist der Gastgeber. Der Host ist mit anderen Dingen beschäftigt, nicht mit Sklaven. Also nicht so sicher, ob ich eine Uhr strecken kann.
Ktc
Verwenden Sie integrierte I2C-Hardware oder schlagen Sie das Protokoll aus GPIO-Leitungen heraus? Im Standard ist kein spezifisches I2C-Timeout-Intervall definiert, daher sollten Slaves unbegrenzt warten, bis der Master ein Paket beendet hat.
Adam Lawrence
Ich verwende die STM32 IC2-APIs. Bitte beachten Sie das Update, es sieht aus wie ein Kapazitätsproblem.
Ktc
1

Abhängig von den Funktionen des STM32 (ich habe noch nie einen verwendet) können Sie einen der folgenden Ansätze ausprobieren. Wenn Sie detaillierter angeben können, was Sie tun möchten, und ein überzeugendes Argument dafür haben, warum jeder Interrupt in der Form erforderlich ist, in der Sie ihn jetzt haben, kann eine spezifischere Antwort in Betracht gezogen werden. Speziell in Ihrem Fall ist I2C jedoch langsam genug, damit dies bei gut geschriebenen Interrupt-Routinen kein Problem darstellt.

  • Interrupts für alles können normalerweise deaktiviert werden. In jedem normalen Controller befinden sich höchstens ein oder zwei nicht maskierbare Interrupts, von denen einer zurückgesetzt wird. Wenn Sie keine Interrupt-gesteuerte Steuerung für etwas benötigen (in Ihrem Fall ADC oder I2C), verwandeln Sie diesen Peripheriecode in einen Code, der keine Interrupts verwendet, und deaktivieren Sie dann die Interrupts.

  • Interrupt-Handler sollten nicht lang sein. Versuchen Sie, so wenig wie möglich vom Interrupt-Vektor selbst zu tun. Der extrem minimalistische Ansatz für Interrupts besteht darin, einfach ein Flag aus der Interrupt-Handler-Routine heraus zu setzen und beispielsweise die Hauptschleife von da an das ganze schwere Heben ausführen zu lassen. Was Ihre spezifische Anwendungs- und Firmware-Architektur erfordert, ist möglicherweise nicht so einfach wie das, aber es lohnt sich wirklich, sich die Mühe zu machen, um zu sehen, wie viel wirklich innerhalb der Interrupts getan werden muss.

  • Wenn Sie periphere DMA haben, verwenden Sie diese, anstatt bei jedem Byte zu unterbrechen. Normalerweise ist es einfacher, den ADC auf DMA zu stellen als auf I2C, aber verschiedene Chips haben unterschiedliche Implementierungen. Es würde mich nicht wundern, wenn es eine saubere Möglichkeit gäbe, einen I2C-Austausch auch an die DMA abzuspalten. Mit DMA können Sie die Anzahl der Interrupts reduzieren und Ihren Prozessorkern von jedem einzelnen Datenblock befreien.

  • Versuchen Sie, die spezifischen Fälle zu identifizieren, in denen Daten beschädigt werden, und den Mechanismus, durch den die Daten beschädigt werden. Dies ist viel schwieriger, aber mit dem kreativen Einsatz eines modernen Oszilloskops / Logikanalysators können Sie möglicherweise einige der Probleme erkennen. Stellen Sie insbesondere sicher, dass das Problem mit dem Timing und nicht mit dem Speicher zu tun hat (was bei einer Kombination aus schrecklichem Code und einem liberalen Compiler möglich ist).

BEARBEITEN: Einige spezifische Hinweise zu diesem Problemfall aus Ihren Kommentaren zur Frage:

  • Es lohnt sich normalerweise nicht, 80% der CPU zum Lesen des ADC zu verwenden. Das Sammeln von Daten ist nutzlos, wenn Sie nicht darauf reagieren oder die Daten sogar speichern können.
  • Selbst wenn Sie auf irgendeine Weise (sinnvollerweise) eine große Datenmenge erfassen, sollten ADC-Interrupts nicht so lang sein, dass das I2C-Peripheriegerät eine Zeit lang vollständig unterdrückt wird, damit Daten verloren gehen. I2C läuft mit höchstens 100 / 400KHz. Sie würden eine wirklich, wirklich lange Unterbrechung benötigen, um lange genug zu unterbrechen, damit es auf I2C wie etwas Ernsthafteres als Taktjitter aussieht.
Chintalagiri Shashank
quelle
Vielen Dank. Unser System erfordert diese Art von komplexem und langem ISR, es ist eine lange Geschichte. Sie haben Recht, I2C muss auch unter dieser Interrupt-Last bestehen und kann es nicht. Ich vermute, dass das Problem in der Hardware liegt, siehe Update.
Ktc
Nach meiner Erfahrung sind die meisten Anwendungsfälle, die eine wahnsinnig lange ISR erfordern, tatsächlich diejenigen, die ein RTOS verdienen. Und ja, nach Ihrer letzten Bearbeitung scheint es sich um ein Hardwareproblem zu handeln. Versuchen Sie, einen kleinen Kondensator in die Leitung einzubauen, in der sich Ihr Logikanalysator befand, und es wird Ihnen wahrscheinlich gut gehen. Warum dies notwendig ist, ist jedoch etwas schwieriger zu beantworten. Ich würde die I2C-Pullup-Widerstände überprüfen (möglicherweise zu niedrig für Ihre Buskapazität) und die Datenblätter aller von Ihnen verwendeten I2C-Puffer / Repeater überprüfen.
Chintalagiri Shashank
0

In einem gegebenen System könnte Rauschen in die Takt- und Datenbusse eintreten. Die Tatsache, dass Ihr Logik-Anlayser das Problem beseitigt, zeigt dies. Befolgen Sie für eine praktische und schnellste Implementierung einfach den Hinweis Ihrer Beobachtung. Auf einem i2c-Bus mit 400 kbit / s Implementierung, basierend auf einer ähnlichen Beobachtung, habe ich 2M parallel zu 12pf von Takt- und Datenpunkten mit Masse verbunden und festgestellt, dass das Problem gelöst ist. Dies entfernt / filtert Rauschen außerhalb des für die spezifische i2c-Kommunikation erforderlichen interessierenden Bandes. Bitte versuchen Sie und beraten Sie.

user41360
quelle