ATmega168 Bootloader

Gast #2662110
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
Gast #2662912
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
Gast #2663170
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 */
Angehängte Dateien:
Persönliche Seite #2663523
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
#2663901
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.
Gast #2665009
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.
Angehängte Dateien:
Gast #2666907
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?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren