Forum: Mikrocontroller und Digitale Elektronik AtmegaXXM1 Bootloader - komme nicht rein.


von Atmega (Gast)


Lesenswert?

Hallo,

ich will einen Bootloader auf einen Atmega64M1 schreiben.

Fuse Bits habe ich folgende gesetzt:

Ext: 0xFF
High: 0xD0
Low: 0xFF

Nun will ich Interrupts im Bootloader nutzen. Meine Main sieht 
folgenermaßen aus:
1
int main(void) {
2
// Interrupt Vektoren auf Bootsektion wie im Datenblatt beschrieben
3
MCUCR = (1 << IVCE);
4
MCUCR = (1 << IVSEL);
5
6
7
// Init ...
8
9
10
sei();
11
12
while(1)  {
13
...
14
15
}
16
17
}

Flashe ich nun den MCU und versuche ihn anzusprechen, kommt nichts 
zurück. Klammer ich

MCUCR = (1 << IVCE);
MCUCR = (1 << IVSEL);

aus, reagiert er ganz normal. Dh. er ist nicht in der Bootloader Sektion 
wie eigentlich mit den Fuse Bits eingestellt.

Was mache ich falsch? Habe ich etwas vergessen?

Schöne Grüße

von Atmega (Gast)


Lesenswert?

Nachtrag:

Eine LED blinken lassen funktioniert.

Das CAN Init läuft auch durch.

Will ich eine CAN Nachricht senden, hängt er fest und es geht nichts 
weiter.
Sende ich eine Nachricht zum MCU, springt er nicht in die CAN Interrupt 
Routine, bleibt aber auch nicht hängen. Die LED in der Main blinkt 
einfach weiter.

Es scheint also an CAN zu hängen... Jemand eine Idee?

von da1l6 (Gast)


Lesenswert?

Hallo

Du kannst IVSEL nicht so einfach schreiben. Das wird ignoriert.

Aus dem XMega AU Datenblatt:
> IVSEL: Interrupt Vector Select
[...]
> This bit is protected by the configuration change protection mechanism.
> Refer to “Configuration Change Protection” on page 13 for details.

da1l6

von Atmega (Gast)


Lesenswert?

Ich glaube du meinst einen anderen MCU?!

Ich nutze den Atmega64M1 <- Das ist ein MCU mit CAN Controller wie der 
AT90CAN


Auf S. 54 im Datenblatt steht:

"The IVCE bit must be written to logic one to enable change of the IVSEL 
bit. IVCE is cleared by hardware four
cycles after it is written or when IVSEL is written. Setting the IVCE 
bit will disable interrupts, as explained in the
IVSEL description above. See the code example below."

Mit dem oben genannten Code als Beispiel.
1
void Move_interrupts(void)
2
{
3
/* Enable change of Interrupt Vectors */
4
MCUCR = (1<<IVCE);
5
/* Move interrupts to Boot Flash section */
6
MCUCR = (1<<IVSEL);
7
}

von Atmega (Gast)


Lesenswert?

2 Nachtrag:

Wenn ich versuche eine Nachricht zu senden, bleibt er hängen, wenn ich 
mit einer while schleife prüfe ob TXOK gesetzt ist. Ersetze ich das 
warten durch ein delay, wird die Nachricht versendet.


Die ISR wird aber leider weiterhin nicht aufgerufen...

von Michael R. (mr-action)


Lesenswert?

Schreibst du deinen Bootloader denn auch an die Richtige Stelle im 
Flash? Wenn du den auf 0x00 schreibst und dann die Interrupts 
verstellst, klappt das selbstverständlich nicht... ;-)

Davon ab, gibt es meine ich ein spezielles Makro um die Interrupts 
umzustellen, damit das auch wirklich den den 4 Takten passiert.

von Atmega (Gast)


Lesenswert?

Michael R. schrieb:
> Schreibst du deinen Bootloader denn auch an die Richtige Stelle im
> Flash? Wenn du den auf 0x00 schreibst und dann die Interrupts
> verstellst, klappt das selbstverständlich nicht... ;-)

Ehm ok, jetzt wirds doof. Ich dachte man setzt das mit den Fuse so, dass 
der ISP Programmer den Bootloader direkt an die korrekte Stelle schreibt 
... Kann auch nix anderes finden...


> Davon ab, gibt es meine ich ein spezielles Makro um die Interrupts
> umzustellen, damit das auch wirklich den den 4 Takten passiert.

Gefunden habe ich das hier:
1
uint8_t regCE = MCUCR & ~((1 << IVCE) | (1 << IVSEL));
2
uint8_t regSEL = MCUCR & ~((1 << IVCE) | (1 << IVSEL));
3
regCE  |= (1 << IVCE);
4
regSEL |= (1 << IVSEL);
5
MCUCR = regCE;
6
MCUCR = regSEL;

Klappt aber leider auch nicht.

Und hier auf mikrocontroller.net im "AVR Bootloader in C - Eine ..." 
wird folgendes verwendet:
1
/* Interrupt Vektoren verbiegen */
2
temp = MCUCR;
3
MCUCR = temp | (1<<IVCE);
4
MCUCR = temp | (1<<IVSEL);

Was leider auch nicht funktioniert...

von Michael R. (mr-action)


Lesenswert?

Na, gab wohl doch keins... Also ich machs über diesen Code schnipsel:
1
  /* Interrupt Vektoren verbiegen */
2
  char sregtemp = SREG;
3
  cli();
4
  uint8_t temp = MCUCR;
5
  MCUCR = temp | (1<<IVCE);
6
  MCUCR = temp | (1<<IVSEL);
7
  SREG = sregtemp;

Und im AtmelStudio hab ich in den Projekteinstellungen unter Toolchain 
-> "AVR/GNU Linker" -> Memory Settings -> FLASH segment: .text=0xF000

Die Adresse müssteste natürlich für deinen µC anpassen... Mein 
Bootloader ist vom AT90CAN128

von Atmega (Gast)


Lesenswert?

Michael R. schrieb:
> Und im AtmelStudio hab ich in den Projekteinstellungen unter Toolchain
> -> "AVR/GNU Linker" -> Memory Settings -> FLASH segment: .text=0xF000

Das scheint zu funktionieren. Der Bootloader des Atmega64M1 beginnt bei 
0x7000 wenn man 4096 Words verwendet.

daher habe ich ".text=0x7000" in Flash segment eingetragen.

Nun klappt
1
uint8_t temp = MCUCR;
2
MCUCR = temp | (1<<IVCE);
3
MCUCR = temp | (1<<IVSEL);

Aber: Ich lasse im Hauptprogramm eine LED jede Sekunde blinken um zu 
gucken, wo ich gerade bin.

Wenn ich nun aber aus dem Bootloader ins Hauptprogramm springen will 
mit:
1
((void (*)())0)();
oder
1
void (*start)( void ) = 0x0000;
2
3
start();

oder aber
1
// relocate
2
uint8_t reg = MCUCR & ~((1 << IVCE) | (1 << IVSEL));
3
  
4
MCUCR = reg | (1 << IVCE);
5
MCUCR = reg;
6
  
7
#if FLASHEND > 0xffff
8
__asm__ __volatile__(
9
"push __zero_reg__" "\n\t"
10
"push __zero_reg__" "\n\t"
11
"push __zero_reg__" "\n\t");
12
#else
13
__asm__ __volatile__(
14
"push __zero_reg__" "\n\t"
15
"push __zero_reg__" "\n\t");
16
#endif


Und KEINE Applikation in den Flash bei 0x0000 schreiben lasse kommt 
wieder der Bootloader. Liegt das daran, dass er zu 0x0000 springt und 
dann da nichts findet und dann weiter guckt bis er wieder beim 
Bootloader ist? Oder klappts einfach nicht?

von Michael R. (mr-action)


Lesenswert?

Jap, wenn dein flash sonst leer ist, landest du wieder im bootloader...

von Atmega (Gast)


Lesenswert?

OK, das is schonmal sehr gut :)

Danke für deine Hilfe!

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
Noch kein Account? Hier anmelden.