Ich habe eine Frage zum USI-I2C Beispiel aus der Codesammlung von A.K. ( Beitrag "Re: attiny USI Slave Implementierung" ) Da ich nicht will dass die Codesammlung unübersichtlich wird, stelle ich meine Frage hier. Bei meinem ATtiny44 funktioniert das Beispielprogramm bis jetzt zuverlässig. Aktuell sende ich versuchsweise 20Byte an einen einen Master und lese 2Byte ein. Wenn ich dass im Beispiel richtig sehe, wird beim Zugriff auf den Sende- und Empfangsbuffer der globale Interupt abgeschalten. Da das Kopieren der Daten und Berechnen der Prüfsumme etwas länger braucht, will ich dass diverse Interupts (externe Interupts, Timerüberläufe,...) den Koopiervorgang kurz unterbrechen können. (Sichern der Daten und anfügen eines Zeitstempels.) Dafür müsste ich die globalen Interupts aktiviert lassen. Dies würde aber zu race conditionen führen. Weis jemand wie ich das bewerkstelligen kann? Ich habe es schon versucht, anstatt mit usi und cli die Interupts global zu behandeln, nur die USI Interrups über das Register USICR die Bits USISIE und USIOIE ab und anzuschalten. Doch dass führt zu fem Probem, dass das Senden / Empfangen gelegentlich fehlschlägt.
BF schrieb: > Wenn ich dass im Beispiel richtig sehe, wird beim Zugriff auf den Sende- > und Empfangsbuffer der globale Interupt abgeschalten. Nur für die Antwort an den Master. Bei der Message vom Master hingegen nicht. Die CRC lässt sich doch wohl auch vorher berechnen, so dass für die Interrupt-Abschaltung nur die Zeit des Kopierens in den Puffer verbleibt.
A. K. schrieb: > Die CRC lässt sich doch wohl auch vorher berechnen, so dass für die > Interrupt-Abschaltung nur die Zeit des Kopierens in den Puffer > verbleibt. Ich hatte den Ablauf aktuell so geplant, dass die Daten laufend in ein Datenarray geschrieben werden und dann zum Senden in den Sendebuffer kopiert werden. Wenn ich da den Kontrollwert nicht beim Kopieren in den Sendebuffer, sondern vorher errechne, müsste ich die Daten in einen Zwischenbuffer schreiben um sicher zu gehen, dass nicht doch ein Wert verändert wird. Dass würde die Resourcen doch ziemlich strapazieren. Außerdem gibt es noch dass Problem, dass der Kopiervorgang ca.2/3 der Zeit in Anspruch nimmt und die Berechnung des Kontrollewertes nur 1/3. Dadrurch würde ich durch die Auslagerung der Kontrollwertberechnung nichts gewinnen. Gibt es also keine Möglichkeit für den Kopiervorgang nur den den USI abzuschalten?
Was dann passiert weiss ich nicht, ich habe das nicht getestet.
PS: Ich hatte diesen Code für Kommunikation in Form von Messages vorgesehen. Wenn es sich eher um einen Datenstrom handelt, dann kommt vielleicht auch der Atmel'sche Code in Frage.
A. K. schrieb: > Was dann passiert weiss ich nicht, ich habe das nicht getestet. Wenn man nur die Interrupt-Flags des USI ab- und anschaltet treten bei mir bei ca. 5% der Sende- / Empfangsversuche des Masters ein Fehler auf. Wie's aussieht reagiert der Slave nicht rechzeitig. Jedenfalls kann in diesen 5% keine Verbindung hergestellt werden. Ich muss leider die Daten paketorientiert versenden, da der Master nicht von mir ist und dieser nur alle 10 bis 50ms eine Momentaufnahme der aktuellen Daten verlangt. Nur wollte ich bis zum letzten Moment ein aktualisierung der Daten zulassen. Also nur für den Kopiervorgang des einen Wertes den betreffenden Interupt abschalten und dann wieder aktivieren. Denn wenn ich die globalen Interrupts während des gesammten Kopiervorgangs abschalte, kommt es zu einer Verfälschung der Messdaten zwischen 7 und 10%. Wenn ich die USI-Interrupts abschalte, bekomme ich zwar immer wieder dass Problem mit der Verbindung, dafür beträgt die Verfälschung der Messdaten nur 2 bis 3%. Desswegen bin ich auf der Suche nach einer Möglichkeit die Datenpakete zu versenden, ohne die Interupts zu sehr zu beeinträchtigen.
Probier mal aus, was ohne Abschaltung des Interrupts passiert. Müsste eigentlich auch ohne gehen. Erhöht die Wahrscheinlichkeit, dass der Master als Antwort nur einen Abort kriegt. Retry seitens des Masters ist ohnehin sinnvoll.
A. K. schrieb: > Probier mal aus, was ohne Abschaltung des Interrupts passiert. Müsste > eigentlich auch ohne gehen. So wie es aussieht, funktioniert es ganz ohne cli/sei bzw. Abschalten der Interrupt's. Ich habe jetzt. ein paar Tausend Datenpakete übermittelt, und es ist kein Übertragungsfehler aufgetreten. Mal schaun, wie sich dass Ganze unter Realbedingungen verhält. Die Frage ist jetzt, warum das Abschalten der Interupt's über die Flags nicht funktioniert hat, obwohl das ja genau die gleiche Funktion erfüllt wie die Verwendung von cli und sei.
BF schrieb: > Die Frage ist jetzt, warum das Abschalten der Interupt's über die Flags > nicht funktioniert hat, obwohl das ja genau die gleiche Funktion erfüllt > wie die Verwendung von cli und sei. Nein, da ist ein gewaltiger Unterschied! Zwischen cli und sei ist zwar die Ausführung der ISRs abgeschaltet, nicht jedoch das Erkennen der entspechenden Ereignisse. Tritt ein entsprechendes Ereignis zwischen cli und sei ein, wird die zugehörige ISR trotzdem ausgeführt, nur halt verzögert nach dem sei. Manipulierst Du hingegen direkt die Flags, schaltest Du auch die Erkennung der Ereignisse mit ab, d.h. die Ereignisse in dieser Zeit gehen komplett verloren. CU
... schrieb: > Manipulierst Du hingegen direkt die Flags, schaltest Du auch die > Erkennung der Ereignisse mit ab, d.h. die Ereignisse in dieser Zeit > gehen komplett verloren. Die IE-Bits haben keinen Einfluss auf die IF-Bits.
Auweia, Asche auf mein Haupt. Da hat A. K. natürlich vollkommen Recht. Bleibt als Erklärung für das unterschiedliche Verhalten noch ein anderer Interrupt, der bei cli/sei mit abgeschaltet wird und über die Flags halt nicht.
Mir sind nur die Interrupts USISIE und USIOIE im Register USICR beim USI-TWI bekannt. Jedenfalls finde ich im Datenblatt und im Beispielquellcode nur die Beiden. ... schrieb: > Bleibt als Erklärung für das unterschiedliche Verhalten noch ein anderer > Interrupt, der bei cli/sei mit abgeschaltet wird und über die Flags halt > nicht. Genau darum geht's ja. Aber diese Interupt's haben eigentlich nichts mit dem USI / I2C zu tun.
BF schrieb: > Aber diese Interupt's haben eigentlich nichts mit dem USI / I2C zu tun. Müssen sie auch nicht. Einmal sind sie mit abgeschaltet (cli/sei) und das andere mal nicht (USISIE/USIOIE). Das kann das Timing schon gut durcheinander bringen, bei der Flag-Variante sind die USI-ISRs unter Umständen wesentlich länger abgeschaltet. Wenn die Gegenseite dann zwei Bytes zu schnell nacheinander sendet oder nicht lange genug auf Antwort wartet, dann hast Du schon verloren.
... schrieb: > Umständen wesentlich länger abgeschaltet. Wenn die Gegenseite dann zwei > Bytes zu schnell nacheinander sendet oder nicht lange genug auf Antwort > wartet, dann hast Du schon verloren. Während des laufenden Transfers sollte das kein Thema sein, da das USI auf Clock Stretching konfiguriert ist, d.h. SCL vom Slave hardwareseitig solange verlängert wird, bis die Software darauf reagierte. Und in der Start Condition ist das sowieso schon Bestandteil der Arbeitsweise des USI. Vorausgesetzt allerdings, dass der Master dieses Clock Stretching auch berücksichtigt und nicht davon ausgeht, SCL sei unidirektional und ausschliesslich unter seiner Kontrolle. Ebenso sollte der Master nicht schon nach wenigen Takten die Start Condition wieder abbrechen, wenn nicht sofort darauf reagiert wurde. Wenn der Master einen Start abbricht und sofort neu initiiert, dann kann es bei verzögerter Reaktion im Slave vorkommen, dass der zweite Start nicht bemerkt wird.
Wichtiges zum Ablauf: Es gibt Phasen, in denen der Slave den Master gleich vorneweg abwirft, d.h. die Adressierung nicht positiv beantwortet. Nämlich dann, wenn der vorherige Request noch in Arbeit ist. In dieser Hinsicht unterscheidet sich das Verhalten deutlich von den üblichen I2C-Hardwarebausteinen. Solche Abbrüche sollten nicht als Fehler interpretiert werden, sondern sind normaler Teil der Arbeitsweise dieses Codes.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.