Hallo,
ich habe ein Problem mit der Kommunikation meines ATMega mit einer
Z80-PIO. Aus irgendwelchen Gründen komme ich in der Kommunikation mit
der PIO aus dem Trab und bleibe unter gewissen Bedingungen in einer
Endlosschleife hängen in der Hoffnung ein Signalwechsel der PIO zu
erleben welcher aber nie eintritt.
Mein Problem ist nun, das ich gerne die Endlosschleife finden würde in
der er hängen bleibt das genaue Signal zu erfahren auf was er wartet und
wo er
genau im Programmablauf stecken bleibt.
Leider ist die Kommunikation mit der PIO vom Timing her so das ich
extrem limitiert bin mit dem was ich so "dazwischen" noch machen kann.
Ausgaben über UART fallen z.B. komplett flach.
Da auch alle Ports belegt sind, habe ich kein JTAG o.ä. zur Verfügung
sondern ausschliesslich ISP und mein AVR Dragon.
Ich habe in meiner Signal-Warteschleife einen counter eingebaut und bei
Überlauf des Counters gebe ich den letzten Wert einer Variable aus dem
"Hauptprogramm" aus - in der Hoffnung zu erkennen an welcher Stelle er
auf das Signal wartet.
Problem ist nun, das uint8_t zu wenig Wartezeit bietet. uint16_t auch,
und uint32_t scheint irgendwie nie in den Überlauffall reinzulaufen
(kann ich mir eigentlich nicht vorstellen). Konkrete Überprüfungen der
Werte der Überlaufvariablen sind zeitlich auch nicht möglich (ich kann
also nicht checken ob uint32_t i > 20.000.000 ist). Ich kann lediglich
darauf prüfen ob der Counter 0 ist. Ich habe mir also mit einem
Überlaufzähler beholfen. Leider ist die dadurch zur Verfügung stehende
Zeit auch nicht ausreichen. Ein weiterer Überlaufzähler für den
Überlaufzähler ist zeitlich schon wieder nicht möglich....
Hier mal der aktuelle Stand meiner "Warteroutine mit
Endlosschleifenerkennung"
"err" wird vom Hauptprogramm mitgegeben und gibt mir einen Hinweis auf
die Codestelle im Hauptprogramm. Noch ein uint8_t geht nicht.
JTAG-Debugging geht nicht (hab ich auch noch nie gemacht). Wie gesagt -
irgendwelche uart-Ausgaben ohne das der Fehlerfall eingetreten ist geht
auch nicht.
Hat noch einer eine Idee wie ich rausfinden kann in welcher Zeile des
generierten ASM Codes der AVR bis zum Sankt Nimmerleinstag wartet (dank
inline habe ich dann die Stelle des Hauptprogramms...)
Ich kann ca. sagen was eine einzelne Datenkommunikation an Zeit dauern
müsste. Kann ich vor jeder Kommunikation einen Timer konfigurieren und
diesen einen Interrupt auslösen lassen? Wenn ich dann die notwendigen
Variablen um die Codestelle zu identifizieren global mache kann ich dann
auf diese in der Interruptroutine zugreifen und diese dann dort
ausgeben. Wenn die Datenkommunikation erfolgreich durchläuft, stoppe ich
den Timer einfach (damit kein IRQ ausgelöst wird).... Klingt irgendwie
durchs Knie ins Auge? Ist das so möglich oder gibt es noch bessere
Wege?
Bevor jemand auf die Idee kommt - ja ich habe einen LA, aber der kann
weder Life-View noch hat er Pre-Trigger-Möglichkeiten - und der Fehler
tritt teilweise erst nach einer Stunde permanenter Kommunikation auf...
Keine Chance mit meinem LA da per Zufall genau diesen Mißstand zu
erwischen.
Du kannst vor der Kommunikation den Timer starten und - wenn er feuert -
den Program Counter vom Stack pulen. Den kannst du auf dein ELF werfen
(addr2line) und bekommst dann genau die Codezeile, wo er war, als der
Timer feuerte.
Je nachdem, wie viel Platz du noch im Flash hast, kannst du auch den
gesamten Stack entlanglaufen und dir den Callstack zusammenbauen. In der
Interrupt-Routine bist du ja ganz allein im System, und da es eh schon
abgestuerzt ist, hast du auch nichts mehr zu verlieren.
Hi,
>Hat noch einer eine Idee wie ich rausfinden kann in welcher Zeile des>generierten ASM Codes der AVR bis zum Sankt Nimmerleinstag wartet
was macht dein Wachhund derweil?
>gebe ich den letzten Wert einer Variable aus dem>"Hauptprogramm" aus -
Der Gedanke ist doch gut, du must ihn nur weiterspinnen.
Nenne die Variable Durchlaufzahl und lade sie in jedem wichtigen
Programmabschnitt mit einer def. Zahl. Mit etwas Hirnschmalz kann man
das sehr fein auflösen. Schnappt dann der Wachhund zu, wird bei
Programmstart einfach die Durchlaufzahl ausgegeben und du kannst sagen
wo er vorher war.
Ich mache das jedenfalls so und habe immer gefunden wo es klemmt.
Viel Erfolg, Uwe
Oliver L. schrieb:> Hat noch einer eine Idee wie ich rausfinden kann in welcher Zeile des> generierten ASM Codes der AVR bis zum Sankt Nimmerleinstag wartet (dank> inline habe ich dann die Stelle des Hauptprogramms...)
Mach doch mal einen 8-bit SysTimer mit 1ms Auflösung.
Vor jeder Kommunikation setzt du einen Flag auf 1 und Counter auf 0.
Nach der Kommunikation (falls erfolgreich) wieder zurücksetzen - am
besten alles in der Kommunikations-Routine selbst.
Wenn in der ISR der Flag gesetzt ist, wird der Counter hochgezählt.
Wenn der Counter überläuft ( > 255ms) wird der Stack uber UART
ausgegeben - wenn man die PUSH-Befehle in der ISR abzieht, hat man
die Adresse (+1 oder +2) wo es klemmt.
So etwas ähnliches hatte ich früher, bei OBD-Testern, es hat immer
funktioniert.
EDIT
Und hab es immer noch - bei I2C.
Oliver L. schrieb:> Da auch alle Ports belegt sind, habe ich kein JTAG o.ä. zur Verfügung> sondern ausschliesslich ISP und mein AVR Dragon.
Hat dein geheimer ATmega evtl. DebugWire? Dann kannst du über den
RESET-Pin debuggen.
Was ich da lese klingt für mich nach einer typischen Race-Condition:
„Unter bestimmten Umständen“ wir Deine Warteschleife das Signal einfach
verpassen und dann bis in alle Ewigkeit auf das bereits vergangene
Signal warten. Um das genau beurteilen zu können müsste man wissen, was
genau Du machst. (Warum z.B. rufst Du 2x info_wardy_is_high() auf?) Wenn
ich mit meiner Vermutung richtig liege wird ein Debugging mit üblichen
Mitteln schwierig, da es schwierig ist, die Fehlerbedingung zu
reproduzieren. Schon kleinste Änderungen am Code können das Timing so
verändern, dass das Programm nicht mehr in den Fehler hineinläuft ohne
ihn natürlich wirklich zu beheben.
Klopfe Deine Signalkette doch mal nach Stellen ab, an denen das Signal
verloren gehen könnte.
Eine gute Einführung in das Thema findet sich, wenn ich mich richtig
erinnere, bei ISBN 0596005903 im Kapitel 5. Das Buch ist auch online
verfügbar: http://www.oreilly.com/openbook/linuxdrive3/book/
Ich habe einen "Festplattenemulator" der als Speichermedium einersiets
SD-Card sowie auch eine PATA-Festplatte anbietet.
Auf der anderen Seite sitzt eine Z80-PIO die nicht so schön designed
einfach Ihre PIO-Ports nach aussen über ein DB25-Kabel zur Verfügung
stellt (Legacy System, keine Änderung möglich). Die Signalqualität ist
daher nicht wirklich optimal. Daher sind teilweise Abfragen doppelt drin
um "Noise" zu umschiffen.
Mit der Festplatte als Speichermedium habe ich scheinbar keinerlei
Probleme. Ich kann das System stundenlang laufen lassen mit permanenter
Datenbefeuerung.
Sobald ich die Festplatte abklemme und jedoch mit der SD-Card arbeite
verhängt sich das System in der Host-Kommunikation. Es verhängt sich
nicht, wenn ich die Bustreiber auf meinem System mit ganz bestimmten
HCT245 bestücke. Andere HCT245, oder LS245 führen zu diesem
"Hängereffekt".....
Irgendwas in der Schaltung wird ein Problem haben was zu ggf. mehr Noise
führt oder was weiss ich.... Will jetzt auch gar nicht zu sehr ausholen,
da ich das Hardwareproblem schon an anderer Stelle diskutiere.
Jedenfalls interessiert mich erstmal wo aktuell die Kommunikation hängen
bleibt.
http://www.pofo.de/P8000/wdcemu.php
ATMega ist ein 1284P - hat der DebugWire? Habe in den Specs nach
"DebugWire" gesucht und nix gefunden.
Edit: Ok - mit "noinit" lasse ich meine Zählervariable den
Watchdog-Reset überleben...
Originaler Beitrag:
Ist denn nach einem Reset via Watchdog Timer sichergestellt, das ich den
Inhalt einer globalen Variable noch lesen kann? Ich habe mal testweise
eine variable global angelegt, und dann auf 1 gesetzt - danach den
Watchdog timer auf 15ms gestellt. (über eine .init3 Funktion dann beim
Bootup den WDT auch wieder deaktiviert).
Die Variable bleibt 0 beim bootup.
Wird der SRAM nicht abgeräumt beim bootup?
> Ist denn nach einem Reset via Watchdog Timer sichergestellt, das ich den> Inhalt einer globalen Variable noch lesen kann?
Nur wenn du die Variable in einer nicht initialisierten Speicher-Sektion
platzierst: http://www.nongnu.org/avr-libc/user-manual/mem_sections.html
Jo, genau das habe ich nun getan.
Habe eine Variable in der .noinit Sektion
Meinen Watchdog Timer so aufgesetzt, das er eine ISR auslöst
Und in der ISR sorge ich dann dafür das ich insgesamt erst nach einer
Minute einen Reset auslöse.
Ich hoffe, das ich nun so weiterkomme.... Vielen Dank erstmal soweit!!