Bootloader selber schreiben: Firmware-Updates ohne Programmer ermöglichen

Einen Bootloader selber schreiben ist eine der wirkungsvollsten Maßnahmen, um Firmware-Updates ohne Programmer zu ermöglichen – sei es im Labor, im Feld oder bei Geräten, die nach dem Einbau schwer zugänglich sind. Statt jedes Update per PICkit oder Snap einzuspielen, kann das Zielsystem neue Firmware über UART, USB, CAN, SPI, I²C oder sogar über ein Dateisystem beziehen und sich selbst programmieren. Genau hier liegt aber auch die Herausforderung: Ein Bootloader greift in den sensibelsten Bereich Ihres Systems ein – in die Programmspeicherverwaltung, das Reset-Verhalten und die Startlogik. Fehler wirken sich sofort aus: Im schlimmsten Fall „bricken“ Sie das Gerät, weil weder Bootloader noch Anwendung sauber starten. In diesem Artikel lernen Sie einen praxiserprobten Ansatz, wie Sie einen Bootloader für PIC-Controller strukturiert planen und umsetzen: mit sauberem Speicherlayout, sicherer Update-Logik, Integritätsprüfung, Fail-Safe-Strategien und einem Workflow, der in MPLAB X/XC8 reproduzierbar bleibt. Dabei steht nicht „magischer Code“ im Vordergrund, sondern ein klares Konzept, das Sie an Ihre PIC-Familie (PIC16/PIC18 oder 16-/32-Bit) und Ihre Schnittstelle anpassen können.

Was ist ein Bootloader – und welche Aufgaben muss er wirklich erfüllen?

Ein Bootloader ist eine kleine Firmware, die beim Reset zuerst läuft, eine Update-Schnittstelle bereitstellt und anschließend die eigentliche Anwendung startet. Entscheidend ist die Trennung der Rollen: Der Bootloader ist nicht die „zweite Anwendung“, sondern ein minimaler, stabiler Kern, der Updates sicher durchführt.

  • Startentscheidung: Soll die Anwendung starten oder soll in den Update-Modus gewechselt werden?
  • Kommunikation: Firmware-Daten empfangen (z. B. UART-Protokoll, USB HID, CAN, I²C, SPI).
  • Speicherprogrammierung: Flash (Program Memory) löschen und schreiben, oft block-/seitenweise.
  • Verifikation: Daten prüfen (z. B. CRC), um Übertragungsfehler zu erkennen.
  • Übergabe: Sprung in die Anwendung (Reset-/Interrupt-Vektoren korrekt behandeln).

Microchip beschreibt diesen Grundgedanken sehr klar: Ein Bootloader ist eine kleine Anwendung, die Firmware-Upgrades ermöglicht, ohne dass ein externer Programmer benötigt wird (MPLAB Harmony 3 Bootloader Library – Überblick).

Voraussetzungen: Kann Ihr PIC sich selbst programmieren?

Ein Bootloader steht und fällt mit der Fähigkeit zur Selbstprogrammierung (Self-Programming). Viele PIC-Familien unterstützen das, aber die Details unterscheiden sich: Schreib- und Löschgranularität, Schutzmechanismen, erforderliche Schlüssel-Sequenzen sowie die Frage, ob Code während des Schreibens weiterlaufen darf. Bei 16-Bit-PICs (z. B. PIC24/dsPIC) sind Schutzmechanismen wie NVMKEY und NVMWREN typisch; Microchip beschreibt diese Lock-out-Mechanismen in den Flash-Programming-Kapiteln (z. B. NVMWREN/NVMKEY) sehr deutlich (Flash Programming – Schutzmechanismen (PDF)).

  • Flash-Row/Page-Struktur: Sie schreiben meist eine „Row“ oder „Page“ am Stück, nicht beliebige Bytes.
  • Erase vor Write: Erase setzt Zellen auf 1, Write programmiert 0 (geräteabhängig).
  • Code Protection: Kann Erase/Write blockieren oder bestimmte Befehle ignorieren.

Ein gutes Beispiel für die notwendige Row-/Panel-Logik zeigt Microchip in den Memory-Programming-Dokumenten für PIC18K42: Flash wird rowweise programmiert, und Erase/Write haben definierte Granularitäten (PIC18K42 Memory Programming – Row/Erase/Write (PDF)).

Speicherlayout planen: Bootloader-Region, Applikations-Region und Vektoren

Der wichtigste Designschritt passiert vor dem ersten Code: das Speicherlayout. Der Bootloader muss in einem reservierten Bereich liegen, der nicht durch Updates überschrieben wird. Die Anwendung muss in einem separaten Bereich beginnen, und Sprung-/Vektorlogik muss zu dieser Aufteilung passen. Viele Bootloader-Fehler entstehen, weil diese Grenzen „irgendwie“ gewählt werden, statt bewusst und dokumentiert.

Minimalmodell: ein gemeinsamer Flash-Bereich mit fester Bootloader-Größe

  • Bootloader am Flash-Anfang: häufig bei 8-Bit-PICs, weil Reset-Vektor standardmäßig am Anfang liegt.
  • Anwendung mit Offset: Startadresse der Applikation liegt nach dem Bootloader.
  • Vektorumleitung: Reset- und Interrupt-Vektoren müssen zur Applikation weiterleiten oder in die Applikation „verlegt“ werden.

Microchip geht in klassischen Bootloader-Appnotes genau auf dieses Thema ein und zeigt, wie ein Bootloader in PIC16/PIC18-Familien so platziert wird, dass die Anwendung nur einen Teil des Programmspeichers nutzt (AN1310: High-Speed Bootloader für PIC16/PIC18 (PDF)). Auch AN851 ist eine grundlegende Referenz, die die Speicheraufteilung und den Bootloader-Ablauf für PIC16/PIC18 demonstriert (AN851: A Flash Bootloader for PIC16/PIC18 (PDF)).

Dual-Bank-Ansatz: Updates ohne Risiko eines „Bricks“

Wenn Ihr PIC Dual-Bank-Flash oder eine ähnliche Architektur bietet, können Sie eine neue Firmware in eine zweite Bank schreiben und erst nach erfolgreicher Verifikation umschalten. Das ist eine der sichersten Strategien, weil ein unterbrochenes Update die alte Bank unberührt lässt. Solche Konzepte werden häufig in Bootloader-Frameworks für leistungsfähigere Controller umgesetzt; die MPLAB Harmony 3 Bootloader-Dokumentation enthält auch Live-Update-Varianten auf Geräten mit Dual-Bank-Unterstützung (Harmony 3 Bootloader Beispiele – Live Update/Dual Bank (Online Docs)).

Update-Einstieg: Wie entscheidet der Bootloader zwischen Update und Anwendung?

Die Einstiegskriterien müssen robust und benutzerfreundlich sein. „Beim Reset immer 3 Sekunden warten“ ist einfach, aber oft unpraktisch. Besser ist ein klarer Trigger, der auch im Feld zuverlässig funktioniert.

  • Hardware-Pin: Ein definierter „BOOT“-Pin wird beim Reset gedrückt/gesetzt.
  • Magic-Flag in RAM: Die Anwendung setzt vor einem Soft-Reset ein Flag (nur sinnvoll, wenn Reset RAM nicht initialisiert oder Sie ein spezielles RAM-Fenster nutzen).
  • EEPROM/Flash-Flag: Die Anwendung schreibt einen „Update requested“-Marker und resettet; Bootloader löscht den Marker nach Eintritt.
  • Kommunikations-Handshake: Bootloader wartet kurz auf ein Startpaket; kommt nichts, startet er sofort die Anwendung.

In der Praxis bewährt sich eine Kombination: kurzer Handshake-Timeout plus optionaler Hardware-Pin. So bleibt der Boot schnell, und Sie haben trotzdem eine sichere „Rettungsleine“.

Kommunikationsprotokoll: Einfach, robust, prüfbar

Ein Bootloader-Protokoll muss weniger können als ein vollständiges Applikationsprotokoll, aber es muss extrem robust sein. Typische Anforderungen: Framing (Start/Stop), Blocknummern, Längenfelder, Fehlerbehandlung und Wiederholmechanismen. Viele Entwickler orientieren sich an Intel HEX (textbasiert) oder an binären Blockformaten (effizienter). Microchip-Bootloader-Appnotes wie AN1310 beschreiben serielle Protokolle, mit denen ein Host Updates lesen, schreiben und verifizieren kann (AN1310 – Protokoll und Ablauf (PDF)).

CRC statt „nur Checksumme“

Für Integrität empfiehlt sich eine CRC, weil sie typische Bitfehler und Burstfehler besser erkennt als eine einfache Summe. Eine gängige CRC-16 lässt sich in Bootloadern oft noch gut unterbringen (Codegröße). Die CRC wird pro Block oder über das gesamte Image berechnet. Die grundlegende CRC-Update-Logik lässt sich allgemein so beschreiben:

CRC = Update(CRC,Byte)

Wichtig ist weniger die konkrete Polynomwahl (die muss zu Ihrem Host-Tool passen), sondern die Konsequenz: Ohne integritätsgesicherte Updates ist ein „Firmware-Update ohne Programmer“ nur scheinbar komfortabel, in der Praxis aber riskant.

Flash-Programmierung: Erase- und Write-Granularität bestimmen die Architektur

Der Bootloader schreibt nicht „einfach Bytes“, sondern muss die Flash-Granularität respektieren. Bei vielen PIC18-Geräten ist das Row- oder Block-Programming typisch: Sie laden Daten in Latches/Buffer, löschen die Zielregion und starten dann eine Programmierroutine. Microchip dokumentiert diese Abläufe ausführlich in Memory-Programming-Guides, etwa für PIC18K42 mit Multi-Word-Interface und Row-Erase/Row-Write (PIC18K42 Memory Programming – Multi-Word und Row-Operationen (PDF)).

Praktische Konsequenzen für Ihr Bootloader-Design

  • Blockgröße = Protokollblock: Richten Sie Ihr Übertragungsformat möglichst an der Flash-Row aus, um Puffer zu sparen.
  • Zwischenspeicher: Wenn Protokollblöcke kleiner sind als Flash-Rows, brauchen Sie einen RAM-Puffer zum Auffüllen.
  • Keine Selbstüberschreibung: Der Bootloader darf niemals in seine eigene Region schreiben oder löschen.
  • Interrupts bewusst behandeln: Während kritischer Flash-Sequenzen können Interrupts stören; Design muss das berücksichtigen.

Reset- und Interrupt-Vektoren: Der Klassiker unter den Stolperfallen

Bei vielen 8-Bit-PICs liegen Reset- und Interrupt-Vektoren an festen Adressen. Wenn Ihre Anwendung nicht bei Adresse 0 beginnt, müssen Sie die Vektoren umleiten oder „trampolines“ verwenden. Genau hier scheitern viele erste Bootloader-Versuche: Die Anwendung ist korrekt geflasht, aber springt nach Reset in den Bootloader zurück oder landet bei einem Interrupt an der falschen Stelle.

  • Reset-Vektor: Bootloader startet an der Standardadresse und springt dann zur Applikations-Startadresse.
  • Interrupt-Vektor: Bootloader implementiert eine Weiterleitung zur Applikations-ISR oder nutzt eine remappte Vektorstruktur (geräteabhängig).
  • Linker-Skript/Memory-Settings: Applikation muss so gelinkt werden, dass sie nicht in die Bootloader-Region schreibt.

In Microchip-Referenz-Bootloadern (z. B. AN851/AN1310) wird dieses Thema als zentraler Bestandteil der Implementierung behandelt, weil es für PIC16/PIC18 unterschiedlich gelöst werden kann (AN851 – Bootloader-Design und Vektoren (PDF)).

Fail-Safe-Strategien: So verhindern Sie „Bricks“ bei Update-Abbruch

Ein professioneller Bootloader ist nicht der, der „Updates kann“, sondern der, der auch bei Fehlern sicher bleibt. Häufige Fehlerquellen sind Spannungseinbrüche, abgebrochene Verbindungen, falsche Images oder falsche Zielgeräte.

Bewährte Sicherheitsmechanismen

  • Image-Header: Enthält Magic, Version, Zielgerät/ID, Länge, CRC.
  • Schreibreihenfolge: Erst Daten schreiben, am Ende ein „Image valid“-Marker setzen.
  • Rollback: Bei Dual-Bank: erst nach kompletter Verifikation umschalten.
  • Timeout und Wiederaufnahme: Bootloader bleibt bei Fehlern im Update-Modus, statt „halb zu starten“.
  • Watchdog bewusst nutzen: WDT kann gegen Hänger schützen, muss aber zum Protokoll passen (keine ungewollten Resets während Transfer).

Wenn Sie nur eine Bank haben, ist der „Valid-Marker“ besonders wichtig: Sie möchten die Anwendung erst starten, wenn klar ist, dass ein vollständiges, verifiziertes Image im Flash liegt.

Host-Tooling: Ohne zuverlässigen PC/Host-Teil ist der Bootloader nur die halbe Lösung

Bootloader-Projekte scheitern oft nicht am Embedded-Code, sondern am Host-Tool: Paketformat, Timing, Retries, COM-Port-Handling, Fehlerreporting. Ein guter Host kann:

  • das Ziel identifizieren (Handshake, Versionsabfrage),
  • die Firmware in Blöcken übertragen,
  • Fehler erkennen und Blöcke wiederholen,
  • nach dem Update verifizieren (CRC oder Readback, wenn erlaubt).

Wenn Sie nicht alles selbst bauen möchten, lohnt ein Blick auf Microchips Bootloader-Ökosystem. Microchip stellt Bootloader-Frameworks und Dokumentation bereit, mit denen sich Bootloader-Firmware generieren bzw. aufsetzen lässt (Microchip Bootloaders – Übersicht).

Selbst schreiben oder Framework nutzen: eine pragmatische Entscheidung

„Bootloader selber schreiben“ heißt nicht, dass Sie alles neu erfinden müssen. Oft ist der beste Weg: einen Referenz-Bootloader als Grundlage nehmen und ihn kontrolliert anpassen. Für PIC16/PIC18 sind AN851 und AN1310 klassische Startpunkte (AN851 (PDF), AN1310 (PDF)). Für größere PIC-/SAM- oder 32-Bit-Projekte ist Harmony 3 häufig eine solide Basis, inklusive Bootloader Library und Beispielen (MPLAB Harmony 3 Bootloader Repository).

Wann ein eigener Bootloader sinnvoll ist

  • Sie brauchen ein sehr kleines Image (Codegröße kritisch) und ein maßgeschneidertes Protokoll.
  • Sie haben spezielle Sicherheitsanforderungen (Signaturen, Secure Boot, Schlüsselverwaltung).
  • Sie müssen eine vorhandene Infrastruktur (z. B. proprietäres Feldbus-Protokoll) nutzen.

Wann ein Framework sinnvoll ist

  • Schneller Start, dokumentierte Beispiele, weniger Risiko bei Speicherlayout und Update-Logik.
  • Mehrere Update-Kanäle (UART, USB, CAN, File System) sollen unterstützt werden.
  • Teamarbeit und Wartbarkeit stehen im Vordergrund.

Sicherheit: Firmware-Authentizität statt nur Integrität

CRC stellt sicher, dass Daten korrekt übertragen wurden. Sie verhindert aber nicht, dass eine „falsche“ oder manipulierte Firmware eingespielt wird. Wenn Ihr Produkt im Feld updatefähig ist, sollten Sie über Authentizität nachdenken:

  • Signaturen: Firmware wird kryptografisch signiert; Bootloader akzeptiert nur gültige Signaturen.
  • Versionsschutz: Downgrade verhindern (Anti-Rollback), um bekannte Sicherheitslücken nicht wieder einzuspielen.
  • Schlüsselmanagement: Public Key im Bootloader, private Keys nur im Build-System.

Der konkrete Sicherheitsumfang hängt stark von Device-Fähigkeiten und Bedrohungsmodell ab. Dennoch ist es sinnvoll, schon beim Bootloader-Layout Platz für einen Header mit Signaturfeldern vorzusehen, selbst wenn Sie zunächst „nur“ CRC implementieren.

Typische Fehler und schnelle Diagnosen

  • Bootloader startet, aber Anwendung nie: Startadresse falsch, Valid-Marker fehlt, Vektorumleitung fehlerhaft.
  • Update läuft, aber Gerät ist danach „tot“: Bootloader-Region überschrieben, Erase/Write-Grenzen verletzt, falsches Linker-Layout.
  • Updates brechen sporadisch ab: Protokoll ohne Retries, Timeout zu aggressiv, UART-Fehler/Clock-Mismatch.
  • Verifikation schlägt fehl: Blockreihenfolge stimmt nicht, CRC-Implementierung auf Host/Target unterschiedlich, Byteorder-Fehler.
  • Gerät reagiert nicht mehr auf Update-Modus: Eintrittsbedingung zu schwach (z. B. zu kurzer Timeout), fehlender Hardware-Trigger.

Praxis-Checkliste: Bootloader-Implementierung in klaren Schritten

  • Speicherlayout definieren: Bootloader-Region fest reservieren, Applikations-Startadresse festlegen, Vektorkonzept planen.
  • Eintrittslogik robust gestalten: Hardware-Pin oder verlässlicher Marker plus kurzer Handshake-Timeout.
  • Protokoll minimal, aber robust: Framing, Länge, Sequenz/Blocknummer, Retries, eindeutige Fehlercodes.
  • Flash-Granularität respektieren: Row/Page-Größen aus Datenblatt ableiten, Pufferkonzept aufbauen.
  • Integrität prüfen: CRC pro Block oder Image-CRC, Verifikation nach dem Schreiben.
  • Fail-Safe umsetzen: „valid“-Marker erst am Ende setzen, bei Fehlern im Bootloader bleiben, optional Dual-Bank nutzen.
  • Host-Tool stabil bauen: Logging, Wiederholungen, Abbruchbehandlung, eindeutige Statusanzeigen.
  • Service-Weg offen halten: ICSP-Header/Testpads als Rettungsanker einplanen, solange möglich.

Weiterführende Outbound-Links: Referenzen und Frameworks für Bootloader-Projekte

IoT-PCB-Design, Mikrocontroller-Programmierung & Firmware-Entwicklung

PCB Design • Arduino • Embedded Systems • Firmware

Ich biete professionelle Entwicklung von IoT-Hardware, einschließlich PCB-Design, Arduino- und Mikrocontroller-Programmierung sowie Firmware-Entwicklung. Die Lösungen werden zuverlässig, effizient und anwendungsorientiert umgesetzt – von der Konzeptphase bis zum funktionsfähigen Prototyp.

Diese Dienstleistung richtet sich an Unternehmen, Start-ups, Entwickler und Produktteams, die maßgeschneiderte Embedded- und IoT-Lösungen benötigen. Finden Sie mich auf Fiverr.

Leistungsumfang:

  • IoT-PCB-Design & Schaltplanerstellung

  • Leiterplattenlayout (mehrlagig, produktionstauglich)

  • Arduino- & Mikrocontroller-Programmierung (z. B. ESP32, STM32, ATmega)

  • Firmware-Entwicklung für Embedded Systems

  • Sensor- & Aktor-Integration

  • Kommunikation: Wi-Fi, Bluetooth, MQTT, I²C, SPI, UART

  • Optimierung für Leistung, Stabilität & Energieeffizienz

Lieferumfang:

  • Schaltpläne & PCB-Layouts

  • Gerber- & Produktionsdaten

  • Quellcode & Firmware

  • Dokumentation & Support zur Integration

Arbeitsweise:Strukturiert • Zuverlässig • Hardware-nah • Produktorientiert

CTA:
Planen Sie ein IoT- oder Embedded-System-Projekt?
Kontaktieren Sie mich gerne für eine technische Abstimmung oder ein unverbindliches Angebot. Finden Sie mich auf Fiverr.

 

Related Articles