AVR Goto Bootloader aus RXC_vect

OP #1708819
Lesenswert?

Hi,
Ich habe ein etwas größeres Projekt und will dabei im laufenden Betrieb 
zum Bootloader wechseln können. Der Bootloader ermittelt aus einer Reihe 
von 'U'-Chars seine Baudrate (Chip45boot2).
Damit der Reset schön einfach geht, frage ich im RXC-vect (der Uart wird 
auch sonst fleißig benutzt) einfach ab, ob 10-mal hintereinander ein 
solches 'U' kommt. Da mein restliches Protokoll keine Buchstaben 
enthält, sollte das auch nicht versehentlich ausgelöst werden.
Der Bootloader-Bereich ist 1k Words, die Startadresse 0x3C00. Das ganze 
ist ein Atmega32.
Mein Problem ist jetzt aber: Es funktioniert nicht. Der Controller 
resettet sich zwar, springt aber nicht in den Bootloader.
Der Bootloader an sich funktioniert, wenn ich die 'U's sende und den 
Controler per Reset-Pin bzw Power-Toggle resette, dann springt er 
problemlos in den Bootloader.

Fuses für Bootsize ist per AVR-Studio auf 1K Words gesetzt, Bootrst ist 
Programmed.

Hier das Empfangs-Interrupt. Die sonstige Abwicklung des Empfanges 
funktioniert einwandfrei...Hat jemand eine Idee?
(Bitte nicht: "Nimm doch einfach den Bootloader xyz", oder "Wozu soll 
das gut sein?")
1
/*Reset an die Bootloader-Adresse*/
2
void reset_to_bootloader(void)
3
{
4
  /*Interrupts deaktivieren*/
5
  cli();
6

7
  /*RXD Pin als Eingang*/
8
  DDRD &= ~(1 << PD0);
9

10
  /*Sprung zur Bootloaderstartadresse*/
11
  goto *0x7800;  
12
}
13

14

15
/*USART Empfangs Interrupt*/
16
ISR(USART_RXC_vect)
17
{  
18
  /*UDR leeren (damit UART wieder bereit), Zeichen zwischenspeichern*/
19
  uint8_t buffer = UDR;                      
20
  static uint8_t flag = ERR_NO_ERROR;
21
  static uint8_t ct_reset;
22

23
  /*Wenn Zeichen ein U ist*/
24
  if (buffer == 'U')                        
25
  {
26
    /*Reset für Bootloader nach dem 10. U*/
27
    if(++ct_reset==10)
28
    {
29
      reset_to_bootloader();                
30
    }
31
    /*wenn 10. U noch nicht erreicht, Vector verlassen*/
32
    else
33
    {
34
      return;
35
    }
36
  }
37

38
  else
39
  {
40
    /*Reset Counter zurücksetzen*/
41
    ct_reset = 0;
42
  }
43

44
  /*Wenn Endzeichen ankommt*/  
45
  if (buffer == RX_TERMINATOR)                  
46
  {  
47
    /*Wenn zuvor kein Fehler aufgetreten war, dann ist der Frame gültig*/
48
    if (flag == ERR_NO_ERROR)                    
49
    {
50
      /*und wird freigegeben*/
51
      release_last_frame(&rx_buffer);  
52
      
53
      /*Und Zähler wird erhöht*/
54
      number_rx_frames++;  
55
    }
56

57
    /*Wenn hingegen ein Fehler aufgetreten war, ist der Frame ungültig*/
58
    else
59
    {
60
      /*und wird verworfen*/
61
      dismiss_last_frame(&rx_buffer);
62

63
      /*Es wird eine Fehlermeldung ausgegeben*/
64
      send_status_message(PREFIX_ERROR, flag);
65

66
      /*Und Flag zurücksetzen*/
67
      flag = ERR_NO_ERROR;
68
    }
69
  }
70

71
  /*Alle anderen Zeichen*/
72
  else
73
  {
74
    /*Werden im Ringpuffer gespeichert und der Rückgabewert (Fehlermeldung) gespeichert*/
75
    flag = put_to_ringbuffer(&rx_buffer, buffer);
76
  }
77
  return;
78
}
OP #1709578
Lesenswert?

Hi Christian,
Momentan mache ich resets auch per Watchdog, allerdings möchte ich den 
zukünftig wirklich als "Wachhund" benutzen und möchte daher die 
goto-Anweisung verwenden. Laut Datenblatt und Beschreibung des 
Bootloaders sollte das ja eingetlich auch ohne weiteres funktionieren, 
leider tut es das einfach nicht, dh. höchst wahrscheinlich mache ich 
dabei noch irgendetwas falsch. Gibt es bei der goto-Anweisung etwas zu 
beachten, zB wenn sie aus einem Interrupt-Vector heraus aufgerufen wird?
Gast #1709600
Lesenswert?

Phillip Hommel schrieb:
> Momentan mache ich resets auch per Watchdog, allerdings möchte ich den
> zukünftig wirklich als "Wachhund" benutzen und möchte daher die
> goto-Anweisung verwenden.

Und warum kannst du den watchdog zukünftig nicht mehr dafür verwenden? 
Ob der nun zuschlägt, weil der Prozessor hängt, oder weil du absichtlich 
eine eine Endlosschleife eingebaut hast, ist dem völlig egal.

Damit bekommst du dann den echten Reset, mit definierten Zuständen aller 
Hardwaremodule. Ein Sprung auf die Resetadresse ist ja kein 
vollständiger Reset.

Phillip Hommel schrieb:
> ...die Startadresse 0x3C00.
>...
>   goto *0x7800;

Hm. Schon mal ins Disassembly geschaut?

Oliver

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