AVR bootloader Probleme

Gast #3769473
Lesenswert?

Hallo mikrocontroller Gemeinde,

ich habe mir den Artikel "AVR Bootloader in C - eine einfache Anleitung" 
hier durchgelesen und versuche nun den Bootloader zum laufen zu bekommen 
um ein HEX File damit zu schreiben..

Leider macht mein µC dabei komische Sachen.

Ich verwende einen AT90CAN128, habe die fuses eingestellt und das -Ttext 
Flag beim Linker auf den richtigen Wert gesetzt, funktioniert alles 
Prima - bootloader startet und meldet sich über den UART.

Nun sobald ich versuche eine Datei zu schreiben ('p') macht er beim 
ersten Zeichen, das ich ihm sende ein Reset.

Ich habe durchgetestet und herausgefunden an welcher Stelle er resetted:

(Anfang der main Schleife)
1
do
2
    {
3
        c = uart_getc();
4
        if( !(c & UART_NO_DATA) )
5
        {
6
             /* Programmzustand: Parser */
7
             if(boot_state == BOOT_STATE_PARSER)
8
             {
9
                  // HIER KOMMT ER NOCH HIN
10
                  switch(parser_state)
11
                  {
12
                      /* Warte auf Zeilen-Startzeichen */
13
                      case PARSER_STATE_START:
14
        // HIER NICHT MEHR
15
                          if((uint8_t)c == START_SIGN) 
16
                          {

.. obwohl parser_state auf PARSER_STATE_START stehen MUSS

Nun kommt der oberwitz: frage ich direkt über dem switch(..) ab, ob 
parser_state PARSER_STATE_START ist
1
if (parser_state == PARSER_STATE_START) {
2
          PORTC ^= (1 << PC0);
3
        }

dann funktioniert alles :/

Der compiler macht dann auch einen ganz anderen assembler code daraus:

ohne IF Abfrage:
1
      /* Programmzustand: Parser */
2
      if(boot_state == BOOT_STATE_PARSER)
3
   1e274:  21 e0         ldi  r18, 0x01  ; 1
4
   1e276:  72 12         cpse  r7, r18
5
   1e278:  06 c1         rjmp  .+524      ; 0x1e486 <main+0x2b6>
6
      {
7
        switch(parser_state)
8
   1e27a:  89 2d         mov  r24, r9
9
   1e27c:  90 e0         ldi  r25, 0x00  ; 0
10
   1e27e:  87 30         cpi  r24, 0x07  ; 7
11
   1e280:  91 05         cpc  r25, r1
12
   1e282:  08 f0         brcs  .+2        ; 0x1e286 <main+0xb6>
13
   1e284:  52 c1         rjmp  .+676      ; 0x1e52a <main+0x35a>
14
   1e286:  fc 01         movw  r30, r24
15
   1e288:  e6 5b         subi  r30, 0xB6  ; 182
16
   1e28a:  ff 40         sbci  r31, 0x0F  ; 15
17
   1e28c:  9d c2         rjmp  .+1338     ; 0x1e7c8 <__tablejump2__>
18
        {
19
          /* Warte auf Zeilen-Startzeichen */
20
          case PARSER_STATE_START:
21
          if((uint8_t)c == START_SIGN)
22
   1e28e:  8a e3         ldi  r24, 0x3A  ; 58
23
   1e290:  e8 12         cpse  r14, r24
24
   1e292:  4b c1         rjmp  .+662      ; 0x1e52a <main+0x35a>

mit IF Abfrage:
1
      /* Programmzustand: Parser */
2
      if(boot_state == BOOT_STATE_PARSER)
3
   1e266:  21 e0         ldi  r18, 0x01  ; 1
4
   1e268:  32 12         cpse  r3, r18
5
   1e26a:  18 c1         rjmp  .+560      ; 0x1e49c <main+0x2da>
6
      {
7
        if (parser_state == PARSER_STATE_START) {
8
   1e26c:  71 10         cpse  r7, r1
9
   1e26e:  10 c0         rjmp  .+32       ; 0x1e290 <main+0xce>
10
          PORTC ^= (1 << PC0);
11
   1e270:  88 b1         in  r24, 0x08  ; 8
12
   1e272:  83 25         eor  r24, r3
13
   1e274:  88 b9         out  0x08, r24  ; 8
14
        }
15
        switch(parser_state)
16
        {
17
          /* Warte auf Zeilen-Startzeichen */
18
          case PARSER_STATE_START:
19
          if((uint8_t)c == START_SIGN)
20
   1e276:  8a e3         ldi  r24, 0x3A  ; 58
21
   1e278:  48 12         cpse  r4, r24
22
   1e27a:  62 c1         rjmp  .+708      ; 0x1e540 <main+0x37e>

Leider kenne ich mich mit assembler nicht so gut aus, aber ich denke die 
unterscheiden sich ganz massiv.. warum der reset stattfindet würde mich 
sehr interessieren

jemand eine Idee??

mfg kevin
Gast #3769489
Lesenswert?

>Nun sobald ich versuche eine Datei zu schreiben ('p') macht er beim
>ersten Zeichen, das ich ihm sende ein Reset.

Folgende Dinge führen häufig zu einem Reset:

Interrupt freigeschaltet und kein Interruptvektor dafür vorhanden.
Stackoverflow.
Arraygrenzen überschritten.
Watchdog aktiv.

Mit deinen Codeschnipseln kann kein Mensch was anfangen,
oder das Problem finden. Das liegt vermutlich ganz woanders.
Gast #3769497
Lesenswert?

Hallo Holger

> Interrupt freigeschaltet und kein Interruptvektor dafür vorhanden.
ich habe ISR(BADISR_vect) { } definiert, sollte also nicht passieren

> Stackoverflow.
1. Wie kann ich das herausfinden? 2. Sollte avr-gcc doch so schlau sein 
keinen stack overflow zu erzeugen, oder?

> Arraygrenzen überschritten.
An der Stelle wird auf kein Array zugegriffen

> Watchdog aktiv.
Das werde ich mal prüfen, ist aber wohl auch eher unwahrscheinlich da 
der reset immer bei der gleichen aktion auftritt.

Den code habe ich 1:1 aus dem artikel übernommen
http://www.mikrocontroller.net/articles/AVR_Bootloader_in_C_-_eine_einfache_Anleitung
Gast #3769745
Lesenswert?

Ich habe nun die compilereinstellungen der beiden Versionen abgeglichen, 
bei 6.2 immernoch das gleiche Verhalten.

AVR GCC Versionen: 4.6.2 (Atmel Studio 6.0) und 4.8.1 (Atmel Studio 6.2)

Kann doch nur ein Compilerproblem sein, wenn alle Einstellungen + 
Programm identisch sind und es beim einen geht, beim anderen nicht, ... 
?
(Firma: Vescomp) #3769872
Lesenswert?

kevin schrieb:
> if((uint8_t)c == START_SIGN)
>    1e28e:  8a e3         ldi  r24, 0x3A  ; 58
>    1e290:  e8 12         cpse  r14, r24
>    1e292:  4b c1         rjmp  .+662      ; 0x1e52a <main+0x35a>

kevin schrieb:
> if((uint8_t)c == START_SIGN)
>    1e276:  8a e3         ldi  r24, 0x3A  ; 58
>    1e278:  48 12         cpse  r4, r24
>    1e27a:  62 c1         rjmp  .+708      ; 0x1e540 <main+0x37e>

 Einmal wird r14 auf empfangenes Zeichen geprüft (ohne Abfrage),
 im anderen Fall wird r4 geprüft (mit Abfrage).
 Du machst da zwar cast auf uint8, aber das sieht man nicht, also
 muss es weiter oben gemacht worden sein (wenn uberhaupt).
 Und warum Compiler das machen sollte - auch mit Optimisierung -
 ist fur mich unverständlich.
 Wie ist 'UART_NO_DATA' definiert ?
Gast #3770033
Lesenswert?

Es ist die UART lib von peter fleury, hier die definitionen der return 
codes:
1
#define UART_FRAME_ERROR      0x1000              /* Framing Error by UART       */
2
#define UART_OVERRUN_ERROR    0x0800              /* Overrun condition by UART   */
3
#define UART_PARITY_ERROR     0x0400              /* Parity Error by UART        */ 
4
#define UART_BUFFER_OVERFLOW  0x0200              /* receive ringbuffer overflow */
5
#define UART_NO_DATA          0x0100              /* no receive data available   */
(Firma: Vescomp) #3770139
Lesenswert?

kevin schrieb:
> #define UART_NO_DATA          0x0100              /* no receive data

kevin schrieb:
> if( !(c & UART_NO_DATA) )

 Also, ich verstehe diese komische Abfrage überhaupt nicht...
 Ob du ein Zeichen empfangen hast oder nicht - das Ergebnis ist für
 mich immer dasselbe.
 (c & UART_NO_DATA) = (c & 0x0100) = 0x00

 somit ist deine Behauptung:
> .. obwohl parser_state auf PARSER_STATE_START stehen MUSS

 schon mal nicht zutreffend.
 Dein Programm ist ohne ein Zeichen zu empfangen zum SWITCH angelangt.
 Jedenfalls sehe ich das so.
#3770297
Lesenswert?

Marc Vesely schrieb:
> Also, ich verstehe diese komische Abfrage überhaupt nicht...
>  Ob du ein Zeichen empfangen hast oder nicht - das Ergebnis ist für
>  mich immer dasselbe.
>  (c & UART_NO_DATA) = (c & 0x0100) = 0x00

Nein, denn c ist größer als 8 Bit (sollte es jedenfalls sein). Die 
Fleury-Lib gibt nun mal in den unteren 8 Bit das empfangene Zeichen und 
in den oberen 8 Bit zusätzliche Statusinformationen zurück. Deshalb auch 
der Cast auf 8-Bit bei dem späteren Vergleich.
(Firma: Vescomp) #3770424
Lesenswert?

Stefan Ernst schrieb:
> Nein, denn c ist größer als 8 Bit (sollte es jedenfalls sein). Die
> Fleury-Lib gibt nun mal in den unteren 8 Bit das empfangene Zeichen und
> in den oberen 8 Bit zusätzliche Statusinformationen zurück. Deshalb auch
> der Cast auf 8-Bit bei dem späteren Vergleich.

 Ja, cast hab ich gesehen, aber nicht in den gesendetem assembler-code,
 also muss es schon vorher gemacht worden sein. Und wo soll der Compiler
 das gemacht haben, ausser bei der Abfrage ?
#3770448
Lesenswert?

Marc Vesely schrieb:
> Ja, cast hab ich gesehen, aber nicht in den gesendetem assembler-code,
>  also muss es schon vorher gemacht worden sein. Und wo soll der Compiler
>  das gemacht haben, ausser bei der Abfrage ?

Was soll er denn da weiter "machen"? Der Cast im Vergleich sagt doch nur
"beschneide c für diesen Vergleich auf die unteren 8 Bit". Und genau das 
macht der Assembler-Code, denn er vergleicht nur das untere Byte.
Gast #3770577
Lesenswert?

Das sind verschiedene Abfragen, erst wird mit (!(c & UART_NODATA)) 
geprüft, ob ein Zeichen empfangen wurde, (c ist uint16), dann wird 
geprüft, ob das empfangene Zeichen gleich START_SIGN, also ':' ist.

Ich habe mir das auch nicht selbst ausgedacht sondern - wie gesagt - es 
ist das Programm aus dem mikrocontroller.net Artikel.

Und es funktioniert mit Atmel Studio 6 einwandfrei, mit 6.2 habe ich 
dieses komische Verhalten, leider verstehe ich den Assembler code nicht 
und habe deshalb keine Idee wo genau nun das Problem liegen könnte, 
interessieren würde es mich aber schon.
#3770720
Lesenswert?

Bei der nicht funktionierenden Variante wird das switch über eine 
Sprungtabelle realisiert. Diese liegt hinter den Interrupt-Vectoren. 
Beim Auslesen des Tabelleneintrags wird nur ein lpm verwendet (kein 
elpm/RAMPZ). Bei einem Bootloader geht das auf Grund seiner besonderen 
Adresslage in die Hose und es kracht.

Ich würde es mit -fno-jump-tables versuchen.
Gast #3771066
Lesenswert?

Vielen Dank Stefan, das flag werde ich mal probieren.

Heißt also, dass solche Probleme auch mit einer älteren avr-gcc Version 
auftreten könnten und ich nur das Glück hatte, dass hier keine 
Sprungtabelle verwendet wurde, oder liege ich da falsch?

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