mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik AVR Bootloader: Sprung zur Applikation


Autor: Jan Krause (jeangonzales)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich möchte von meinem Bootloader nach erfolgtem Flashen in die Anwendung 
springen. Das Problem ist aber, dass das nicht so recht funktioniert. 
Ich arbeite wie in der Application Note von Atmel gezeigt mit einem 
Funktionszeiger auf die Adresse 0x0000. Vorher werden noch die 
Interrupts wieder auf den Applikationsbereich umgebogen:
void (*jump_to_main_application)( void ) = 0x0000;

void main()
{

  ...
  uint8_t temp;
  cli();
  
  // Get MCUCR
  temp = MCUCR;

  // Enable change of Interrupt Vectors
  MCUCR = (temp | (1<<IVCE));
  
  // Move interrupts to App Flash section 
  MCUCR = (temp & ~(1<<IVSEL));
  
  jump_to_main_application();

}

Wenn der Code ausgeführt wird, springt der AVR aber immer wieder in den 
Bootloader, der dann in einer Endlosschleife immer wieder ausgeführt 
wird. Hier noch Ausschnitte aus den lss und lst Dateien (bin leider des 
Assemblers noch nicht so recht mächtig, um die Sprungadresse zu deuten):
                        jump_to_main_application();
   3e4e2:  e0 91 06 02   lds  r30, 0x0206
   3e4e6:  f0 91 07 02   lds  r31, 0x0207
   3e4ea:  19 95         eicall
   3e4ec:  a6 cf         rjmp  .-180      ; 0x3e43a <main+0x102>


1411 03d0 E091 0000     lds r30,jump_to_main_application
1412 03d4 F091 0000     lds r31,(jump_to_main_application)+1
1413 03d8 1995          eicall
1414 03da 00C0          rjmp .L144

1430                 .global  jump_to_main_application
1431                 .global  jump_to_main_application
1434                 jump_to_main_application:
1435 0006 0000          .skip 2,0


Irgend eine Idee, was verkehrt läuft?
Die Anwendung, die geflasht wurde, funktioniert. Wenn ich die Fuse 
BOOTRST lösche, wird die vom Bootloader geflashte Anwendung korrekt 
ausgeführt).

Grüße, Jan

Autor: Klugscheisser (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Im wesentlichen gibt es zwei mögliche Ursachen.

1. Die Applikation wird zwar korrekt angesprungen, aber dort wird sofort 
wieder in den Bootloader gesprungen. Das ist auf nicht ganz 
durchprogrammierte Erkennung der Bedingung für das gewollte springen in 
den Bootloader zurückzuführen.

2. Ich bin mir nicht sicher, aber ich würde mal schauen wie der 
Assemblercode für den Teil:
  // Get MCUCR
  temp = MCUCR;

  // Enable change of Interrupt Vectors
  MCUCR = (temp | (1<<IVCE));
  
  // Move interrupts to App Flash section 
  MCUCR = (temp & ~(1<<IVSEL));


aussieht. Lt. Datenblatt dürfen max. 4 Zyklen zwischen dem setzen von 
IVCE und IVSEL liegen. Die Ausdrücke sehen wegen dem laden von temp 
etwas länglich aus, aber es könnte trotzdem OK sein. Dennoch würde ich 
mal nachschauen.

Falls Dir das noch ein wenig zu hoch ist, würde ich vorsichtshalber
  // Enable change of Interrupt Vectors
  MCUCR |= (1<<IVCE));
  
  // Move interrupts to App Flash section 
  MCUCR &= ~(1<<IVSEL);

stattdessen schreiben.

Autor: tom (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Jan,

Mach mal so:

// pointer NUR deklarieren
static void (*pApplic) (void);


int main (void)
{

// dein code...

    // pointer HIER initialisieren
    pApplic = (void *) 0x0000; // app reset vector

    pApplic();
}


... dann sollte es tun.
wahrscheinlich hast Du einen mega128 o.ä. und benutzt gcc ?
Dann wird wohl die Initialisierung Deiner automatischen Variablen nicht 
funzen wg. der Lokierung oberhalb der 64k-Grenze.

Gutt Lack, tom.

Autor: Jan Krause (jeangonzales)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Tom,

Ja, ich verwende unter anderem einen Mega2561 und kompiliere mit 
avr-gcc.

verstehe zwar nicht, was du mit "Lokierung oberhalb 64k-Grenze" meinst", 
aber ich werde es heute abend mal ausprobieren!

Die Tipps aus dem Beitrag hier: 
Beitrag "Re: Sprung von Bootloader nach Hauptprogramm"

kann ich jedenfalls nicht mal kompilieren.

*Jan

Autor: Jan Krause (jeangonzales)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klugscheisser wrote:
> Im wesentlichen gibt es zwei mögliche Ursachen.
>
> 1. Die Applikation wird zwar korrekt angesprungen, aber dort wird sofort
> wieder in den Bootloader gesprungen. Das ist auf nicht ganz
> durchprogrammierte Erkennung der Bedingung für das gewollte springen in
> den Bootloader zurückzuführen.

Wer soll denn was wo prüfen?
Wenn der Sprung funktionert, also der IP auf Adresse 0 gesetzt wird, 
sollte die Initialisierung wie nach einem normalen Reset stattfinden.



> aussieht. Lt. Datenblatt dürfen max. 4 Zyklen zwischen dem setzen von
> IVCE und IVSEL liegen. Die Ausdrücke sehen wegen dem laden von temp
> etwas länglich aus, aber es könnte trotzdem OK sein. Dennoch würde ich
> mal nachschauen.

Ist kein Problem. Derselbe Code funktioniert ja auch im Bootloader (nur 
dass die Vektoren dann auf den Bootloderbereich umgelegt werden) 
wunderbar. Ausserdem stammt der 1:1 aus der AN von Atmel.

Ich denke eher, der Tipp von Tom wird mich zum Erfolg führen :)

Autor: Jan Krause (jeangonzales)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So, jetzt bin ich wieder etwas schlauer. Der Hinweis mit der 64k-WORD 
Grenze hat mich letztlich auf den richtigen Weg gebracht:

Der GCC hat ja den Aufruf des NULL-Funktionszeigers mit einer 
EICALL-Instruktion übersetzt (An den Adressen 0x0237 und 0x0238 steht 
der NULL-Pointer:
                       jump_to_main_application();
   3e574:  e0 91 37 02   lds  r30, 0x0237
   3e578:  f0 91 38 02   lds  r31, 0x0238
   3e57c:  19 95         eicall
<main+0x184>

Aber er hat "vergessen", das EIND Register auf 0 zu setzen. Das 
erweitert ja die Adresse im Z-Register um ein weiteres Byte, wenn der 
Adressraum größer als 64k ist (wie bei meinem ATMega2561 der Fall).

Jetzt habe ich den Teil von Hand in Assembler kodiert:
asm volatile (
    "ldi r24, 0"  "\n\t"
    "out 0x3C, r24"  "\n\t"
    "ldi r30, 0x00"  "\n\t"
    "ldi r31, 0x00"  "\n\t"
    "eicall"
);

Und siehe da, es funktionert!
Dabei geholfen hat dieser Thread auf der avr-gcc mailinglist: 
http://www.mail-archive.com/avr-gcc-list@nongnu.or...

Autor: tom (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Jan,

na prima, das es bei Dir jetzt funzt.
Du kannst aber auch einfach ein 'call 0x00000' benutzen für den Sprung 
auf den Reset-vector der applikation. Sollte auch tun.
Vice versa geht das so natürlich dann auch mit dem springen von 
applikation in den bootloader, da sollte dann natürlich die adresse des 
BTL-reset vectors drin stehen.

#define pApplic()     _asm__ __volatile_ ("call 0x00000")


void foo(void)
{

    pApplic();

}

Na denn, ciao + frohes werkeln.

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.