Ich möchte in der Watchdog-ISR die Interrupt-Rücksprung-Adresse
speichern, um nach dem Reset feststellen zu können, wo der Watchdog
angesprochen hat.
Folgender Code für einen 328P:
1
// Speicherbereich, in den der Stack kopiert werden soll. (Die section
2
// .noinit wird nach dem Reset nicht überschrieben!)
Eigentlich habe ich erwartet, dass ich nach dem Watchdog-Reset in der
Variablen SaveArea.sp den Inhalt des Stacks der ISR incl.
Rückkehradresse finde.
Dem ist aber nicht so: SaveArea.sp enthält zwar einen plausiblen Wert
für SP, in SaveArea.stack finde ich aber kein Bytemuster, das eine
plausible ISR-Rückkehr-Adresse ergibt.
Wo steckt der Fehler?
Uhu U. schrieb:> Wo steckt der Fehler?
Wahrscheinlich in deiner Interpretation der Daten.
Zeige den Assemblerquelltext deines Programms und einen Dump der
aufgezeichneten Stackdaten. Dann werden wir die Rücksprungadresse schon
finden...
Die ISR-Rückkehradresse müsste also 0x1a26 sein, denn auf diesem Befehl
schlägt der Watchdog in main zu. Die ISR kopiert dann die Daten in die
SaveArea und wartet, bis der WD ein zweites mal zuschlägt und den Reset
auslöst.
Logischerweise müssten danach in der SaveArea die Bytes 26 1a vorkommen
- tun sie aber nicht.
Die main sieht folgendermaßen aus:
1
intmain(void){
2
memcpy(&sa,&SaveArea,sizeofsa);
3
4
initErrorLED();
5
initWatchdog(WDTO_2S);
6
7
initializeUART();
8
9
set_sleep_mode(SLEEP_MODE_IDLE);
10
sei();
11
12
...
13
14
assert(!memcmp(&SaveArea,&sa,sizeofsa));// check, if SaveArea has been corrupted
Zu Beginn von main lege ich eine Sicherheitskopie sa der SaveArea an und
prüfe mit dem assert(…), ob sich durch die (hier weggelassenen)
Initialisierungen irgendwas geändert hat - das ist nicht der Fall.
Mit den Befehlen * und # habe ich getestet, ob meine SaveArea einen
manuell ausgelösten Reset unbeschadet übersteht - das ist der Fall, die
Daten in der SaveArea sollten also den Stack enthalten, wie er in der
Watchdog-ISR war.
Leider bin ich nicht schlauer, als vergangene Nacht…
Kann man die Adresse auch mit pull/push vom Stack holen? So kenne ich
das aus alter Zeit.
Einmal habe ich einen 8080-Emulator auf dem 6502 laufen lassen, der in
der Funkschau veröffentlicht war. Die Rücksprungadresse lag allerdings
daneben, weil die beiden Prozessoren unterschiedliches ablegten, der
eine die Folgeadresse und der andere die aktuelle.
Uhu U. schrieb:> Der ASM-Code im Hauptprogramm sieht so aus:
Und der der ISR?
Welche Werte finden sich denn im Stack?
Da deine ISR nicht naked ist, werden vermutlich doch ein paar Register
auf den Stack gepusht. Memcopy kann sicherlich nicht ganz ohne. Damit
zeigt der Stackpointer dann nicht mehr auf das, was du vermutest.
Oliver
Da ist deine Rücksprungadresse.
Uhu U. schrieb:> Logischerweise müssten danach in der SaveArea die Bytes 26 1a vorkommen
Nein, denn erstens ist das die Byte-Adresse, und zweites stehen die
Bytes auf dem Stack andersherum, denn er wird ja von Oben nach Unten
beschrieben.
Christoph db1uq K. schrieb:> Kann man die Adresse auch mit pull/push vom Stack holen? So kenne ich> das aus alter Zeit.
Dann müsste man den ganzen Stack abräumen, denn die Rückkehradresse
liegt ja über allem, was die ISR auf den Stack geschoben hat.
Der springende Punkt kann eigentlich nur dieser Aufruf in der ISR sein:
Uhu U. schrieb:> Logischerweise müssten danach in der SaveArea die Bytes 26 1a vorkommen
Da steht aber 13 0D, was die genaue Hälfte von 26 1A ist. Da der AVR das
ROM mit 16-Bit-Zugriffen anspricht, und nicht mit 8-Bit-Zugriffen,
könnte das die Erklärung sein.
Uhu U. schrieb:> Der ASM-Code im Hauptprogramm sieht so aus:
Und die ISR?
Denn:
Durch abzählen der push Operationen, solltest du den abgelegten PC
lokalisieren können.
In etwa so:
adresse = AktuellerSP+AnzahlPush+FlagByte
Adresse+1 und Adresse+2 sollte dann den PC ergeben
? ? ?
Rufus Τ. F. schrieb:> Da der AVR das> ROM mit 16-Bit-Zugriffen anspricht, und nicht mit 8-Bit-Zugriffen,> könnte das die Erklärung sein.
Das wird so sein, nicht nur könnte.
Uhu U. schrieb:> Die ISR-Rückkehradresse müsste also 0x1a26 sein, denn auf diesem Befehl> schlägt der Watchdog in main zu.
Wie kommst du zu dieser Erkenntnis?
Diese Adresse wird auch auf dem Stack sein.
Die ISR-Rückkehradresse ist davon abhängig wo genau der Watchdog in der
uart_puts_P zuschlägt.
Uhu U. schrieb:> Wie kommst du darauf?Stefan E. schrieb:> Uhu U. schrieb:>> Logischerweise müssten danach in der SaveArea die Bytes 26 1a vorkommen>> Nein, denn erstens ist das die Byte-Adresse, und zweites stehen die> Bytes auf dem Stack andersherum, denn er wird ja von Oben nach Unten> beschrieben.
Rufus Τ. F. schrieb:> Uhu U. schrieb:>> Logischerweise müssten danach in der SaveArea die Bytes 26 1a vorkommen>> Da steht aber 13 0D, was die genaue Hälfte von 26 1A ist. Da der AVR das> ROM mit 16-Bit-Zugriffen anspricht, und nicht mit 8-Bit-Zugriffen,> könnte das die Erklärung sein.
Interessanter Gedanke:
Die ISR pusht 15 Byte, dann müsste die Rückkehradresse bei SP+16 liegen.
---
Ich habs ausprobiert - das kommt hin mit folgendem Befehl:
Das war eine schwere Geburt… Mit diesem Harvard-Modell werde ich mich
wohl nie anfreunden.
Vielen Dank für die Hilfe!
PS für die, die den Trick nachmachen wollen:
Der Offset ist nicht fest, sondern hängt davon ab, welche Register in
der ISR gebraucht und folglich auf dem Stack zwischengespeichert werden
müssen.
Man muss sich im konkreten Fall immer den asm-Code der ISR ansehen und
danach den Offset bestimmen.
Der Beitrag "Watchdog speichert Reset-Adresse -- für atmega328p" enthält eine
ausgefeiltere Version des Watchdog-Paktes, die die Rückkehr-Adresse der
Watchdog-ISR automatisch findet. Man muss also nicht mehr nach jeder
Änderung an der Watchdog-ISR den Offset überprüfen.