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.
Antworten:
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.
quelle
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)
quelle
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:
quelle
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.
quelle