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
Wie ist dein BOOTLDRSTART definiert? Ist das vielleicht eine Datenadresse im ROM von der der Bootlader erst an eine eigentliche Ablaufadresse geladen wird?
Du machst ne Zuweisung und keinen Funktionsaufruf. Die Syntax für nen Funktionsaufruf sieht z.B. so aus:
1 | #define CALL(addr) (((void(*)(void))(char *)addr)())
|
2 | ...
|
3 | CALL( 0xFFF0 ); // API call |
Peter
@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
@Stefan BOOTLDRSTART ist natürlich 0x1e4a, ich hatte da nur einige Kommentare noch nicht aktualisiert
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?
Ä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...
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
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
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.
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.
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.