PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : I2C-Befehle unterbrechen



Che Guevara
23.09.2012, 16:34
Hi,

bevor ich jetzt mit dem basteln und programmieren anfange, wollte ich mal fragen, was passiert wenn mehrere I2C-Befehle (Start, Send, Receive, Stop) durch andere I2C-Befehle unterbrochen werden?
Hintergrund:
Auf einem ATXMega32A4 wird mit 800Hz eine Routine aufgerufen, die einen Sensor über I2C abfrägt. Jetzt möchte ich in der Mainloop einen anderen I2C-Slave abfragen, weiß aber nicht so genau, was passiert wenn z.b. in der Mainloop schon die Adresse des einen Slave gesendet wurde und dann der Interrupt reinkommt und den anderen Slave anspricht? Den Interrupt disablen ist leider nicht möglich, da es eine Software für meinen Quadrocopter ist und dieser Interrupt die Regelschleife darstellt. Beide Slaves hängen an der selben Schnittstelle (TWIC).

Wäre nett, wenn jemand da mal was schreiben könnte :)

Gruß
Chris

Kampi
23.09.2012, 16:46
Hey,

ich denke mal, dass es dann zu einem komischen Verhalten der Busteilnehmer führen kann.
Der Fall der am wenigsten schlimm wäre wäre der, wenn der Slave dann einfach nur ein Error ausgibt, weil er den Befehl nicht versteht.
Wenn der Fall eintritt das schon ein Slave adressiert wurde, kannst du keinen anderen Slave adressieren, da der Slave ein Ack auf den Bus gibt wenn er adressiert wurde.
Der Fall würde dann etwa so ablaufen:
Slave 1 wird adressiert und bestätigt diese. Er wartet nun auf Befehle
Du willst Slave 2 adressieren und der Slave 1 würde diese Adresse u.U. als Befehl werten
Slave 1 reagiert auf den Befehl und Slave 2 wird nicht adressiert

TheDarkRose
23.09.2012, 16:58
Interrupt setzt ein Flag -> I2C Kommunikation wird erst im Mainloop durchgeführt.

Che Guevara
23.09.2012, 18:43
Hi,

@Kampi,
genau so dachte ich mir das auch, aber ich war nicht sicher, obs da nicht irgendeine Art Sicherung gibt...

@TheDarkRose,
du meinst, ich solle in der ISR nur ein Flag setzen und das ganze Programm dann in den Mainloop stecken und auf das Flag warten? So hatte ich es vorher, bis ich gemerkt hatte, dass ich da das Timing nicht so sauber hinbekomme... Deswegen ist es jetzt so und ich werde es auch so belassen.

Gruß
Chris

Kampi
23.09.2012, 18:51
@Kampi,
genau so dachte ich mir das auch, aber ich war nicht sicher, obs da nicht irgendeine Art Sicherung gibt...


Hey,

hardwaremässig gibt es keine Sicherung (zumindest weiß ich nichts davon).
Du musst sowas durch deine Software umgehen.

Che Guevara
23.09.2012, 18:55
Hm ok, dann werd ich mir mal was überlegen... Danke für eure Antworten!

Gruß
Chris

Klebwax
23.09.2012, 19:10
Hi,

@Kampi,
genau so dachte ich mir das auch, aber ich war nicht sicher, obs da nicht irgendeine Art Sicherung gibt...
Wenn du I2C in Hardware nutzt, gibt es schon gewisse Sicherungen, ein Byte, daß gerade auf den Bus geschoben wird, kann man nachträglich nicht mehr ändern. Das rettet aber nicht den ganzen Frame.



@TheDarkRose,
du meinst, ich solle in der ISR nur ein Flag setzen und das ganze Programm dann in den Mainloop stecken und auf das Flag warten? So hatte ich es vorher, bis ich gemerkt hatte, dass ich da das Timing nicht so sauber hinbekomme... Deswegen ist es jetzt so und ich werde es auch so belassen.

Das mit dem Flag kann auch nicht gehen. Die Mainloop müßte schneller als die Interrupte sein, sonst verliert man Interrupte.

Die einzige Möglichkeit ist umgekehrt. Man muß sich das Timing ganz genau ansehen und die I2C Übertragungen so auf die Interrupte verteilen, daß sie nicht ineinander laufen. Das erfordert sorgfältige Planung.

MfG Klebwax

for_ro
23.09.2012, 19:35
Hallo Chris,
reicht denn 1/800 s nicht, um den zweiten Sensor abzufragen? Ist doch eigentlich jede Menge Zeit. Allerdings musst du davon noch die Ausführungszeit der I2C Befehle im Interrupt abziehen.
Wenn das reicht, musst du die I2C Kommunikation nur unmittelbar nach dem Interrupt machen, wie oben geschrieben mittels eines Flag.
Wenn nicht, bleibt noch die Möglichkeit, einzelne Teile der gesamten Kommunikation zwischen den interrupts durchzuführen, so wie Klabwax das vorgeschlagen hat.

Klebwax
23.09.2012, 19:44
Wenn nicht, bleibt noch die Möglichkeit, einzelne Teile der gesamten Kommunikation zwischen den interrupts durchzuführen, so wie Klabwax das vorgeschlagen hat.

Du hast mich missverstanden. Nicht zwischen den Interrupten, in den Interrupten. Sonst muß, wie ich schon sagte, die Mainloop schneller als die Interrupte sein und man kann nie eine längere Berechnung machen.

MfG Klebwax

Che Guevara
23.09.2012, 20:18
Hi,

nunja, ich erklärs mal ein bisschen:
Alles, was in der ISR(1) abgearbeitet wird dauert im Worst-case ca. 0.666ms. Die ISR(1) wird alle 1.25ms aufgerufen, d.h. zwischen zwei ISR-Aufrufen bleiben ca. 0.6ms Zeit. Dann gibts allerdings noch einen zweiten und einen dritten Interrupt, diese sind für das einlesen des PWM-Summensignals verantwortlich. Wann diese genau kommen, hängt immer von der Stellung der Fernsteuerungsknüppel ab. Diese beiden Interrupts sind Hi-Level, d.h. sie können den anderen Interrupt (Lo-Level) jederzeit unterbrechen.
Es ist also so, dass selbst wenn ich die I2C-Kommunikation direkt nach der Regelschleifen-ISR(1) ausführe ich nicht weiß, ob nicht ein anderen Interrupt dazwischen kommt und direkt danach dann wieder die ISR(1).
Ich hoffe ihr versteht die Thematik.

Gruß
Chris

Klebwax
23.09.2012, 20:47
Was man machen kann, ist folgendes:

I2C wird nur in ISR(1) gemacht. Das kann dann auch mal von einem anderen Interrupt unterbrochen werden, solange weder in main() noch in einem anderen Interrupt die I2C-Hardware angefasst wird. Das schlimmste was passieren kann, ist das die Pause zwischen zwei I2C Bytes etwas länger wird.

Nicht in jedem ISR(1) wird das gleiche gemacht. Mal wird der eine Sensor, mal der andere abgefragt. Dadurch wird die ISR nie zu lang. Dazu kann man einen Zähler in der ISR mitführen, und die Sensoren je nach Zählerstand auswählen.

MfG Klebwax

Che Guevara
23.09.2012, 21:59
Hi,

auch das scheidet leider aus, da der Sensor welcher in der ISR(1) abgefragt wird der Gyro + ACC (MPU6000) ist, welcher zwingend notwendig ist. Es wäre zwar evtl. möglich, den anderen Slave auch noch in der ISR abzufragen, aber spätestens wenn dann nochmal ein Slave hinzukommt, wirds wohl Probleme geben...
Was wäre den, wenn ich am Anfang der ISR(1) einfach einen provisorischen I2CSTOP einfüge? IMHO sollte dann, falls eine Verbindung vorhanden ist, diese gestoppt werden?

Gruß
Chris

Kampi
23.09.2012, 22:15
Was wäre den, wenn ich am Anfang der ISR(1) einfach einen provisorischen I2CSTOP einfüge? IMHO sollte dann, falls eine Verbindung vorhanden ist, diese gestoppt werden?


Wird wahrscheinlich nicht funktionieren, da du damit den I²C am Mikrocontroller stoppst aber wenn ein Device bereits ausgewählt wurde ändert der Stop-Befehl da nichts dran.

Klebwax
23.09.2012, 22:33
Wird wahrscheinlich nicht funktionieren, da du damit den I²C am Mikrocontroller stoppst aber wenn ein Device bereits ausgewählt wurde ändert der Stop-Befehl da nichts dran.

So ist es.

Die Frage ist: wie oft muss der jeweilige Sensor gelesen werden. Wie ist seine Messbandbreite? Kann z.B. der ACC alle 1,25ms ein wirklich neues Ergebniss liefern? Und wie weit dreht sich dein Kopter in 1,25ms. Reicht es aus, nur alle 2,5ms einen echten Messwert zu nehmen und dazwischen zu interpolieren? Die langsameren Sensoren werden dann, einer nach dem anderen in jeder 2. ISR gelesen.

MfG Klebwax

Che Guevara
23.09.2012, 22:36
Ja, der ACC und der GYRO sind beide in der Lage, alle 1ms (also 1000Hz) ein neues Signal zu liefern. Die Freqzenz von 800Hz ist zwar nicht zwingend (es könnten auch 600Hz sein), aber das Flugverhalten wird dadurch besser, da ja der Gyro auch integriert wird... Ob der merkbare Unterschied dadurch sooo groß ist weiß ich nicht, aber ich möchte es bei 800Hz belassen ;)

Aber bei einer normalen Kommunikation wird doch die "Verbindung" auch durch ein I2CSTOP beendet. Dem Slave sollte es doch egal sein, ob ich ihn nur addressiere oder auch einen Befehl schicke... Oder irre ich mich da?

Gruß
Chris

Kampi
23.09.2012, 22:49
Aber bei einer normalen Kommunikation wird doch die "Verbindung" auch durch ein I2CSTOP beendet. Dem Slave sollte es doch egal sein, ob ich ihn nur addressiere oder auch einen Befehl schicke... Oder irre ich mich da?



Dieses I2CStop sorgt dafür das ein NACK gesendet wird. Die Verbindung wird dadurch nur beendet, weil der Slave dann ein NACK erwartet.
Wenn er ein NACK bekommt obwohl er Daten erwartet, kann das zum Fehlverhalten des Slaves führen bzw. den Bus stören.
Ob du ihm nun eine Adresse schickst oder Daten ist dem Slave egal. Er wertet einfach nur das erste Datenpaket als Adresse und dann das zweite als Daten. Mehr macht er nicht (wie soll er auch sonst erkennen ob das erste Datenpaket eine Adresse oder Daten sind wenn man ihm das vom Werk aus nicht vorgibt).
Es ist beim I²C Bustechnisch festgelegt, dass die ersten Daten eine Adresse sind und von daher weiß der Slave das es sich um eine Adresse handelt und es ist auch festgelegt, dass eine Kommunikation mit einem NACK endet und deswegen weiß der Slave, dass bei einem NACK die Kommunikation zu ende ist.
Wenn du nun einfach mittendrin ein NACK sendest verwirrst du den Chip.
Das ist im Grunde dasselbe als wenn du jemanden nach der Uhrzeit fragst und er dir sagt das die Sonne scheint ;)
Der I²C Bus ist nun mal nicht dafür gedacht das mitten in einer Kommunikation die Kommunikation abgebrochen wird. Sowas gilt es softwareseitig zu umgehen.