Hallo, ich fahre einen ATmega8 mit 2 MHz Quarz und +5V Versorgungsspannung. Angeschlossen ist eine I2C Real Time Clock, RTC (PCF8563). Die TWI bitrate beträgt 20.000 bit/s. Der TWI Bus besitzt 2 x 10 KOhm Pull-up Widerstände. Die Kommunikation mit der RTC funktioniert tadellos. Der Alarm-Teil der RTC erzeugt nach jeder Minute einen low level interrupt, der an INT1 angeschlossen ist. Jetzt das Problem: Wenn die RTC "scharf" gemacht wurde, versetze ich den ATmega8 in den Power-Down mode. Nach einer Minute weckt die RTC via INT1 den ATmega8 wieder auf. --> Danach soll die RTC wieder scharf gemacht und der ATmega8 wieder in den Power-Down mode versetzt werden. Das funktioniert aber nicht mehr, denn die TWI Kommunikation ist tot, bzw hängt. Durch debuggen habe ich folgendes heraus gefunden: - Vor dem Schlafen legen hat das TWCR register einen Wert von 0x20 oder 0x04, je nachdem welche TWI Operation vorher statt gefunden hat - so wie es sein soll. - Unmittelbar nach dem Aufwachen hat das TWCR register einen Wert von 0x84, d.h. das TWINT und das TWWC bit ist gesetzt. Das TWWC (TWI Write Collision Flag) besagt: "The TWWC bit is set when attempting to write to the TWI Data Register – TWDR when TWINT is low.". Dabei hat während der Power-Down Phase keinerlei TWI write Aktion statt gefunden. Es ist auch schon mal passiert, dass die CPU nach dem Aufwachen einen Reset durchgeführt hat. Meine ad hoc Lösung: Bevor ich wieder das TWI nach dem Aufwachen verwende, setze ich das TWCR = 0. Im Anhang die entsprechenden Code-Schnipsel als txt file. Frage: Ist das ein Hardware Fehler des ATmega8, den bisher keiner bemerkt hat, oder habe ich etwas übersehen, oder in der Doku noch nicht verstanden ? Grüße Manni
Manfred L. schrieb: > Im Anhang die entsprechenden Code-Schnipsel als txt file. Was soll die Schnipselei, da sieht doch keiner durch. Wo ist die Mainloop? Poste echten Code und nenne ihn auch richtig (*.c), sonst funktioniert die Darstellung nicht.
Manfred L. schrieb: > Dabei hat während der Power-Down Phase keinerlei TWI write Aktion statt > gefunden. Während des PowerDown sicher nicht. Aber wohl beim Einschlafen oder beim Aufwachen. Mehr kann man angesichts des unvollständigen Quelltextes nicht sagen. Ähem doch: die Sequenz zum Einschlafen ist schlicht falsch, sie enthält die Möglichkeit für eine race condition. Ob das jetzt die Ursache des TWI-Problems ist, kann man allerdings (wieder mangels vollständigem Code) nicht sagen. > Es ist auch schon mal passiert, dass die CPU nach dem Aufwachen einen > Reset durchgeführt hat. Das ist auf jeden Fall ein sicherer Hinweis auf entweder einen kapitalen Bug oder Hardwareprobleme.
Peter D. schrieb: > Was soll die Schnipselei, da sieht doch keiner durch. Entschuldige bitte, wenn ich gegen die Netiquette im Forum verstoßen haben sollte. Bin erst seit 2005 dabei. Ich wollte Euch und das Forum nicht mit Sinnlosem vollmüllen. Wie von Dir gewünscht, in der zip file Anlage alle Sourcen der .c und .h files. Ebenso eine Schematics der verwendeten Hardware. Ich hoffe, das hilft weiter :-)
c-hater schrieb: > Das ist auf jeden Fall ein sicherer Hinweis auf entweder einen kapitalen > Bug oder Hardwareprobleme. Das Reset Problem hat sich als Wackelkontakt erledigt. Der vollständige Source Code ist im oberen Post an Peter beigelegt. Aber ich danke Dir für den Hinweis zum Thema "race condition". Dabei bin ich auf die Seite: http://www.gammon.com.au/interrupts gestoßen. Unter dem Heading "How are interrupts queued?" findet man hier noch weitere Lösungen für den Sleep mode und das Aufwachen durch interrupts. Habe dies aber noch nicht im Detail getestet.
> Unmittelbar nach dem Aufwachen hat das TWCR register > einen Wert von 0x84, d.h. das TWINT und das TWWC bit > ist gesetzt TWWC? Ich lese im Datenblatt TWINT und TWEN.
Manfred L. schrieb: > Unter dem Heading "How are interrupts queued?" findet man hier > noch weitere Lösungen für den Sleep mode und das Aufwachen durch > interrupts. Habe dies aber noch nicht im Detail getestet. Kannst du machen, ist sicher auch interessant, hat aber nichts mit deinem Problem zu tun. Das wichtigste Rat steht übrigends ganz unten in dem Beitrag: "Read the data sheet!" Oliver
Manfred L. schrieb: > Habe dies aber noch nicht im Detail getestet. Neben diesem Problem ist auch das Handling des Level-Interrupts stark verbessungswürdig. Auf der sicheren Seite bist du nur, wenn du ihn bereits in der ISR verbietetest. Ansonsten wird diese bei einem Aufwachen deutlich mehr als nur einmal ausgeführt... Außerdem ist mir aufgefallen, dass du vor dem Einschlafen weder testest, ob deine TWI-Operation vollständig abgeschlossen ist, noch ob deine UART-Ausgabe vollständig abgeschlossen ist. Beides muß gegeben sein, sonst versteht der jeweilige Peer nur noch "gnülpft", denn beides hält beim Powerdown erstmal stumpf an. Ganz prekär ist das beim TWI, den das enthält auch asynchrone Logik, die zwar als Master nicht relevant ist, aber nichtsdestotrotz sicherlich in irgendeiner Form beim Einschlafen "angefasst" wird.
Manfred L. schrieb: > Bin erst seit 2005 dabei. Ich wollte Euch und das Forum > nicht mit Sinnlosem vollmüllen. Sorry für OT: besser wäre, die Quelltexte und Header mit korrekter Endung anzuhängen. Die Forensoftware kann’s dann hübsch mit Syntax-Highlighting und so darstellen, so dass es für potentielle Helfer erheblich angenehmer und schneller ist, sich das anzuschauen. Das ganze Geraffel in ein Archiv zu packen, das man sich dann erstmal laden und auspacken muss, war ein Schritt in genau die falsche Richtung.
Jack V. schrieb: > das man sich dann erstmal laden > und auspacken muss, war ein Schritt in genau die falsche Richtung. Ich finde beides gut! OK, es ist eher so, dass es schon etwas nervt, wenn das gerade bequeme fehlt. Zum anschauen ist es schön alle Dateien im Foren Erleuchter zu erreichen. Will ich das Projekt testen, macht eine *.zip mehr Spaß. Je mehr Dateien drin sind, desto mehr Spaß. Viele Einzeldateien im Erleuchter sind dann eher Unspaß.
Jack V. schrieb: > Das > ganze Geraffel in ein Archiv zu packen, das man sich dann erstmal laden > und auspacken muss, war ein Schritt in genau die falsche Richtung. Nö. Das ist genau richtig. So kann man sehr schnell ein Projekt daraus machen und dieses (hoffentlich) kompilieren und (hoffentlich) laufen lassen. Ich habe keine zwei Minuten gebraucht, um aus dem Archiv ein solches Projekt zu machen. Syntax-Highlighting habe ich dann auch in der lokalen Version. Und ich weiß, dass es ohne Fehler und Warnungen kompiliert, der Schöpfer des Projektes also zumindest mit einiger Wahrscheinlichkeit die verwendete Sprache hinreichend beherrscht. Ich kann mich also bezüglich der Fehleranalyse voll auf den sachlichen Gehalt der Software konzentrieren. Ich habe aber noch sehr viel mehr, z.B. ein *.lss-File, was mir zeigt, was wirklich passiert, wenn an irgendeiner Stelle Zweifel bezüglich irgendeiner Sache bestehen, die einfach nicht im C-Quelltext nachgelesen werden kann. Was u.a. bei der Pennerei nicht ganz unwichtig ist...
c-hater schrieb: > Neben diesem Problem ist auch das Handling des Level-Interrupts stark > verbessungswürdig. Auf der sicheren Seite bist du nur, wenn du ihn > bereits in der ISR verbietetest. Ich danke Dir auch hier für den wertvollen Hinweis. Die ISR habe ich daraufhin wie folgt geändert:
1 | ISR (INT1_vect) |
2 | {
|
3 | cli (); |
4 | CLEAR_BIT (GICR, INT1); |
5 | }
|
c-hater schrieb: > Außerdem ist mir aufgefallen, dass du vor dem Einschlafen weder testest, > ob deine TWI-Operation vollständig abgeschlossen ist, noch ob deine > UART-Ausgabe vollständig abgeschlossen ist. Auch dieser Hinweis ist vollkommen richtig! Meines Erachtens habe ich dies in allen TWIM_xxxx Funktionen (file TWI_Master.c) so implementiert habe, z.B. in TWI_Write()
1 | /*
|
2 | ** Wait until transmission completed
|
3 | */
|
4 | while (!(TWCR & (1<<TWINT))); |
Somit sollte doch sicher gestellt sein, dass beim Verlassen der Funktion die TWI Aktion für den Master abgeschlossen ist. Bei der UART Ausgabe prüfe ich jetzt im UCSRA Register, ob das TXC Bit gesetzt ist. Somit sollten allen Aktiviäten der CPU abgeschlossen sein, bevor es in den sleep mode geht. Leider steht im TWCR Register nach dem wake-up immer noch der Wert 0x84 (TWINT=1, TWEN=1), aber vor dem Sleep mode war es 0x04 (TWEN=1), was es auch sein sollte. Mit meiner Krücke --> TWCR=0 läuft die CPU jetzt schon seit mehr als zwei Tagen kontinuierlich durch, ohne sonstige Fehler oder Mucken. Aber trotzdem wurmt es mich, denn es darf nicht sein, was nicht sein kann !
Manfred L. schrieb: > while (!(TWCR & (1<<TWINT)));[/c] > Somit sollte doch sicher gestellt sein, dass beim Verlassen der Funktion > die TWI Aktion für den Master abgeschlossen ist. Nein, das ist leider nicht der Fall. Das letzte, was du bei einer Transaktion normalerweise tust, ist das Absetzen der STOP condition. Deren Erscheinen auf dem Bus geschieht aber einerseits nicht instantan, wird aber andererseits auch nicht durch TWINT zurückgemeldet. Du mußt also vor dem Einschlafen zusätzlich auf das "Verlöschen" von TWSTO warten.
Hallo, Problem detektiert und behoben ! Problem war: Wenn die CPU (ATmega8) in den sleep mode geschickt und durch einen INT1 interrupt wieder aufgeweckt wurde, funktionierte der TWI (I2C) Link nicht mehr. Vorher funktionierte der Link noch. Hier arbeitet die CPU als Master. Ursache ist: Bei allen TWI Operationen (Conditions) wird das TWEN Bit im TWCR Register auf TRUE gesetzt, z.B.:
1 | TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTA); // START Condition |
2 | TWCR = (1<<TWINT)|(1<<TWEN); // WRITE Operation |
3 | TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA); // READ Operation hier mit ACK |
4 | TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO); // STOP Condition |
Wenn diese Operationen durch eine STOP Condition beendet wurden, bleibt das TWEN Bit stets als einziges Bit im TWCR gesetzt. Die CPU nimmt vermutlich an, dass noch weitere TWI Operationen folgen, weil halt das TWI I/F noch ENabled ist. In diesem Zustand darf die CPU anscheinend nicht in den sleep mode geschickt werden, denn nach dem Aufwachen ist im TWCR Register neben dem TWEN Bit auch noch das TWINT Bit gesetzt worden, von wem auch immer. Die Lösung: Da am Ende einer jeden TWI Operation die STOP Condition durchgeführt wird, ist danach das TWCR Register auf 0 zu setzen, d.h. das TWI I/F wird disabled. Danach kann in den sleep mode gegangen werden und nach dem Aufwachen steht im TWCR Register immer noch eine 0 und die nachste TWI Operation läuft ohne Fehler durch. Die überarbeitete STOP Condition Prozedur sieht dann wie folgt aus:
1 | TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO); |
2 | while (TWCR & (1<<TWINT)); |
3 | while (TWCR & (1<<TWSTO)); |
4 | TWCR = 0; |
Ich bedanke mich bei allen für die hilfreichen Kommentare, speziell bei c-hater ! Grüße Manni
Beitrag #6325915 wurde von einem Moderator gelöscht.
Manfred L. schrieb: > Wenn diese Operationen durch eine STOP Condition beendet wurden, bleibt > das TWEN Bit stets als einziges Bit im TWCR gesetzt. Die CPU nimmt > vermutlich an, dass noch weitere TWI Operationen folgen, weil halt das > TWI I/F noch ENabled ist. In diesem Zustand darf die CPU anscheinend > nicht in den sleep mode geschickt werden, denn nach dem Aufwachen ist im > TWCR Register neben dem TWEN Bit auch noch das TWINT Bit gesetzt worden, > von wem auch immer. Das sind sehr viele angenommene Vermutungen. So lange im Datenblatt nichts zu den Themen steht, ist das aber alles eher weniger oder auch ganz bestimmt nicht zutreffend. Ein leicht zu übersehendes Problem des AVR-TWI ist, daß der Zyklus für das Modul nach Senden eines STOP am Ende der Kommunikation erst nach Ablauf der für ein Stop erforderlichen Haltezeit beendet ist. Die Bits im Konfigurationsregister werden aber sofort gesetzt. Oliver
:
Bearbeitet durch User
Nachtrag: Hatte ich übersehen: c-hater schrieb: > Du mußt also vor dem Einschlafen zusätzlich auf das "Verlöschen" von > TWSTO warten. So isses. Oliver
Beitrag #6330417 wurde von einem Moderator gelöscht.
Oliver S. schrieb: > Das sind sehr viele angenommene Vermutungen. So lange im Datenblatt > nichts zu den Themen steht, ist das aber alles eher weniger oder auch > ganz bestimmt nicht zutreffend. Das ist richtig ! Da im Datenblatt dazu nichts steht, sind praktikable Lösungen gesucht, die ich im Post vom 03.07.2020 18:48 dargestellt habe. Diese Lösung läuft jetzt seit 4 Tagen durch und zeigt keine Mucken (4 x pro Sekunde) Oliver S. schrieb: > So isses. Dazu warte ich 0.1 Sekunden, bevor ich den Sleep Modus einschalte. In dieser Zeit ist die STOP Condition durch die CPU mit Sicherheit abgearbeitet. Danke für die Kommentare Manni
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.