Forum: Mikrocontroller und Digitale Elektronik ATmega168 Bootloader


von Jürgen (Gast)


Lesenswert?

Hallo,

ich versuche gerade, diesen Bootloader

http://www.mikrocontroller.net/articles/AVR_Bootloader_in_C_-_eine_einfache_Anleitung

auf meinem ATmega168 zum Laufen zu bringen.
Ich hänge allerdings schon am "Hallo Welt" - Bootloader fest. Dieser 
funktioniert zwar einigermaßen, wenn ich ihn an Adresse 0x0000 schreibe, 
aber wenn ich ihn an die Bootloader-Adresse 0x3800(mithilfe der 
Linker-Option     -Ttext=0x3800) schreibe, passiert nichts.
Hier nochmal der Code:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <avr/boot.h>
4
#include <util/delay.h>
5
#include "uart.h"
6
 #ifndef F_CPU
7
#define F_CPU 20000000UL
8
#endif
9
#define BOOT_UART_BAUD_RATE     9600     /* Baudrate */
10
#define XON                     17       /* XON Zeichen */
11
#define XOFF                    19       /* XOFF Zeichen */
12
 
13
int main()
14
{
15
    unsigned int   c=0;               /* Empfangenes Zeichen + Statuscode */
16
    unsigned char  temp,              /* Variable */
17
                        flag=1,            /* Flag zum steuern der Endlosschleife */
18
      p_mode=0;     /* Flag zum steuern des Programmiermodus */
19
    void (*start)( void ) = 0x0000;        /* Funktionspointer auf 0x0000 */
20
 
21
    /* Interrupt Vektoren verbiegen */
22
 
23
    char sregtemp = SREG;
24
    cli();
25
    temp = MCUCR;
26
    MCUCR = temp | (1<<IVCE);
27
    MCUCR = temp | (1<<IVSEL);
28
    SREG = sregtemp;
29
 
30
    /* Einstellen der Baudrate und aktivieren der Interrupts */
31
    uart_init( UART_BAUD_SELECT(BOOT_UART_BAUD_RATE,F_CPU) ); 
32
    sei();
33
 
34
    uart_puts("Hallo hier ist der Bootloader\n\r");
35
    _delay_ms(1000);
36
 
37
    do
38
    {
39
        c = uart_getc();
40
        if( !(c & UART_NO_DATA) )
41
        {
42
            switch((unsigned char)c)
43
            {
44
                 case 'q': 
45
         flag=0;
46
                     uart_puts("Verlasse den Bootloader!\n\r");
47
                     break;
48
                  default:
49
                     uart_puts("Du hast folgendes Zeichen gesendet: ");
50
                     uart_putc((unsigned char)c);
51
                     uart_puts("\n\r");
52
                     break;
53
            }
54
        }
55
    }
56
    while(flag);
57
 
58
    uart_puts("Springe zur Adresse 0x0000!\n\r");
59
    _delay_ms(1000);
60
 
61
    /* vor Rücksprung eventuell benutzte Hardware deaktivieren
62
       und Interrupts global deaktivieren, da kein "echter" Reset erfolgt */
63
 
64
    /* Interrupt Vektoren wieder gerade biegen */
65
    cli();
66
    temp = MCUCR;
67
    MCUCR = temp | (1<<IVCE);
68
    MCUCR = temp & ~(1<<IVSEL);
69
 
70
    /* Rücksprung zur Adresse 0x0000 */
71
    start(); 
72
    return 0;
73
}
Hat jemand ne Idee was ich falsch machen könnte?

Gruß Jürgen

von Tom M. (Gast)


Lesenswert?

Wie hast du denn die Fuses gesetzt?

von Jürgen (Gast)


Lesenswert?

Da hab ich folgendes:

low 0xEF
high 0xDF
extended 0xF8

von Stefan E. (sternst)


Lesenswert?

Mit welcher Optimierungs-Einstellung kompiliert?

von Thomas E. (thomase)


Lesenswert?

Jürgen schrieb:
> wenn ich ihn an die Bootloader-Adresse 0x3800(mithilfe der
>
> Linker-Option     -Ttext=0x3800)
Wo trägst du die denn ein?
Im Makefile wäre das so richtig.
In die AVR-Studio-Options kommt die Wordadresse:
0x3800 / 2 = 0x1c00

mfg.

von Jürgen (Gast)


Lesenswert?

Ich benutze die Optimierungseinstellung -Os und ich setze in den 
AVR-Studio options die Linker option -Ttext=0x3800, sodass dann im 
Makefile folgendes  erscheint:
1
## Linker flags
2
LDFLAGS = $(COMMON)
3
LDFLAGS +=  -Ttext=0x3800  -Wl,-Map=BootloaderTest.map

von Jürgen (Gast)


Angehängte Dateien:

Lesenswert?

Ich hab hier nochmal den Assemblercode dazu!

von Tom M. (tomm) Benutzerseite


Lesenswert?

Schau mal ins Hexfile, sind dort die Adressen 0x38xx sichtbar? Die 
zweite Zeile sollte etwa mit :1003800 beginnen.

Setzt du F_CPU richtig? Sonst ist die Baudrate total verwurstelt...

von Jürgen (Gast)


Angehängte Dateien:

Lesenswert?

Im Hex file beginnt die 2. Zeile mit :103810000C945...
Die F_CPU sollte richtig sein, da ich von der seriellen Schnittstelle 
einwandfreie Zeichenketten bekomme wenn ich das Programm nicht im 
Boot-Bereich starte.
Ich habe jetzt mithilfe der StatusLED herausgefunden, dass der 
Mikrocontroller in uart.c hängen bleibt. Ich verwende die 
Implementierung der seriellen Schnittstelle von Peter Fluery(siehe 
Anhang). An der durch den Pfeil markierten Stelle läuft das Programm nun 
nicht weiter:
1
void uart_putc(unsigned char data)
2
{
3
    unsigned char tmphead;
4
5
    
6
    tmphead  = (UART_TxHead + 1) & UART_TX_BUFFER_MASK;
7
    
8
    while ( tmphead == UART_TxTail ){
9
        ;/* wait for free space in buffer */
10
    }
11
    
12
    UART_TxBuf[tmphead] = data;
13
    UART_TxHead = tmphead;
14
15
    /* enable UDRE interrupt */
16
----->   UART0_CONTROL    |= _BV(UART0_UDRIE);
17
  
18
19
}/* uart_putc */

von Tom M. (tomm) Benutzerseite


Lesenswert?

Hmm sieht für mich alles ok aus. Vielleicht fällt ja jmd anders was auf?

Der Passus aus der uart.c passt (ich wundere mich, dass der Compiler 
hier das Z-Register verwendet, wo ein lds/ori/sts genügt):
1
+00001D6E:   ECE1        LDI       R30,0xC1       Load immediate
2
+00001D6F:   E0F0        LDI       R31,0x00       Load immediate
3
+00001D70:   8180        LDD       R24,Z+0        Load indirect with displacement
4
+00001D71:   6280        ORI       R24,0x20       Logical OR with immediate
5
+00001D72:   8380        STD       Z+0,R24        Store indirect with displacement
6
+00001D73:   9508        RET                      Subroutine return


In deiner "boot.txt" sieht die Vektoren-Tabelle okay aus; zumindest sind 
Rx complete und DRE umgesetzt:
1
+00001C24:   940C1CC9    JMP       0x00001CC9     Jump // USART Rx complete
2
+00001C26:   940C1CF9    JMP       0x00001CF9     Jump // USART Data Register Empty
3
+00001C28:   940C1C51    JMP       0x00001C51     Jump // USART Tx Complete

Das Verschieben der Tabelle erfüllt auch die Bedingung, dass das Setzen 
von IVCE und IVSEL innerhalb von 4 Zyklen (gem. Wiki-Aritkel) geschehen 
muss. Stack wird auch für den 168er passend gesetzt (0x4FF), deswegen 
knallt's auch nicht. Auch hier fällt mir wieder die Verwendung des Z 
Registers auf, mein Compiler macht das anders (avr-gcc 4.3.3).

Hab mal den C Code reingemischt:
1
    char sregtemp = SREG;
2
3
+00001C6B:   B72F        IN        R18,0x3F       In from I/O location
4
5
    cli();
6
7
+00001C6C:   94F8        CLI                      Global Interrupt Disable
8
9
    temp = MCUCR;
10
11
+00001C6D:   E5E5        LDI       R30,0x55       Load immediate
12
+00001C6E:   E0F0        LDI       R31,0x00       Load immediate
13
+00001C6F:   8180        LDD       R24,Z+0        Load indirect with displacement
14
+00001C70:   2F98        MOV       R25,R24        Copy register
15
16
    MCUCR = temp | (1<<IVCE);
17
18
+00001C71:   6091        ORI       R25,0x01       Logical OR with immediate
19
+00001C72:   8390        STD       Z+0,R25        Store indirect with displacement
20
21
    MCUCR = temp | (1<<IVSEL);
22
23
+00001C73:   6082        ORI       R24,0x02       Logical OR with immediate
24
+00001C74:   8380        STD       Z+0,R24        Store indirect with displacement
25
26
    SREG = sregtemp;
27
28
+00001C75:   BF2F        OUT       0x3F,R18       Out to I/O location

von Stefan E. (sternst)


Lesenswert?

Tom M. schrieb:
> Hmm sieht für mich alles ok aus. Vielleicht fällt ja jmd anders was auf?

Ich bezweifle, dass das Disassembly tatsächlich von obigen Source-Code 
stammt, denn dieser Teil
1
    uart_init( UART_BAUD_SELECT(BOOT_UART_BAUD_RATE,F_CPU) ); 
2
    sei();
3
 
4
    uart_puts("Hallo hier ist der Bootloader\n\r");
5
    _delay_ms(1000);
ist dort doppelt drin, und zwar vor und nach dem Verschieben der 
Vektoren. Und das vor dem Verschieben ist natürlich tötlich.

Tom M. schrieb:
> Der Passus aus der uart.c passt (ich wundere mich, dass der Compiler
> hier das Z-Register verwendet, wo ein lds/ori/sts genügt):

Was mich ebenfalls an dem -Os zweifeln lässt.

von Jürgen (Gast)


Angehängte Dateien:

Lesenswert?

So ich habe festgestellt, dass das Disassembly tatsächlich nicht das 
richtige war, denn der Teil
1
uart_init( UART_BAUD_SELECT(BOOT_UART_BAUD_RATE,F_CPU) ); 
2
sei();
3
4
uart_puts("Hallo hier ist der Bootloader\n\r");
5
_delay_ms(1000);
erscheint wie bereits erwähnt 2 mal. Diesen hatte ich zu Debugzwecken an 
der Anfang geschoben. Ich habe hier nun nochmal das richtige file, 
kompiliert mit -Os, das genausowenig funktioniert.

von Jürgen (Gast)


Lesenswert?

Also ich habe mittlerweile eine andere Implementierung für sie serielle 
Kommunikation genommen und jetzt klappt auch fast alles, nur das ich 
scheinbar nicht in den Flash speicher schreiben kann. Ich benutze die 
Funktion
1
 void boot_program_page (uint32_t page, uint8_t *buf)
aus dem Bootloader Tutorial(s.o). Ich habe testweise einfach mal 
versucht, irgendetwas an den Anfang des Speichers zu schreiben:
1
for (int i = 0; i < SPM_PAGESIZE; i++)
2
  {
3
    flash_data[i] = 0x01;
4
  }
5
  boot_page_erase (64);
6
  program_page((uint16_t)0, flash_data);
Jedoch ohne Erfolg. Hat vielleicht jemand eine Idee?

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.