Ein Bootloader muss her…
…sonst fallen Updates ziemlich schwer.
Design
Ein Bootloader ist ja grundsätzlich mal dafür da, dass er die eigentliche Applikation lädt und startet. Drumherum gibt es aber noch viele andere Aufgaben, die ein Bootloader noch erfüllen kann. In meinem Fall soll der Ablauf aussehen wie folgt:
Wir starten am Reset-Vektor, Adresse 0x000. Über den gesamten Applikationsbereich wird eine Prüfsumme berechnet und mit einer am Ende des Speichers hinterlegten verglichen. Wenn sie übereinstimmen, wird die Applikation sofort gestartet.
Wenn die Prüfsumme nicht passt, dann richtet sich der Bootloader mal die UART-Schnittstelle ein und wartet auf Befehle. In diesem Zustand kann dann von außen eine neue Applikation eingespielt werden. Am Ende wird ein Neustart ausgelöst und wir beginnen von vorne, diesmal hoffentlich erfolgreich.
Wenn im Normalbetrieb die Software aktualisiert werden soll, muss die Applikation direkt in den Bootloader zu Punkt 2 springen.
Der 3. Punkt ist vielleicht etwas unkonventionell, weil die Applikation den Bootloader kennen muss. In vielen Fällen (Arduino) horcht der Bootloader beim Starten kurz auf Befehle, bevor er die Applikation startet. Auf anderen Plattformen muss ein Pin auf einen bestimmten Pegel gebracht werden, um den Bootloader zu starten. Bei beiden Varianten ist aber ein Neustart erforderlich, unter Umständen sogar ein Power-On-Reset, um in den Bootloader zu kommen. Das ist bei fix installierten Modulen, die im Idealfall mehrere Jahre ohne Unterbrechung laufen und sich einen Bus teilen, nicht wirklich praktikabel. Deshalb darf die Applikation generell mal gleich starten und muss sich selber um Updates kümmern.
Implementierung
Assembler-Programmierung ist mit den kleinen PIC-Prozessoren wirklich einfach und speichereffizient sowieso, deshalb mache ich das wieder. Ich stecke mir selbst das Ziel, den Bootloader im Adressbereich 0x000 bis 0x0ff zu implementieren, um den ganzen Bereich von 0x100 bis 0x7ff für die Applikation zur Verfügung zu haben. Das sind also 256 Befehle. Am Anfang habe ich noch keine Ahnung, ob sich das ausgeht, ich komme auch zunächst knapp drüber. Aber immerhin, wir sind feature-complete. Ich kann über die UART-Schnittstelle eine Applikation auf den Prozessor laden und die wird dann ausgeführt. Das muss natürlich das Hello-World der Microcontroller sein, blinky-blink:
Am Ende bekomme ich den Bootloader mit ein paar einfachen Optimierungen unter die gesetzten 256 Befehle und kann damit das Projekt nach zwei Abenden intensiver Arbeit schon wieder als fertig bezeichnen. Also wirklich fertig, funktioniert, nie wieder angreifen!
Die Hardware auf dem Bild ist übrigens ein Arduino Proto Shield (Nachbau), gesteckt auf ein uraltes Arduino-Board, aus dem ich den Prozessor entfernt habe. Ich verwende das Board also nur als Spannungsversorgung und USB-UART Konverter. Auf dem Shield thront der treue PIC12F1572, diesmal im SO8-Gehäuse und sauber verlötet, mit einer LED zum Debuggen und einem Pinheader zum Programmieren.