Hallo zusammen. Ich habe ein Problem mit meinem ATMega1284: Ich versuche einen Bootloader zu schreiben, der Daten per I2C entgegen nimmt. Das Programm ist zur Hälfte fertig - Ich kann Daten per I2C senden und empfangen. Nun möchte ich aber das Programm in die entsprechende Bootloadersektion 0xF000 schreiben. Ich habe die BOOTRST Fuse gesetzt, und anschließend in der Linker GUI die Sektion .text=0xF000 definiert, woraufhin das Studio einen Linkeraufruf mit .text=0x1E000 erzeugt. Wenn ich nun dieses Programm flashe, funktioniert aber leider nichts. Beim Laden per JTAG springt er im Assembler an Adresse 0xF306. Es sieht aber so aus, als ob das Programm an die Stelle 0xF000 geschrieben worden wäre. Habe ich noch irgendwas vergessen? Hat jemand schon selbst einen Bootloader in AVR Studio 6 erstellt? Gruß, Dirk
Das sieht etwas nach dem byte-word Problem bei den AVRs aus. 0xF000 sieht nach einem 8kB Bootloader aus, damit liegt der Bootloader bei 0x1E000, soweit ich weiß braucht der Linker immer die Adressen im byte Format und nicht Word Format, damit musst du im Linker die text sction auf 0x1E000 legen. Wenn du interrupts verwendest musst du diese auch an den Bootloader anpassen. Es kann auch ganz hilfreich sein sich das Hexfile mal mit einem anderen Tool anzuschauen, um herauszufinden wo der Code nun wirklich liegt, ich verwende dazu immer das Segger J-Flash Tool.
Ich habe die Ursache gefunden: Das Problem lag am MCUCR: Der Code
1 | temp = MCUCR; |
2 | MCUCR = temp | (1<<IVCE); |
3 | MCUCR = temp | (1<<IVSEL); |
funktioniert bei mir nie (Weder im AVRSim, noch auf der HW). Auf höchster Otimierungsstufe scheint er die geforderten 4 Takte nicht einhalten zu können.
1 | MCUCR = (1<<IVCE); |
2 | MCUCR = (1<<IVSEL); |
Funktioniert dagegen ab Compilerstufe 1!!! Damit funktionieren nun endlich die Interruptroutinen...
Ich bekomme es mit -Os problemlos hin:
1 | .global setivsel |
2 | .type setivsel, @function |
3 | setivsel: |
4 | /* prologue: function */ |
5 | /* frame size = 0 */ |
6 | /* stack size = 0 */ |
7 | .L__stack_usage = 0 |
8 | in r24,0x35 |
9 | mov r25,r24 |
10 | ori r25,lo8(1) |
11 | out 0x35,r25 |
12 | ori r24,lo8(2) |
13 | out 0x35,r24 |
14 | ret |
Das ORI zwischen den beiden OUT-Befehlen dauert ja nur einen Takt, damit sollte die 4-Takte-Bedingung noch erfüllt sein. Allerdings gibt es keinen wirklich Grund für diese Veroderung.
Ihhh, Assembler :-) Mein Code sieht nun wie folgt aus:
1 | static void move_interrupt_vector(enum section section_to_use) |
2 | {
|
3 | uint8_t mcucr_write[2]; |
4 | uint8_t current_state = MCUCR; |
5 | |
6 | switch ( section_to_use ) |
7 | {
|
8 | case APPLICATION: |
9 | mcucr_write[0] = current_state | (1<<IVCE); //Enable access |
10 | mcucr_write[1] = current_state & ~(1<<IVSEL); //Set interrupt vector to address 0x0 |
11 | break; |
12 | case BOOTLOADER: |
13 | mcucr_write[0] = current_state | (1<<IVCE); //Enable access |
14 | mcucr_write[1] = current_state | (1<<IVSEL); //Set interrupt vector to address 0xF000 |
15 | break; |
16 | default:
|
17 | // do nothing
|
18 | break; |
19 | }
|
20 | MCUCR = mcucr_write[0]; |
21 | MCUCR = mcucr_write[1]; |
22 | }
|
Das Ganze funktioniert sowohl mit -Os, -O1, -O2 und -O3 (laut AVRSim). Nur halt -O0 geht nicht...
Dirk Hölscher schrieb: > Nur halt -O0 geht nicht... Ohne Optimierung wird der Index von mcucr_write zur Laufzeit ausgewertet, das dauert halt länger als 4 Zyklen. Allerdings ist die Verwendung eines Arrays an dieser Stelle völlig überflüssig, vor allem, da der erste Wert für beide Fälle eh immer gleich ist. KISS - keep is simple and stupid Oliver
Dirk Hölscher schrieb: > Ihhh, Assembler :-) Das ist der vom Compiler generierte Assemblercode. Ich versteh' dein Gewürge mit dem Rücklesen des existierenden MCUCR nicht. Das Teil hat nach einem Reset einen wohl definierten Wert (nämlich 0), da kannst du doch einfach drauf schreiben, statt solche Verrenkungen zu machen.
Oliver schrieb: > Ohne Optimierung wird der Index von mcucr_write zur Laufzeit > ausgewertet, das dauert halt länger als 4 Zyklen. Nachtrag: Zumindest der gcc 4.3.3, den ich hier auf dem Rechner habe, erzeugt ohne Optimierung auch ohne Array solch umständlichen Code, der schafft die 4 Zyklen ohne Optimierung auch ohne Array nicht. Oliver
Jörg Wunsch schrieb: > Ich versteh' dein Gewürge mit dem Rücklesen des existierenden MCUCR > nicht. Das Teil hat nach einem Reset einen wohl definierten Wert > (nämlich 0), da kannst du doch einfach drauf schreiben, statt solche > Verrenkungen zu machen. Stimmt schon. Ich komme halt aus einer großen Softwareschmiede, und da ist es fatal einfach Andererleuts Register zu überschreiben. Also lieber chirurgisch nur die Bits anpassen, die ich brauche... Geschmackssache... Mir ging es aber hauptsächlich um folgende Aussage:
1 | --- Bootloader.c -------------------------- |
2 | MCUCR = (1<<IVCE); |
3 | 0000F084 LDI R24,0x55 Load immediate |
4 | 0000F085 LDI R25,0x00 Load immediate |
5 | 0000F086 LDI R18,0x01 Load immediate |
6 | 0000F087 MOVW R30,R24 Copy register pair |
7 | 0000F088 STD Z+0,R18 Store indirect with displacement |
8 | MCUCR = (1<<IVSEL); |
9 | 0000F089 LDI R24,0x55 Load immediate |
10 | 0000F08A LDI R25,0x00 Load immediate |
11 | 0000F08B LDI R18,0x02 Load immediate |
12 | 0000F08C MOVW R30,R24 Copy register pair |
13 | 0000F08D STD Z+0,R18 Store indirect with displacement |
Danke für den Hinweis mit dem Dissassembler. Das ist der Code, den der Compiler bei -O0 aus den beiden MCUCR = Anweisungen macht. Wie man sieht, werden daraus pro Aufruf je 5 Anweisungen, was das Nicht-Funktionieren erklärt. Kann es sein, dass er garnicht auf das MCUCR Register 0x35 zugreift? Ich kenne mich in Assembler leider nur sehr schlecht aus...
Dirk H. schrieb: > Kann es sein, dass er garnicht auf das MCUCR Register 0x35 zugreift? Ich > kenne mich in Assembler leider nur sehr schlecht aus... Doch, tut er. Nur hat das Register beim Zugriff per ld die Adresse 0x55. Der Optimierer nutzt dann den out-Befehl, damit heisst das Register dann 0x35. Datenblatt lesen bildet. Oliver
Dirk H. schrieb: > Ich komme halt aus einer großen Softwareschmiede, und da > ist es fatal einfach Andererleuts Register zu überschreiben. Du bist aber hier bei Mikrocontrollern, und bei denen ist oft genug Effektivität wichtiger als stures Befolgen nicht immer sinnvoller Richtlinien. Aktionen wie das Einrichten der Vektortabelle gehören ohnehin mit zu den ersten Dingen, die man nach einem Reset erledigt, insofern ist es völlig legitim, dass sie vom Resetzustand des Controllers ausgehen. > Das ist der Code, den der Compiler bei -O0 aus den beiden MCUCR = > Anweisungen macht. Ja, -O0 eben. Das will man nicht benutzen, nicht freiwillig. Ist wie einen Porsche zu fahren, aber die Handbremse angezogen zu lassen. Jede Ente fährt dann schneller los.
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.