Funktionsaufruf an fester Adresse

Gast #411592
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
Gast #411595
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
Gast #411597
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/doc2537.pdf
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?
#411600
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
Gast #411601
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.
1
/* external for Bootloader --------------------- */
2

3
typedef void (*pFn)(void);
4
const pFn Bootloader = (pFn)0x1234;
5
.....
6

7
if (rcvBuffer[0] == 'B')
8
   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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren