mikrocontroller.net

Forum: Compiler & IDEs WinAVR - Sprung zu absoluter Adresse


Autor: Steffen Hausinger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Bri (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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)

Autor: Steffen Hausinger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Bri (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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



Autor: Steffen Hausinger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
goto *0xf000;

  

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Jörg (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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...

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.