mikrocontroller.net

Forum: Compiler & IDEs Funktionsaufruf an fester Adresse


Autor: Axel Barkow (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich möchte aus meiner Software für einen Mega88 eine Funktion an einer
festen Adresse im Bootloaderbereich anspringen, die nicht Teil meiner
Software ist. Ich habe das über einen Funktionszeiger versucht, jedoch
bringt das nicht den gewünschten Erfolg.

void (*jump_to_bootloader)( void ) = BOOTLDRSTART;
//Aufruf über jump_to_bootloader()

Nach langem Probieren habe ich eine Lösung gefunden, indem ich eine
Dummy-Funktion an diese fixe Adresse gebunden habe und den für diese
Funktion entstehenden Code nicht ins Flash übertrage.

void jump_to_bootloader(void) _attribute_ ((section
(".bootldrstart")));
void jump_to_bootloader(void)
{
  asm("nop");
}
//Aufruf über jump_to_bootloader()


Diese Lösung finde ich nur etwas unschön. Hat jemad einen besseren
Vorschlag oder eine Lösung für das Funktionszeigerproblem?

Gruß,

Axel

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie ist dein BOOTLDRSTART definiert?

Ist das vielleicht eine Datenadresse im ROM von der der Bootlader erst
an eine eigentliche Ablaufadresse geladen wird?

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du machst ne Zuweisung und keinen Funktionsaufruf.

Die Syntax für nen Funktionsaufruf sieht z.B. so aus:
#define CALL(addr)      (((void(*)(void))(char *)addr)())
...
CALL( 0xFFF0 );               // API call


Peter

Autor: Axel Barkow (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Stefan
BOOTLDRSTART ist eine Konstante (0x1e2a).

@Peter
Die Zuweisung ist nur die Initialisierung einer globalen Variablen. Der
eigentliche Aufruf im Programm erfolgt über

...
msg.data[0] = 0x02;
can_send_message(&msg);
//jump_to_bootloader at 0x1e2a;
jump_to_bootloader();
...

Werde dein Makro aber auch noch einmal testen.

@all
Der Assembler-Code, der bei beiden Varianten entsteht, ist auch
unterschiedlich.

Die Dummy-Funktion erzeugt folgendes:
        msg.data[0] = 0x02;
 b4e:  82 e0         ldi  r24, 0x02  ; 2
 b50:  8a 87         std  Y+10, r24  ; 0x0a
        can_send_message(&msg);
 b52:  ce 01         movw  r24, r28
 b54:  01 96         adiw  r24, 0x01  ; 1
 b56:  67 dc         rcall  .-1842     ; 0x426

        //jump_to_bootloader = 0x1e2a;
        jump_to_bootloader();
 b58:  78 d9         rcall  .-3344     ; 0xfffffe4a

Der Funktionszeiger folgendes:

        msg.data[0] = 0x02;
 b4e:  82 e0         ldi  r24, 0x02  ; 2
 b50:  8a 87         std  Y+10, r24  ; 0x0a
        can_send_message(&msg);
 b52:  ce 01         movw  r24, r28
 b54:  01 96         adiw  r24, 0x01  ; 1
 b56:  67 dc         rcall  .-1842     ; 0x426
        //jump_to_bootloader = 0x1e2a;
        jump_to_bootloader();
 b58:  e0 91 00 01   lds  r30, 0x0100
 b5c:  f0 91 01 01   lds  r31, 0x0101
 b60:  09 95         icall

Den Aufruf über icall hatte ich auch schon über inline-Assembler
probiert, hat aber auch nicht funktioniert. Ich hatte das Z-Register
allerdings direkt mit ldi beschrieben.

Gruß,

Axel

Autor: Axel Barkow (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Stefan
BOOTLDRSTART ist natürlich 0x1e4a, ich hatte da nur einige Kommentare
noch nicht aktualisiert

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So verkehrt ist die erste Variante nicht bis auf die Tatsache, dass
0x1e4a von 0x0b58 aus nicht erreichbar ist. Wieso?

In
http://www.atmel.com/dyn/resources/prod_documents/...
liest man, dass rcall nur 2K words in either direction (= +- 0x1000)
adressieren kann. Möglicherweise ist das bei dem AtMega88 auch so.

Es gibt eine ähnliche Diskussion darüber:
http://www.mikrocontroller.net/forum/read-2-240145.html

Ich vermute der Compiler ist einmal zu schlau, sieht dass sich der
Funktionspointer nicht ändert und setzt direkt den zugewiesenen Wert
ein. Dafür ist er dann aber zu blöd und weiss nix von der 2K Grenze.

Welche Compilerversion benutzt du?

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ähm - Habe ich jetzt Quatsch geschrieben oder sind die Beispiele
gedreht? Muss mir mal selbst einen kompletten C-Code zusammenbasteln
und schauen, was jeweils rauskommt. Melde mich wieder...

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich denke die Adresse ist fest ?

Dann kostet der Umweg über ne globale Variable nur unnötig Flash und
SRAM.


Ältere WINAVR-Versionen hatten nen Bug bei RCALL/RJMP, die haben dann
relativ zum Modul gesprungen.
Z.B. ein Call nach 0x0000 für zur Startadresse des Moduls und nicht zum
Resetvektor.


Peter

Autor: Axel Barkow (abarkow)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ein avr-gcc -dumpversion ergibt 3.4.6, installiert ist WinAVR 20060421

@Peter
Gut, die globale Variable kostet zwar Speicher, trotzdem sollte der
Aufruf funktionieren. Die Adresse ist im Prinzip fix, ich halte mir so
aber die Möglichkeit offen, diese Adresse von extern zu beeinflussen.

@Stefan
Ja, die Beispiele sind gedreht, sorry. Also der rcall funktioniert, der
icall nicht. Wobei ich das so nicht verstehe.

Gruß,

Axel

Autor: JojoS (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich probiere z.Zt. das gleiche, im Elektronik Forum gibt es einen
ähnlichen Thread. Da ich das auch mit dem gcc realisieren möchte passt
es hier aber besser.
/* external for Bootloader --------------------- */

typedef void (*pFn)(void);
const pFn Bootloader = (pFn)0x1234;
.....

if (rcvBuffer[0] == 'B')
   Bootloader();      // exit to Bootloader

Der Bootloader Aufruf ist natürlich kein echter Call sondern ein
Never-come-back Jump, der Bootloader macht einen Reset nach dem
Blitzdingsen, damit nicht wieder die alte Diskussion losgeht... Im AVR
Studio habe ich das durchgesteppt, der Call springt an die 0x1234.
Unschön ist nur das die Bootloader adresse absolut angegeben wird. Ich
hätte hier lieber ein external und die Adresse vom Linker aufgelöst,
aber das habe ich nicht hinbekommen (kann der Linker eine .sym Datei
nutzen?).
Als Bootloader benutze ich den von P.Fleury, steht hier auch in der
Codesammlung. Der muss noch etwas umsortiert werden damit der
'Warmstart' auch die nötigen Initialisierungen macht.

Autor: JojoS (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nachtrag: ich hatte auch probiert den Pointer mit dem Attribut PROGMEM
zu versehen und in den Codespeicher zu legen, aber dann klappt der
Bootloader() call nicht weil der Compiler trotzdem LDS statt LPM
Befehle erzeugt.

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.