Forum: Mikrocontroller und Digitale Elektronik AVR Goto Bootloader aus RXC_vect


von Phillip H. (philharmony)


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
}

von Christian P. (Firma: FSW GmbH) (f-sw)


Lesenswert?

Hallo Phillip,

ich benutze eine Software die das auch so
ähnlich macht.
Ich benutze dazu den Watchdog. Einfach nach dem
empfangen der 10 'U' den Watchdog einschalten und
der Controller macht nach der eingestellten Zeit einen Reset.

Gruß

Christian

von Phillip H. (philharmony)


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?

von Oliver (Gast)


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

von Stefan E. (sternst)


Lesenswert?

1
  goto *0x7800;
Das springt zur Word Adresse 0x7800.

von Nils S. (kruemeltee) Benutzerseite


Lesenswert?

1
void (*jump_to_bootloader)( void ) = 
2
  bootloaderstartadresse; jump_to_bootloader(); // Jump to bootloader
Quelle: http://www.embedded-projects.net/index.php?page_id=81

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.