mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Bootloader und Interrupts


Autor: Guile Lampert (sphinx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo liebes Forum,
ich schreibe gerade einen Bootloader für meinen Roboter.
Die Software läuft auf einem ATmega2560.

Die Fuses habe ich auf:
- Boot Flash section size: 4096
- Boot Reset vector enabled
gesetzt.

Bei der Ausführung des Bootloaders tritt leider das folgende Problem 
auf:
Über USB (RS232) sende ich ein hex file an den uC, der Bootloader 
dekodiert das hex file und flasht den uC. Anschliessend schaltet der 
Bootloader die Interrupt Vektoren auf die Anwendung und startet die 
Anwendung jmp 0x0000.

Die Interrupt Vektoren werden mit den folgenden Befehlen umgesetzt:
MCUCR  = (1<<IVCE);  // Enable change of Interrupt Vectors
MCUCR  = (0<<IVSEL); // Move interrupts to Application

Der Disassembler im AVR Studio zeigt, dass das Programm korrekt ins 
Flash geschrieben wurde (vergleich des Assemblercodes an willkürlichen 
Stellen).

Es scheint so, als ob immer noch die Interruptvektortabelle des 
Bootloaders verwendet wird und nicht die der Applikation.

Hat jemand vieleicht ein ähnliches Problem oder einen Hinweis was ich 
falsch gemacht haben könnte?

Vielen Dank im voraus!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So
MCUCR  = (0<<IVSEL); // Move interrupts to Application

kann man nicht gezielt ein Bit löschen.

Eine 0 kannst du beliebige oft nach links schieben, es
bleibt immer noch eine 0.
Deine Schreibweise ist im Grunde nur eine verschleierte
Form für
MCUCR = 0;

und das wirst du wohl kaum so haben wollen.

Um 1 Bit gezielt auf 0 zu setzen:
MCUCR &= ~( 1 << IVSEL );

Autor: Guile Lampert (sphinx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Karl Heinz,
da war ich wohl mit Blindheit geschlagen! Vielen Dank!

Leider startet die Applikation immer noch nicht korrekt. Wie es scheint 
landet der uC immer noch in den Interrupttabellen des Bootloaders obwohl 
die Anwendung schon läuft!!!

Mein Code sieht jetzt so aus:
// Auf die Interrupttabelle der Applikation umschalten
// ===================================================
MCUCR  =  (1<<IVCE); // Enable change of Interrupt Vectors
MCUCR &= ~(1<<IVSEL); // Move interrupts to Application

// Die Applikation anspringen
// ==========================
((void (*)())0x0000)();


Autor: Jörg X. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich verstehe das Datasheet ("... Within four cycles, write the desired 
value to IVSEL while writing a zero to IVCE. ..." )so:
MCUCR  =  (1<<IVCE); // Enable change of Interrupt Vectors
MCUCR &= ~((1<<IVSEL)|(1<<IVCE)); // clear both bits
hth. Jörg

ps.: Der Beispielcode verwendet eine Temp-Variable, wahrscheinlich um 
das 4-Takt-Zeitfenster sicher einzuhalten.

Autor: Guile Lampert (sphinx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Jörg,
danke für den Hinweis! Ich habe den Code jetzt angepasst.
// Vorsichtshalber um 4 Takt Vorgabe einzuhalten
unsigned char moveApplication = ~((1<<IVSEL)|(1<<IVCE));
    
// Enable umschalten
MCUCR  =  (1<<IVCE);

// Interruptvektortabelle umschalten
MCUCR &= moveApplication;

// Applikation anspringen
void (*applicationPointer)( void ) = 0x0000;
applicationPointer();

Aus einem mir immer noch unerklärlichem Grund landet der uC jedoch immer 
wieder im Bootloader nach dem jmp 0x0000.

Eine Kleinigkeit habe ich wohl noch übersehen.

Autor: Guile Lampert (sphinx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also so wie es aussieht, führt der uC kurz nachdem er die Applikation 
anspringt einen erneuten reset durch und landet wieder im Bootloader.
Ist mir im Moment leider unerklärlich. Die Anwendung selbst habe ich 
bereits getestet. Die läuft einwandfrei.

Im assembler sieht das umschalten der Interruptvektortabellen so aus:

485:            unsigned char moveApplication = ~((1<<IVSEL)|(1<<IVCE));
+0001F425:   EF0C        LDI     R16,0xFC         Load immediate
+0001F426:   2E80        MOV     R8,R16           Copy register
487:            MCUCR  =  (1<<IVCE); // Enable change of Interrupt Vectors
+0001F427:   E001        LDI     R16,0x01         Load immediate
+0001F428:   BF05        OUT     0x35,R16         Out to I/O location
488:            MCUCR &= moveApplication;  // Move interrupts to Application
+0001F429:   B705        IN      R16,0x35         In from I/O location
+0001F42A:   2108        AND     R16,R8           Logical AND
+0001F42B:   BF05        OUT     0x35,R16         Out to I/O location
492:            void (*applicationPointer)( void ) = 0x0000;       // Set up function pointer to RESET vector
+0001F42C:   E000        LDI     R16,0x00         Load immediate
+0001F42D:   E010        LDI     R17,0x00         Load immediate
+0001F42E:   E020        LDI     R18,0x00         Load immediate
+0001F42F:   0128        MOVW    R4,R16           Copy register pair
+0001F430:   2E62        MOV     R6,R18           Copy register
493:            applicationPointer();
+0001F431:   01F2        MOVW    R30,R4           Copy register pair
+0001F432:   BE6C        OUT     0x3C,R6          Out to I/O location
+0001F433:   9519        EICALL                   Extended indirect call to (Z)
+0001F434:   CD54        RJMP    PC-0x02AB        Relative jump


Bei der IN Anweisung bin ich mir nicht ganz sicher aber ich denke, die 
benötigt auch nur einen Takt. Daher sollten beim Umschalten die 4 Takte 
eigentlich eingehalten werden.

Autor: TorstenS (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Jan,

ich habe ein ähnliches Phänomen beobachtet (sowohl mit ATmega168er als 
auch mit ATmega128) und hab's bisher so umgangen, dass ich im Bootloader 
keine Interrupts verwende. Dazu habe ich den Empfang von Zeichen über 
den UART auf Polling umgestellt.
Genauere Untersuchungen zur eigentlichen Ursache habe ich noch nicht 
angestellt.

Tschüss
Torsten

Autor: Guile Lampert (sphinx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Torsten,
dann bist Du schon der Zweite, der mir von diesem Phänomen berichtet.
Ich werde dann wohl oder übel auf Polling der RS232 Schnittstelle 
umstellen müssen.

Mittlerweile sitze ich hier schon seit zwei Tagen und versuche dieses 
Problem in den Griff zu bekommen.
Vieleicht weiss noch jemand wie man es umgeht?

Vielen Dank!
Gruss
Jan

Autor: Jörg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe einen Bootloader für Mega8 geschrieben der auch Interrupts 
verwendet. Da klappt das Umschalten. Die Interrupts sollten zu dem 
Zeitpunkt natürlich disabled sein, mit cli() ode so.

Von wegen landet wieder im Bootloader: Schlägt da vielleicht aus 
irgendwelchen Gründen der Watchdog zu?

Gibt es noch Fuses, die dabei eine Rolle spielen können?

Autor: Guile Lampert (sphinx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Jörg,
die Interrupts habe ich vorher disabled => cli(). Sorry habe wegen der 
Übersichtlichkeit nicht alles gepostet.

Bei den Fuses gibt es eine Option "Watchdog Timer always on" die habe 
ich aber ausgeschaltet.

Wenn ich die Applikation mit dem AVR Studio direkt auf den 2560 brenne, 
läuft sie ohne Probleme nur wenn ich mit dem Bootloader das Programm 
aufspiele, springt er zum Anfang des Bootloaders "0x1F000 so ca. nach 4 
Sekunden.

Merkwürdig...

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jan Raddatz wrote:

> Wenn ich die Applikation mit dem AVR Studio direkt auf den 2560 brenne,
> läuft sie ohne Probleme nur wenn ich mit dem Bootloader das Programm
> aufspiele, springt er zum Anfang des Bootloaders "0x1F000 so ca. nach 4
> Sekunden.

Nun, daß hat aber nichts mit der Interruptvektortabelle zu tun.

Da ist irgendwas faul in Deinem Programm und es rennt irgendwann hinten 
über auf 0x0000.
Und ohne den Bootloader hinten dran merkst Du das bloß nicht.


Peter

Autor: Guile Lampert (sphinx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hmm ich geb's ja ungern zu aber mir scheint, dass Du recht hast.
Die Interrupts werden jetzt schonmal richtig angesprungen! Immerhin!

Es scheint aber noch ein Problem bei der Initialisierung der Anwendung 
zu geben. Mal gucken!

Autor: subitus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Auch wenn der Beitrag schon ein wenig älter ist:
Für die Forumleser, die auf ein ähnliches Phänomen stoßen wie Guile 
Lampert (sphinx): Dieses Problem tritt immer dann auf, wenn Interrupts 
verwendet werden, deren Sprungadressen jedoch nicht definiert sind. 
Generell gilt: Stets alle ISR definieren - andernfalls springt der IRQ 
im Wald umher.

Gruß,
AnnoDazumaL

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.