Forum: Compiler & IDEs AVR Studio 6 und Bootloader


von Dirk H. (xplod)


Lesenswert?

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

von Thomas (Gast)


Lesenswert?

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.

von Dirk H. (xplod)


Lesenswert?

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...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von Dirk H. (xplod)


Lesenswert?

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...

von Oliver (Gast)


Lesenswert?

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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von Oliver (Gast)


Lesenswert?

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

von Dirk H. (xplod)


Lesenswert?

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...

von Oliver (Gast)


Lesenswert?

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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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