Forum: Compiler & IDEs Vorgehensweise um Bootloader zu programmieren


von Nik B. (nikbamert)


Lesenswert?

Hi,

bin dabei mir einen Bootloader für Atmels Avr's zu programmieren.
Nun wollte ich das eigentlich so machen, dass ich den uC direkt in der 
Bootsection starten lasse. Inklusive programmieren geht auch schon 
alles, nur stellt sich mir am Ende die Frage, wie ich zum Hauptprogramm 
springen kann.
Schön wäre ein Reset per Watchdog, aber dann lande ich wieder im 
Bootloader, da ich das BOOTRST Fuse so eingestellt habe dass ich bei 
einem Reset direkt im Bootloader lande. Die andere Möglichkeit wäre am 
Ende des Bootloadercodes einfach zur Adresse 0x00 zu springen, aber ob 
das so ideal ist weiss ich nicht (stackinit?). Die letzte Möglichkeit 
die mir einfällt ist, den Bootloader jeweils vom Hauptprogramm 
aufzurufen, aber wenn man dann mal irgendeinen fehlerhaften Code 
uploaded, sperrt man sich selbst aus und kommt nie mehr in den 
Bootloader.
Daher die Frage: Gibt's sonst irgendeine elegante Methode um dieses 
Problem zu lösen?

Nik

von Wolfgang Horn (Gast)


Lesenswert?

Hi, Nik,

ja, der Bootloader hat schon seine Denkhürden!

Du: "Daher die Frage: Gibt's sonst irgendeine elegante Methode um dieses
Problem zu lösen?"

Keine Angst. Das Übliche ist sicher.

Du: "Nun wollte ich das eigentlich so machen, dass ich den uC direkt in 
der
Bootsection starten lasse."

Das hast Du richtig verstanden, so ist das vorgesehen.


Du: "..am Ende des Bootloadercodes einfach zur Adresse 0x00 zu 
springen..."

So habe ich das gemacht, so ist das üblich. Watchdog geht nicht, weil, 
wie Du erkannt hast, dann der Bootloader wieder gerufen wird.

Initialisierung des Stack ist kein Problem, weil der Sprung auf 0x0000 
die Initiaisierung der Application Section startet.
Deine Vorsicht ist trotzdem richtig, ich gehe davon aus, daß die 
Register ihre vorherigen Inhalte behalten. Insbesondere beim UART zu 
beachten.

Ciao
Wolfgang Horn

von Stefan K. (_sk_)


Lesenswert?

Wichtig ist, die IR-Vektoren auf Normalbetrieb umzustellen. Sonst werden 
für Deine Interrupts die Vektoren aus dem Bootbereich geholt.
1
  uint8_t my_GICR_IVCE  = GICR | _BV(IVCE);
2
  uint8_t my_GICR_IVSEL = GICR & ~_BV(IVSEL);
3
4
  GICR = my_GICR_IVCE;              // diese beiden Schreibbefehle müssen
5
                                    // direkt hintereinander erfolgen
6
  GICR = my_GICR_IVSEL;             // (max. 4 Taktzyklen)
7
8
  asm("jmp 0");                     // direkter Sprung an den
9
                                    // Applikations-Start

Stackinit ist kein Problem, das macht Dein "Normalprogramm" nach Start 
bei 0000h ja nochmal.
Ein bischen Beachtung schenken musst Du Registern, die im Bootloader 
geändert werden. Die im Manual angegebene Initialisierung nach Reset ist 
natürlich nicht mehr gegeben!

Viel Spass, Stefan

von Schmittchen (Gast)


Lesenswert?

Naja, geschickter ist es vom Bootloader aus nachzuschauen, ob überhaupt 
eine Applikation vorliegt und dann erst dorthin weiterzuverzweigen. 
Ansonsten rennst du ins Nirvana, ungünstige Ports werden zufällig 
eingeschaltet - kann böse Folgen haben.

Saubere (Luxus)variante: Deshalb aus dem Bootloader heraus eine 
Checksummenprüfung des Applikationscodes durchführen. Das soeben 
berechnete Ergebnis muss identisch mit dem vorausberechneten, und in der 
Applikation an einer bestimmten Speicherstelle abgelegten, Ergebnis 
sein.

Ist das zu aufwendig, dann aus dem Applikationscode heraus eine 
Konstante an einer genau definierten Speicherstelle anlegen lassen, 
deren Vorhandensein vom Bootloader abgefragt werden kann. Liegt diese 
Konstante vor, dann ist eine gültige Applikation im Flash und darf 
angesprungen werden, wenn nicht, dann nicht.


Und damit du auch schön über Reset (WD-Reset) in die Applikation 
verzweigen kannst, verwendet man einen "zweiteiligen" Bootloader. Ich 
nenne das immer Bootmanager und Bootloader. Der Bootmanager wird IMMER 
vom Resetvektor aufgerufen und schaut nur, ob eine Applikation vorliegt 
(Verfahren siehe oben). Falls keine Applikation, dann Abzweigen in den 
Bootloader, falls Applikation als gültig erkannt, dann diese starten.
Abzweigung in Bootloader: Erst hier werden dann irgendwelche 
Registereinstellungen und Initialisierungen FÜR den Bootloader 
vorgenommen, du hast kein Problem mit "verstellten" oder "write-once" 
Registern in der Applikation usw..

Übrigens, ich schreibe hier nicht AVR-spezifisch, sondern 
allgemeingültig.

von Nik B. (nikbamert)


Lesenswert?

Dankeschön für alle eure Antworten,

ich habe nun zum Testen einfach mal einen jump zur Adresse 0 gemacht, 
ohne sonst irgendwas an den Registern zu ändern. In den meisten Fällen 
klappt das auch, einige Male hatte ich jedoch das Problem, dass das 
Hauptprogramm nicht mehr (richtig) anlief, deshalb möchte ich eigentlich 
eher eine "Luxusvariante", damit einfach nichts mehr schief läuft. 
Allerdings habe ich da einige Problemchen - ich möchte nämlich das der 
Bootloader möglichst noch in 1024 Words / 2048 bytes Platz findet, im 
Moment bin ich aber schon bei 1920 Byte. Das mit der Prüfung per 
Checksumme klingt eigentlich sehr interessant, nur stellt sich mir da 
die Frage ob das beim Programm/Bootloaderstart dann nicht immer eine 
Ewigkeit dauert, wenn zB 64kByte Code überprüft werden müssen (?).

Das Firmwareupdate das sich der Bootloader holt, kommt von einer 
SD-Karte(FAT32). Nun muss ich es also in 100 bytes noch irgendwie 
hinkriegen, die Datei auf das Erstellungsdatum zu überprüfen, so dass 
nicht bei jedem Start die Firmware neu geschrieben wird, sondern nur, 
wenn auch wirklich eine aktuellere Version vorhanden ist. Zudem dann 
noch die Elemente die zur "Luxusvariante" führen. Luxus muss es für mich 
eigentlich nicht gerade sein,
ich kann nämlich mit ziemlicher sicherheit davon ausgehen, dass wenn 
geupdated wurde, dass dann auch eine gültige Applikation vorliegt.
Allerdings müsste ich das Problem mit den Registern noch lösen.
Gibt es ausser den Interruptvektoren noch sonstige, für den Betrieb 
wichtige Register die ich wieder in den Ursprungszustand zurücksetzen 
müsste?

Problematisch würde es, wenn dies von AVR zu AVR noch unterschiedlich 
wäre :-(

Grüsse,
Nik

EDIT: Noch eine Frage zu Stefans asm beispiel: Kann man davon ausgehen 
dass "jmp 0" immer funktioniert oder muss es bei einigen AVR mit mehr 
als 64kb Flash "rjmp" heissen? Habe von assembler leider nicht so viel 
Ahnung...

von Nik B. (nikbamert)


Lesenswert?

Hi, wollte mal sagen, dass ich es nun so wie Stefan mache, klappt super! 
:-)
Allerdings habe ich noch eine Frage; In meinem Bootloader brauche ich 
den SPI (für die SDkarte). Bleibt das Register SPCR erhalten, wenn ich 
wie Stefan vorgehe, oder wird dies auf die Defaultwerte zurückgesetzt?

von Joe D. (kosmonaut_pirx)


Lesenswert?

hallo,
falls du mit "so wie Stefan" das irq-table-geschiebe meinst, dann ändert 
sich nichts, da wird nichts zurückgesetzt. müsste die mcu ja alle 
control register abklappern für sowas.
bye kosmo

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.