VersaMCU/bootloader
Julian Appel 01c5e0930e Guard env:versapad's upload against overwriting the bootloader
pio run -e versapad --target upload writes the app starting at
0x0000 and silently destroyed the installed UF2 bootloader twice
today during testing -- no warning, no error, just a board that
stopped responding to the boot-key hold.

upload_openocd.py now checks for the bootloader (verify_image against
the locally built bootloader/.pio/build/versapad_bootloader/firmware.bin)
before an env:versapad upload and refuses if one is present, pointing
at env:versapad_usb instead. Fails closed: an inconclusive check (e.g.
bootloader not built locally, SWD not responding) blocks rather than
proceeding on a guess -- confirmed necessary the hard way, since a
"fail open" first attempt let the destructive upload through silently.
Scoped to PIOENV == "versapad" only, since bootloader/platformio.ini's
own upload reuses this same script and must always be allowed to write
0x0000. A new erase-bootloader-and-flash custom target remains as the
explicit, deliberate override.

Documented the workflow (bootloader is its own PlatformIO project,
flashed once via SWD; versapad_usb is the normal path afterward;
versapad's upload is now guarded) in README.md and
doc/10_usb_bootloader.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-05 23:27:02 +02:00
..
boards Add UF2 bootloader for USB firmware flashing 2026-08-03 20:56:58 +02:00
inc Add UF2 bootloader for USB firmware flashing 2026-08-03 20:56:58 +02:00
include Fix bootloader hardware bring-up and add key-based boot entry 2026-08-05 21:28:15 +02:00
lib Add UF2 bootloader for USB firmware flashing 2026-08-03 20:56:58 +02:00
scripts Add UF2 bootloader for USB firmware flashing 2026-08-03 20:56:58 +02:00
src Fix bootloader hardware bring-up and add key-based boot entry 2026-08-05 21:28:15 +02:00
.gitignore Guard env:versapad's upload against overwriting the bootloader 2026-08-05 23:27:02 +02:00
LICENSE-uf2-samdx1 Add UF2 bootloader for USB firmware flashing 2026-08-03 20:56:58 +02:00
platformio.ini Add UF2 bootloader for USB firmware flashing 2026-08-03 20:56:58 +02:00
README.md Fold bootloader documentation into the main doc/ index 2026-08-05 22:49:56 +02:00

VersaMCU UF2-Bootloader

USB-Bootloader für das VersaPad-v2-Makropad. Wird per Atmel-ICE/SWD einmalig auf den ATSAMD21G17D geflasht und belegt 0x0000..0x1FFF (8 KiB). Danach lässt sich die App-Firmware ohne SWD über USB aktualisieren.

Speicherlayout, Bootloader-Aktivierung, Bedienung und Hardwaretest-Ergebnisse stehen in ../doc/10_usb_bootloader.md. Diese Datei beschreibt nur das Bootloader-Unterprojekt selbst.

Herkunft

Abgeleitet und stark eingekürzt aus microsoft/uf2-samdx1 (MIT-Lizenz, siehe LICENSE-uf2-samdx1). Übernommen wurden nur die SAMD21-Bootloader-Sourcen (src/, inc/), die zugehörigen CMSIS-/ASF-Header für genau den SAMD21G17A-Chip (lib/) sowie das Linkerskript, angepasst auf den 128-KiB-Flash/16-KiB-RAM-Chip auf diesem Board (Original-Vorlagen zielen auf 256-KiB-Chips wie den SAMD21G18A). Board-Vorlage war boards/gemma_m0 aus dem Original-Repo (crystalless, gleiche USB_VID wie unser Board).

Nicht übernommen: SAMD51/SAME54-Support, der Bootloader-Selbstupdate-Pfad (selfmain.c, sketch.cpp, das python2-Tooling uf2conv.py/gendata.py) und das Node-/Makefile-basierte Build-System — stattdessen ein eigenständiges PlatformIO-Environment, damit dasselbe Tooling wie für die App-Firmware ausreicht.

Für die App-Seite (nicht diesen Bootloader-Build) gibt es unter ../uf2conv.py eine eigene, minimale Python-3-Neuimplemen- tierung des .bin.uf2-Konverters (kein Upstream-Code, passendes Blockformat zu inc/uf2format.h), eingebunden über ../upload_uf2.py als env:versapad_usb-Upload-Hook.

Build

cd bootloader
pio run -e versapad_bootloader

Flash (Atmel-ICE/SWD, einmalig, überschreibt ggf. vorhandene App-Firmware nicht,

da nur 0x0000..0x1FFF beschrieben wird)

pio run -e versapad_bootloader --target upload

Achtung bei manuellem SWD-Flashen von Bootloader UND App

upload_openocd.py (App, env:versapad) und der Bootloader-Upload (oben) sind sicher, weil sie jeweils nur ihren eigenen Bereich anfassen. Beim manuellen Debuggen über OpenOCD-Kommandozeile aber Vorsicht:

openocd -c "program datei.elf verify" ohne explizite Zieladresse hat sich in dieser Kombination aus OpenOCD-Version/CMSIS-DAP-Adapter/Target-Skript als unzuverlässig erwiesen — statt die im ELF hinterlegten Sektionsadressen (0x2000 für die App) zu nutzen, landeten die rohen Datei-Bytes teils direkt ab Flash-Adresse 0x0000 und haben damit den frisch geschriebenen Bootloader sofort wieder überschrieben (bestätigt am 2026-08-05: Byte 0 an Adresse 0x0000 war 0x7f, der Beginn der ELF-Magic \x7fELF — die rohe Datei, kein Firmware-Code). Passierte zuverlässig, wenn Bootloader- und App-Flash im selben OpenOCD-Aufruf kombiniert wurden.

Regel für manuelles SWD-Flashen beider Bereiche: immer die .bin-Datei verwenden (nie .elf) und die Zieladresse immer explizit angeben (program firmware.bin 0x0 verify für den Bootloader, program firmware.bin 0x2000 verify für die App), und Bootloader- und App-Schreibvorgang in getrennten OpenOCD-Aufrufen, nicht in einer gemeinsamen -c-Kommandokette. Im Zweifel danach mit dump_image in einer frischen, unabhängigen Sitzung verifizieren.