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
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)
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
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
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
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; |
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.