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
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
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
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.
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...
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?
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.