Bootloader Tutorial, Teil 3: Live-Update Bootloader

Björn Schmitz

17/12/2019

Im dritten und letzten Teil dieser Reihe möchte ich auf eine weitere Realisierungsmöglichkeit für einen Bootloader eingehen. Der Unterschied bei dieser Variante besteht darin, dass der Bootloader kein eigenständiges Firmware-Projekt ist, sondern in der Hauptapplikation integriert wird. Hierdurch erhält die Applikation eine Möglichkeit ein Update von sich selbst durchzuführen, ohne das andere Funktionen der Firmware dadurch (vollständig) unterbrochen werden müssen. Wer aber vorher noch einmal die ersten beiden Teile lesen möchte, findet diese hier:

Bootloader Tutorial, Teil 1

Bootloader Tutorial, Teil 2

Problembeschreibung

Stellen wir uns eine Mikrocontrollerfirmware vor, welche über ein User-Interface mit einem Benutzer interagieren kann. Außerdem ist die Firmware für das Auslesen von Sensoren und die Steuerung von Aktoren zuständig. Die Firmware kann eigenständig Softwareupdates von einem Server herunterladen und installieren. Das Problem: Bei einem klassischen Update müsste die Firmware zunächst durch den Nutzer in einen Updatemodus gebracht werden, in dem dann mit dem Bootloader die neue Firmware aufgespielt wird. Das hat unter anderem folgende Nachteile:

  • Der Nutzer kann während dem Update nicht auf die übrigen Funktionen der Firmware zugreifen.
  • Der Bootloader braucht ein umfangreiches Wissen über die Hardware, sodass er alle Aktoren in einem sicheren Zustand halten kann.
  • Ggf. muss der Bootloader einen komplexen Kommunikationsstack beherrschen (in diesem Fall WLAN). Hierdurch benötigt der Bootloader nicht nur viel Speicher, sondern wird auch Fehleranfällig. Somit können auch Updates des Bootloaders erforderlich sein.
  • Da die Anwendungssoftware diesen Kommunikationsstack in der Regel ebenfalls benötigt, ist dieser immer doppelt vorhanden. Wird der Stack für die Applikation angepasst, muss dies entweder für den Bootloader passieren, oder die Host-Software muss 2 verschiedene Varianten des Protokolls unterstützen.
  • Läuft beim Update etwas schief, ist die Firmware nicht mehr zu gebrauchen, bis ein neues Update aufgespielt wird.

In der Regel ist der erste Punkt besonders problematisch. Lange Updatezeiten können für den Nutzer frustrierend sein. Es kann daher von Vorteil sein das Update der Firmware im Hintergrund auszuführen, ohne dass der Nutzer dies mitbekommt.

Lösung

Wie beschrieben wäre wünschenswert das die Firmware sich selber auf den neusten Stand bringt, ohne das deren übrige Funktionen dabei beeinträchtigt werden. Dabei gibt es allerdings folgende Probleme:

  • Eine Firmware die auf einem Flashspeicher läuft, kann sich nicht selbst überschreiben.
  • So lange der Flash beschrieben wird, kommt es in der Regel zu CPU-stalling. Die CPU wartet also, bis der Schreibvorgang beendet ist, bevor der nächste Befehl vom Flash geladen wird. Die Applikation läuft dadurch deutlich langsamer.

Um dies zu lösen haben einige Mikrocontroller Hersteller (Beispiele sind unter anderem Microchip und ST) eine breite Palette an Mikrocontrollern herausgebracht, deren Flash Speicher aus zwei symmetrischen Flash Bänken besteht. Dies hat den Vorteil, dass die CPU gleichzeitig Befehle von einer Bank ausführen kann, während die andere Bank beschrieben wird.

Physikalische und virtuelle Adressen

Um zu verstehen, wie das Update nun funktioniert muss man zunächst wissen, dass es einen Unterschied zwischen physikalischen und virtuellen Adressen gibt. Grundsätzlich haben beide Flash Bänke, so wie auch RAM und die Register des Controllers, ihren eigenen physikalischen Adressbereich. Diese einzelnen physikalischen Adressen werden allerdings virtuell auf einen größeren Gesamtbereich gemapped. Das bedeutet, dass die Software in der Regel nicht die physikalische Adresse des Flashs kennt, sondern lediglich auf die virtuellen Adressen zugreift. Über die virtuelle Adresse kann die SW dann direkt auf Register, RAM oder eben eine der beiden Flash Bänke zugreifen. In der Regel werden die Flash Bänke dabei nach dem folgenden Schema gemapped:

Um den virtuellen Adressbereich voll auszuschöpfen, können wir nun entweder eine Firmware schreiben, die so groß ist, dass sie sich auf den vollen virtuellen Programmspeicher erstreckt. Der Linker kennt beim Erstellen der Firmware lediglich die virtuellen Adressen, so dass in diesem Fall vom Entwickler keine Wissen, über die Aufteilung der Flash Bänke erforderlich ist. Alternativ können wir aber auch unsere Firmware auf den halben virtuellen Programmspeicher beschränken. So wird sichergestellt, dass Bank 2 immer frei bleibt und dieser Bereich für Updates zur Verfügung steht. Nach einem Update kann dann das Mapping einfach auf folgendes Schema geändert werden:

So wird nach einem Reset immer die Firmware auf Bank 2 gestartet. Auf Bank 1 verbleibt die alte Firmware, auch wenn diese nicht mehr angesprungen wird.

Der Updatevorgang

Wie sieht aber nun der Updatevorgang aus? Im Grunde wie jeder andere, die Updatesoftware, welche Teil der Hauptapplikation ist, muss aber sicherstellen, sie sich nicht selbst löscht und ausschließlich auf die Flash Bank schreibt, von der Sie selber nicht ausgeführt wird. Das kann man recht einfach erreichen, indem man die Adresse beim Schreiben auf den Flash, immer um die halbe virtuelle Adresse inkrementiert. Programmdaten die eigentlich an Adresse null gehören, werden so auf Adresse 0 + halber Programmspeicher (und damit auf den Anfang der zweiten Flash Bank) geschrieben. Ist der Programmspeicher so gemapped das Bank 1 auf virtueller Adresse 0 liegt, wird dann immer auf Bank 2 geschrieben. Ist Bank 2 auf Adresse virtueller Adresse 0, wird immer auf Bank 1 geschrieben.

Durch die Aufteilung auf zwei Flash Bänke, kann eine Firmware, welche auf einer der Flash Bänke läuft, ein Update der anderen Flash Bank ausführen ohne dass es zu CPU-stalling kommt. Hierdurch kann das Update im Hintergrund erfolgen und die Firmware kann parallel ihre übrigen Tasks weiterhin bearbeiten. Vor allem, wenn ein Betriebssystem verwendet wird, und der Updateprozess in einem niederprioren Thread läuft, werden die übrigen Funktionen kaum beeinträchtigt.

Ist das Firmwareupdate abgeschlossen, kann die Applikation die beiden Flash Bänke ummappen, und durch einen Sprung an den Anfang des virtuellen Adressbereichs die neue Firmware starten.

Brauche ich trotzdem einen klassischen Bootloader?

Im Grunde wird durch das oben beschriebene Vorgehen der klassische Bootloader nicht vollständig ersetzt. Es fehlt zum Beispiel eine Überprüfung des Applikationsspeichers. Außerdem wird das Mapping der Flash Bänke – je nach Controller – nach einem Reset wieder zurückgesetzt. Es wird also ggf. ein Stück Code benötigt, welche die Entscheidung trifft welche Flash Bank angesprungen werden soll. Entsprechend muss das Mapping der Adressbereiche vom Bootloader vorgenommen werden:

Schauen wir uns zunächst den PIC32MZ an. Dieser hat neben dem Programmspeicher einen sogenannten Bootflash. Dieser ist unter anderem für den Bootloader reserviert. Bei einem Reset startet der PIC32MZ immer aus dem Bootflash. Zwar ist beim PIC32MZ ein Bootloader im Bootflash vorinstalliert, dieser führt allerdings immer einen Sprung in Bank 1 aus. Bei dieser Controllerfamilie muss also der Standard Bootloader (welcher von Microchip als SW-Projekt zur Verfügung gestellt wird) entsprechend angepasst werden.

Bei „dual-flash“ Varianten des STM32 sieht das Ganze etwas anders aus. Hier befindet sich ein vorinstallierter Bootloader im sogenannten „System Memory“. Dieser Bootloader entscheidet auf Grundlage des BFB2 („Boot from Bank 2“) Bits in den „Option Bytes“ darüber ob Bank 1 oder Bank 2 angesprungen werden soll. Die Option Bytes sind ebenfalls im Flash, werden also bei einem Reset nicht zurückgesetzt. Ist das BFB2 Bit gesetzt startet der Mikrocontroller nach einem reset zunächst in den vorinstallierten Bootloader, welcher dann wiederum die Applikation in Bank 2 startet. Ist das Bit gelöscht wird der Bootloader beim Start nicht durchlaufen und stattdessen die Applikation auf Bank 1 ausgeführt.

Man kann also bei Dual-Flash Varianten des STM32 auf einen Bootloader verzichten. Voraussetzung hierfür ist allerdings das nach einem Update auch eine Verifizierung des Speicherbereichs durchgeführt wird – man also kontrolliert, ob das Update erfolgreich war – bevor man das BFB2 Bit ändert. Zwar prüft beim ST auch der vorinstallierte Bootloader laut Application Note AN2606, ob Bank 2 „valid Code“ enthältBei dieser Überprüfung handelt es sich aber nicht um eine Check Summen-Überprüfung oder ähnliches. Anstatt dessen steht im Reference Manual des STM32L0X2 (RM0376): „The code is considered as valid when the first data located at the bank start address (which should be the stack pointer) points to a valid address (stack top address).“ Wurde das Update also fehlerhaft durchgeführt oder wird der Speicher nach erfolgreichem Update beschädigt, erkennt der Bootloader das nicht. Hinzukommt, wenn ein Update von Bank 2 auf Bank 1 durchgeführt wird, so dass hinterher der aktuelle Code in Bank 1 liegt, beim Start niemals eine Überprüfung durchgeführt wird. 

Ich muss also wie gesagt überprüfen, ob ich das Update korrekt durchgeführt habe, bevor ich das BFB2 Bit ändere. Das verhindert zumindest das direkt nach dem Update eine defekte FW angesprungen wird.

Fazit

Mikrocontroller mit 2 symmetrischen Flash Bänken ermöglichen intelligente Updatemethoden. Durch die zusätzliche Flash Bank kann eine Firmware ein Update ihrer selbst durchführen, ohne dabei Ihre übrigen Funktionen einstellen zu müssen.

Ein weiteres interessantes Plus dieser Technik: Ich habe für den Fall, dass die Firmware auf einer der beiden Flash Bänke im Feld beschädigt wird, immer noch eine ältere lauffähige Firmware als Ersatz gespeichert. Das heißt, selbst wenn Teile des Flashs beschädigt werden, stellt das System seine Arbeit nicht vollständig ein, sofern ich in der Lage bin diesen Defekt zu erkennen.

Man sollte allerdings erwähnen, dass das Ganze auch einen Nachteil hat. Ich muss mein System immer so auslegen das mein Mikrocontroller über den doppelten Flash Speicher verfügt, als meine Firmware mit einem klassischen Updateprozess benötigen würde. Diesen Speicher muss ich natürlich bezahlen.


Geschrieben von Björn Schmitz

Seit Juli 2017 gehöre ich zum MEDtech-Ingenieur Team und bin hier vor allem als Firmwareentwickler tätig. Schon in kürzester Zeit konnte ich an vielen spannenden Projekten aus dem Bereich Medizintechnik, aber auch aus anderen Bereichen mitwirken.


Weitere Beiträge

  • 25/09/2025
  • Allgemein, Elektrodermale Aktivität, Hardware, Produktion

Darf ich vorstellen? Das ist EDA – unsere Eule für elektrodermale AktivitätDas ist EDA, unsere kleine Eule mit einem besonderen Talent. EDA kann elektrodermale Aktivität (kurz: EDA) messen – ...

Weiterlesen
  • 09/09/2025
  • Allgemein, Software

In vorangegangenen Blogbeiträgen habe ich zwei wesentliche Komponenten einer einfachen und universell einsetzbaren Software-Architektur vorgestellt: Events mit Dispatcher, Listeners und Datapool. Damit lassen sich bereits sehr viele einfache Use-Cases ...

Weiterlesen
  • 19/03/2025
  • Allgemein, Unternehmen, Veranstaltungen

Wir freuen uns, euch zu einem exklusiven VDI-Event des Netzwerk Systems Engineering einzuladen, das bei uns im Büro stattfindet!Am Freitag, den 28. März 2025, wird sich alles um die ...

Weiterlesen
Cookie-Übersicht

Die Internetseiten der MEDtech Ingenieur GmbH verwenden Cookies. Cookies sind Textdateien, welche über einen Internetbrowser auf einem Computersystem abgelegt und gespeichert werden.

Zahlreiche Internetseiten und Server verwenden Cookies. Viele Cookies enthalten eine sogenannte Cookie-ID. Eine Cookie-ID ist eine eindeutige Kennung des Cookies. Sie besteht aus einer Zeichenfolge, durch welche Internetseiten und Server dem konkreten Internetbrowser zugeordnet werden können, in dem das Cookie gespeichert wurde. Dies ermöglicht es den besuchten Internetseiten und Servern, den individuellen Browser der betroffenen Person von anderen Internetbrowsern, die andere Cookies enthalten, zu unterscheiden. Ein bestimmter Internetbrowser kann über die eindeutige Cookie-ID wiedererkannt und identifiziert werden.

Durch den Einsatz von Cookies kann die MEDtech Ingenieur GmbH den Nutzern dieser Internetseite nutzerfreundlichere Services bereitstellen, die ohne die Cookie-Setzung nicht möglich wären.

Mittels eines Cookies können die Informationen und Angebote auf unserer Internetseite im Sinne des Benutzers optimiert werden. Cookies ermöglichen uns, wie bereits erwähnt, die Benutzer unserer Internetseite wiederzuerkennen. Zweck dieser Wiedererkennung ist es, den Nutzern die Verwendung unserer Internetseite zu erleichtern. Der Benutzer einer Internetseite, die Cookies verwendet, muss beispielsweise nicht bei jedem Besuch der Internetseite erneut seine Zugangsdaten eingeben, weil dies von der Internetseite und dem auf dem Computersystem des Benutzers abgelegten Cookie übernommen wird.

Die betroffene Person kann die Setzung von Cookies durch unsere Internetseite jederzeit mittels einer entsprechenden Einstellung des genutzten Internetbrowsers verhindern und damit der Setzung von Cookies dauerhaft widersprechen. Ferner können bereits gesetzte Cookies jederzeit über einen Internetbrowser oder andere Softwareprogramme gelöscht werden. Dies ist in allen gängigen Internetbrowsern möglich. Deaktiviert die betroffene Person die Setzung von Cookies in dem genutzten Internetbrowser, sind unter Umständen nicht alle Funktionen unserer Internetseite vollumfänglich nutzbar.

Weitere Informationen erhalten Sie in unserer Datenschutzerklärung.

Unbedingt notwendige Cookies

Dieses Cookie wird benötigt, um Ihre Cookie-Einstellungen zu merken und weitere Hauptfunktionen zur Verfügung zu stellen

Um Ihnen eine Auskunft über Ihre gespeicherten personenbezogenen Daten hier (https://medtech-ingenieur.de/gespeicherte-daten-2/) geben zu können, benötigen wir einen Cookie, um Sie bei der Datenabfrage identifizieren zu können. Dieser Cookie muss aus Sicherheitsgründen deshalb aktiviert sein. Ein weiterer Cookie wird gesetzt, um diesen Banner nicht erneut anzeigen zu müssen.

Cookie-Name Beschreibung
PHPSESSID Name: PHP session
Anbieter:
Eigentümer der Webseite (MEDtech Ingenieur)
Zweck:
Wir benötigt, um Sie bei der Anfrage von personenbezogenen Daten identifizieren zu können. Das Cookie wird nur gesetzt, wenn Sie eine Anfrage hier (https://medtech-ingenieur.de/gespeicherte-daten-2/) stellen.
Laufzeit: Sitzungsende
Kategorie: Unbedingt notwendige Cookies
moove_gdpr_popup Name: Cookie-Box Einstellungen
Anbieter:
Eigentümer der Webseite (MEDtech Ingenieur)
Zweck:
Wird benötigt, um Ihre Cookie-Einstellungen zu speichern, um den Cookie-Banner nicht erneut anzeigen zu müssen.
Laufzeit: 1 Jahr
Kategorie: Unbedingt notwendige Cookies
comment_author_9c90e388e3e1be4a6c594fa6ac8a3eec
comment_author_email_9c90e388e3e1be4a6c594fa6ac8a3eec
comment_author_url_9c90e388e3e1be4a6c594fa6ac8a3eec
Name: Kommentar Einstellungen
Anbieter:
Eigentümer der Webseite (MEDtech Ingenieur)
Zweck:
Cookie wird angelegt, wenn Sie ein Kommentar auf MEDtech Ingenieur veröffentlichen wollen, um Sie als Autor identifizieren und den aktuellen Status Ihres Kommentars anzeigen zu können. Das Cookie enthält den angegebenen Namen. Das Cookie wird erst gesetzt, wenn Sie der Speicherung Ihrer personenbezogenen Daten zustimmen.
Laufzeit: 1 Jahr
Kategorie: Unbedingt notwendige Cookies
rmp-rate Name: RMP Rate
Anbieter: Eigentümer der Webseite (MEDtech Ingenieur)
Zweck: Cookie wird angelegt, wenn Sie eine Bewertung eines Blogbeitrags mithilfe des Sternebewertungssystems abgeben. Ihnen wird eine anonymisierte ID zugewiesen, um zu erkennen, ob Sie einen Artikel bereits bewertet haben oder nicht. Das Cookie wird nur verwendet, um zu verhindern, dass mehrfache Bewertung abgegeben werden und erst gesetzt, wenn Sie auf einen Stern klicken.
Laufzeit: 1 Jahr
Kategorie: Unbedingt notwendige Cookies
medtech-download-page Name: Download Page
Anbieter: Eigentümer der Webseite (MEDtech Ingenieur)
Zweck: Cookie wird angelegt, wenn Sie den Landing-Page Prozess erfolgreich durchlaufen haben. Dies geschieht nur, wenn Sie einen Content-Download von unserer Website anstreben.
Laufzeit: 1/2 Jahr
Kategorie: Unbedingt notwendige Cookies