www.mikrocontroller.net

Forum: Compiler & IDEs Vorgehensweise um Bootloader zu programmieren


Autor: Nik Bamert (nikbamert)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Wolfgang Horn (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Stefan Kleinwort (_sk_)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wichtig ist, die IR-Vektoren auf Normalbetrieb umzustellen. Sonst werden 
für Deine Interrupts die Vektoren aus dem Bootbereich geholt.
  uint8_t my_GICR_IVCE  = GICR | _BV(IVCE);
  uint8_t my_GICR_IVSEL = GICR & ~_BV(IVSEL);

  GICR = my_GICR_IVCE;              // diese beiden Schreibbefehle müssen
                                    // direkt hintereinander erfolgen
  GICR = my_GICR_IVSEL;             // (max. 4 Taktzyklen)

  asm("jmp 0");                     // direkter Sprung an den
                                    // 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

Autor: Schmittchen (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Nik Bamert (nikbamert)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Nik Bamert (nikbamert)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Joe Die (kosmonaut_pirx)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.