Forum: Compiler & IDEs WinAVR - Sprung zu absoluter Adresse


von Steffen Hausinger (Gast)


Lesenswert?

Hallo allerseits,

ich stehe bei WinAVR momentan vor folgendem Problem: Ich möchte aus 
meiner Applikation heraus meinen Bootloader aufrufen. Da die Applikation 
die Adresse des Bootloaders nicht kennt, habe ich am Ende des Flashs 
einen Sprungbefehl definiert, der zum Bootloader führt. Die Applikation 
muss also nur einen Sprung zur letzten Flashadresse machen und wird dann 
entsprechend weitergeleitet.

Nur - wie macht man so einen Sprung zur letzten Adresse in WinAVR? Alle 
Sprungbefehle scheinen relativ sein. Gibt es einen Befehl wie "goto" für 
absolute Adressen? Auch mit inline Assembler komme ich nicht so recht 
weiter. Wenn ich "rjmp FLASHEND" schreibe, macht er nach dem Compilieren 
daraus etwas wie "rjmp PC+0x0123" - was aufaddiert jedoch nicht FLASHEND 
ergibt.

Was kann ich tun? Ich habs erstmal behelfsmäßig über einen IJMP-Befehl 
gelöst, bei dem ich die FLASHEND-Adresse ins Z-Register schreibe. Da 
muss es aber doch noch einen "ordentlichen" Weg für geben, an eine 
absolute Adresse zu springen?!

Weiß jemand Rat?

Viele Grüße,
Steffen

von Bri (Gast)


Lesenswert?

Definier dir einen Funktionszeiger setzt den Wert des Funktionszeigers 
auf die feste Adresse und rufe dann die Funktion auf. Oder du schreibst 
einfach einen Assemblerbefehl. (mit dem asm statement)

von Steffen Hausinger (Gast)


Lesenswert?

Hallo Bri,

keine Ahnung, wie Funktionszeiger funktionieren, aber das werde ich dann 
mal ausprobieren. An anderer Stelle hätte ich sowas schonmal gebrauchen 
können, dann ist es jetzt wohl Zeit sich soetwas anzuschauen.

Per Assembler geht es leider nicht (bzw. nur per IJMP, siehe oben), weil 
auch dort beim Tiny45 mit dem "rjmp"-Befehl nur relative Sprünge 
unterstützt werden. Und das haut irgendwie nicht hin. Die Adresse, die 
mir vom Linker generiert wird, ist nicht die, die ich angegeben habe.

Danke für Deine Antwort!
Steffen

von Bri (Gast)


Lesenswert?

Also rein als Schuß ins blaue würde ich sagen, es könnte es so gehen:

void (* boot_loader) (); // Definition Variable als Funktionszeiger

boot_loader = 0xF000; // hier richtige Adress eintragen

boot_loader(); // und aufrufen



von Steffen Hausinger (Gast)


Lesenswert?

Hallo Bri,

das war nicht nur ins Blaue, es war ins Schwarze! Nur in der hinteren 
Klammer der Definition muss noch ein "void" stehen - das ist alles.

Übrigens wird aus dem Gebilde am Ende wieder ein "ICALL" mit der 
Sprungadresse im Z-Register. Kein "rjmp", obwohl der ja auch 4K 
adressieren kann (reicht beim Tiny45 aus) und durch das nicht notwendige 
Laden des Z-Registers zwei Befehle weniger benötigen würde.

Vielen Dank für Deine Hilfe!
Steffen

von Rolf Magnus (Gast)


Lesenswert?

Naja, ein Aufruf über einen Funktionszeiger wird zwangsweise zu einem 
icall. Der Compiler weiß ja nicht, daß er das in diesem speziellen Fall 
nicht braucht.
Es gibt bei gcc auch noch eine Erweiterung, die alternativ gehen könnte. 
Ich kann grad nicht ausprobieren, welcher Code rauskommt, aber du kannst 
es mal versuchen mit:
1
goto *0xf000;

  

von Peter D. (peda)


Lesenswert?

Ja, da ist ein schon sehr lange bekannter Bug bis AVR-GCC 3.4.6.

Ein RCALL wird fehlerhaft compiliert und bezieht sich auf die 
Startadresse des aktuellen Objektes, die logischer Weise ja nie 0x0000 
ist.

Damit ist jeder RCALL mit konstanter Adresse zum Scheitern verurteilt.


Beim AVR-GCC 4.1.1. hat man deshalb einen Work-Around gebastelt, indem 
auch konstante Calls mit einem ICALL gemacht werden.

Den RCALL wie bei Funktionsaufrufen vom Linker auflösen zu lassen, war 
wohl zu kompliziert.


Peter

von Jörg (Gast)


Lesenswert?

Ich komme etwas spät in diesen Thread...
In meinem Bootloader habe ich mehrere Methoden ausprobiert:
- Von der Applikation komme ich zurück in den Bootloader, indem ich 
einfach den Watchdog "kommen lasse", dafür reicht ein for(;;).
- Vom Bootloader in die Applikation geht am kompaktesten mit zwei "push 
r1" vor dem Funktionsende. Das ergibt eine "gefälschte" 
Rücksprungadresse von 0x0000, denn das Register r1 ist konstant Null.
- Mit Funktionszeiger geht auch, das ist aber etwas mehr Code. Bin sehr 
knapp dran...

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
Noch kein Account? Hier anmelden.