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?
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.