Long-range architectural sketch, filed now so it's documented rather than living in my head. Nothing here should be built before FPGA SPI3 data acquisition is working and v1.0 is in sight. This is a post-v1.0 vision for how the project makes the jump from "replacement firmware for a specific scope" to "platform for handheld instruments."
Three layers, each solving a different problem. They compose together but can be built independently and incrementally.
Layer 1 — WebUSB flasher (distribution)
Problem: How do non-developers get firmware onto the device? Right now the first-flash path requires either dfu-util (Mac/Linux, Homebrew or apt install), Zadig + dfu-util (Windows, painful), or Artery ISP Programmer (Windows-only GUI, thanks to @michkovitalik for documenting this path on #4). No path works for all users without install friction.
Proposal: Host a browser-based flasher at something like https://davidclawson.github.io/OpenScope-2C53T/flash/. User visits URL in Chrome or Edge, walks through the BOOT0 + reset physical step with photos/video, clicks Connect, and the browser talks DFU directly to the AT32 ROM bootloader over WebUSB. The page fetches the latest release binaries from GitHub, handles the option-byte write (224 KB SRAM), then writes the bootloader and application firmware.
Existing library to build on: WebDFU — MIT-licensed JavaScript port of dfu-util, known to work with standard DFU devices. The AT32 ROM bootloader is DFU-compliant so it should work with minimal adaptation.
What this unlocks:
- Zero install, identical UX on Mac / Linux / Windows / ChromeOS
- Works for users who have never installed a toolchain in their lives (the Home Assistant / maker / hobbyist crowd)
- Distribution is a URL, not a PyPI package or a platform-specific installer
- One canonical first-flash path replaces three OS-specific walkthroughs
Tradeoffs:
- Chrome/Edge only. No Firefox, no Safari. Real limitation but overlap with "people who flash embedded devices" is very high.
- HTTPS required (GitHub Pages handles this free)
- Doesn't eliminate the physical BOOT0 + pinhole reset step for the very first flash — only software install friction
- ~1 weekend of focused work to build well, not a single session
A Python flasher CLI was previously under consideration for the same problem. WebUSB dominates on every axis that matters for end users — no install, no code signing, works on ChromeOS, URL-based distribution. A Python version might still have value for CI or automation, but it's no longer the primary play.
Layer 2 — SPI flash boot slots (installation)
Problem: Once WebUSB is working, the next question is: how does a user switch between different firmwares without re-entering ROM DFU mode or reflashing? Today, switching firmwares means a full flash cycle.
Proposal: Use the 16 MB Winbond W25Q128JVSQ SPI flash to store multiple complete firmware images in "slots," with a boot selector that copies the chosen slot into MCU flash at boot time. The application is only ~210 KB, so even 6 slots at ~2 MB each is extravagant.
Sketch layout:
MCU flash (1 MB, unchanged):
0x08000000 Bootloader (16 KB, permanent)
0x08003800 Upgrade flag sector (2 KB) — extend with "boot target" field
0x08004000 Active firmware (1008 KB) — whichever slot is currently "live"
SPI flash (16 MB, new regions):
0x000000 UI assets (current usage, unchanged)
0x400000 Slot metadata table (64 KB) — names, versions, CRCs, valid flags
0x500000 Slot 0 firmware image (~2 MB)
0x700000 Slot 1 firmware image
0x900000 Slot 2 firmware image
... up to 6 slots in the remaining space
Boot flow:
- Bootloader reads "boot target" flag from the upgrade flag sector
- If slot=N: copies SPI slot N → MCU flash
0x08004000 (only if it has changed since last boot, to minimize writes)
- Jumps to MCU flash
0x08004000 as normal
- If slot=active (default): jumps directly without copying
User-facing surface:
- New Settings → Boot Slot menu, lists slots by name and version ("Automotive v0.3", "Stock Scope v1.0", "Ham Lab v0.1")
- Hold a specific button at power-on to enter the slot selector directly (power-user shortcut)
- Selector can mark slots as invalid (bad CRC) and skip them
What this unlocks when combined with Layer 1:
Once a device has v1.0+ installed, the WebUSB flasher can write new builds to SPI slots over the HID bootloader path — no ROM DFU mode, no case opening, no BOOT0 jumper. The user visits the flasher page, picks a build, picks a slot, clicks install. Their existing firmware stays in its slot, unchanged. They can flip between slots on demand from the boot menu.
This is the mechanism that makes the platform vision real: the same $75 hardware becomes multiple different instruments based on which slot is active, and switching between them is a reboot, not a reflash.
Why this specific hardware is well-suited:
- Massive underused SPI flash (most of 16 MB is empty)
- Existing HID bootloader can be extended incrementally rather than replaced
- Existing 3-strike crash recovery + ROM DFU ultimate escape hatch still apply per-slot
- Slot corruption never bricks the device — bootloader skips invalid slots and falls back to active
Incremental implementation path:
- Phase 1: hardcode "boot from slot 0 if present, else MCU flash active." Tests the mechanism with a single slot.
- Phase 2: metadata table + slot selector UI
- Phase 3: web flasher integration (write to arbitrary slot over HID bootloader)
Each phase is independently useful.
Caveats:
- SPI NOR flash has ~100k erase cycles per sector. Occasional slot updates are fine. Design must avoid writing metadata on every boot.
- First-flash bootstrap is unchanged — the very first firmware still arrives via ROM DFU. The slot system is an upgrade path for devices that already have v1.0+.
- Don't write a custom bootloader for this. Extend the existing HID bootloader. Every new bootloader feature is a new way to brick users.
Layer 3 — Module packs (customization)
Problem: How does one firmware become different instruments? Different users want fundamentally different things from the same hardware — automotive diagnostics, HVAC commissioning, ham radio measurements, education, bench tools, component testing.
Proposal: Do NOT build separate firmware binaries per vertical. Build one universal firmware plus a library of module packs that customize it. A pack is:
- A set of JSON procedure files (existing
modules/ directory seeds this with automotive, HVAC, ham radio, education)
- A default theme
- A menu layout preset (which features are prominent)
- Optional welcome screen / branding
- Default settings for that vertical
Why not separate binaries:
|
Separate firmwares per vertical |
One firmware + module packs |
| Binaries to maintain |
5-10 |
1 |
| Test matrix |
Explodes combinatorially |
Stays flat |
| Switch verticals |
Reflash |
Pick a module |
| Contributor burden |
"Which build do I target?" |
"Just add a module" |
| Fits in flash? |
Only with work |
Already does (~210 KB used of 1 MB) |
| Mixes verticals |
Impossible |
Free |
The 2C53T has ~800 KB of unused MCU flash and ~14 MB of unused SPI flash. There is no physical reason to fragment the firmware across builds.
The UX is still what feels like picking a specialized tool: the web flasher in Layer 1 bundles "firmware + pack" as a single install operation, so the user picks "Automotive" and gets a device that boots into an automotive-focused UI. Under the hood it's the universal firmware with an automotive module pack loaded into SPI flash.
How the three layers compose
Web flasher (Layer 1)
↓ delivers to
SPI flash boot slot (Layer 2)
↓ configured with
Module pack (Layer 3)
↓ produces
A specific instrument (automotive scan tool, ham radio analyzer, bench scope, ...)
Each layer solves a different problem:
- Layer 1 solves: How do non-developers get firmware onto the device?
- Layer 2 solves: How do multiple firmwares coexist without reflashing?
- Layer 3 solves: How does one firmware become many different instruments?
Together, they turn the project from "replacement firmware for a specific scope" into an open platform for handheld instruments. Separate Layer 1/2/3 work is each useful in isolation, but the combination is what makes the WRT54G/OpenWrt analogy concrete for this hardware.
Priority order and scheduling
Do not build any of this before FPGA SPI3 data acquisition is working. The scope must actually scope before distribution and platform work has any leverage. Pre-v1.0, all of this is premature.
Signal to reconsider: FPGA SPI3 flowing reliably + v1.0 in sight + continued external user interest. At that point, the WebUSB flasher is the highest-leverage next move because it unlocks the non-developer audience and makes Layers 2 and 3 reachable.
Priority order when we build:
- Layer 1 WebUSB flasher — unlocks non-developer audience, ~1 weekend of work
- Layer 2 Phase 1 (hardcoded single slot) — tests the boot-copy mechanism
- Layer 2 Phase 2 (selector UI + metadata table)
- Web flasher → slot integration (Layer 1 × Layer 2) — the moment secondary builds become zero-friction
- Pack bundling in the web flasher (Layer 3) — first-class multi-vertical experience
Related signals
The demand signal for easier cross-platform flashing has already arrived this week, across three operating systems in two days:
Three of the first four external users hit first-flash friction. That's the confirmation that the distribution layer matters — the remaining gate is just FPGA SPI3 working so there's something worth flashing easily.
Not in scope for this issue
- Building anything. This is a design note, not an implementation ticket.
- FPGA SPI3 work. That's tracked separately and remains the critical path.
- Python flasher CLI. Superseded by WebUSB for the end-user case.
- Artery ISP Mac version. Almost certainly does not exist; Chinese MCU vendor tools are universally Windows-only. The WebUSB flasher is the Mac/Linux story.
Filing this now so the idea is documented and searchable when the time comes. Feedback and alternate proposals welcome — this is a sketch, not a commitment.
Long-range architectural sketch, filed now so it's documented rather than living in my head. Nothing here should be built before FPGA SPI3 data acquisition is working and v1.0 is in sight. This is a post-v1.0 vision for how the project makes the jump from "replacement firmware for a specific scope" to "platform for handheld instruments."
Three layers, each solving a different problem. They compose together but can be built independently and incrementally.
Layer 1 — WebUSB flasher (distribution)
Problem: How do non-developers get firmware onto the device? Right now the first-flash path requires either
dfu-util(Mac/Linux, Homebrew or apt install), Zadig +dfu-util(Windows, painful), or Artery ISP Programmer (Windows-only GUI, thanks to @michkovitalik for documenting this path on #4). No path works for all users without install friction.Proposal: Host a browser-based flasher at something like
https://davidclawson.github.io/OpenScope-2C53T/flash/. User visits URL in Chrome or Edge, walks through the BOOT0 + reset physical step with photos/video, clicks Connect, and the browser talks DFU directly to the AT32 ROM bootloader over WebUSB. The page fetches the latest release binaries from GitHub, handles the option-byte write (224 KB SRAM), then writes the bootloader and application firmware.Existing library to build on: WebDFU — MIT-licensed JavaScript port of
dfu-util, known to work with standard DFU devices. The AT32 ROM bootloader is DFU-compliant so it should work with minimal adaptation.What this unlocks:
Tradeoffs:
A Python flasher CLI was previously under consideration for the same problem. WebUSB dominates on every axis that matters for end users — no install, no code signing, works on ChromeOS, URL-based distribution. A Python version might still have value for CI or automation, but it's no longer the primary play.
Layer 2 — SPI flash boot slots (installation)
Problem: Once WebUSB is working, the next question is: how does a user switch between different firmwares without re-entering ROM DFU mode or reflashing? Today, switching firmwares means a full flash cycle.
Proposal: Use the 16 MB Winbond W25Q128JVSQ SPI flash to store multiple complete firmware images in "slots," with a boot selector that copies the chosen slot into MCU flash at boot time. The application is only ~210 KB, so even 6 slots at ~2 MB each is extravagant.
Sketch layout:
Boot flow:
0x08004000(only if it has changed since last boot, to minimize writes)0x08004000as normalUser-facing surface:
What this unlocks when combined with Layer 1:
Once a device has v1.0+ installed, the WebUSB flasher can write new builds to SPI slots over the HID bootloader path — no ROM DFU mode, no case opening, no BOOT0 jumper. The user visits the flasher page, picks a build, picks a slot, clicks install. Their existing firmware stays in its slot, unchanged. They can flip between slots on demand from the boot menu.
This is the mechanism that makes the platform vision real: the same $75 hardware becomes multiple different instruments based on which slot is active, and switching between them is a reboot, not a reflash.
Why this specific hardware is well-suited:
Incremental implementation path:
Each phase is independently useful.
Caveats:
Layer 3 — Module packs (customization)
Problem: How does one firmware become different instruments? Different users want fundamentally different things from the same hardware — automotive diagnostics, HVAC commissioning, ham radio measurements, education, bench tools, component testing.
Proposal: Do NOT build separate firmware binaries per vertical. Build one universal firmware plus a library of module packs that customize it. A pack is:
modules/directory seeds this with automotive, HVAC, ham radio, education)Why not separate binaries:
The 2C53T has ~800 KB of unused MCU flash and ~14 MB of unused SPI flash. There is no physical reason to fragment the firmware across builds.
The UX is still what feels like picking a specialized tool: the web flasher in Layer 1 bundles "firmware + pack" as a single install operation, so the user picks "Automotive" and gets a device that boots into an automotive-focused UI. Under the hood it's the universal firmware with an automotive module pack loaded into SPI flash.
How the three layers compose
Each layer solves a different problem:
Together, they turn the project from "replacement firmware for a specific scope" into an open platform for handheld instruments. Separate Layer 1/2/3 work is each useful in isolation, but the combination is what makes the WRT54G/OpenWrt analogy concrete for this hardware.
Priority order and scheduling
Do not build any of this before FPGA SPI3 data acquisition is working. The scope must actually scope before distribution and platform work has any leverage. Pre-v1.0, all of this is premature.
Signal to reconsider: FPGA SPI3 flowing reliably + v1.0 in sight + continued external user interest. At that point, the WebUSB flasher is the highest-leverage next move because it unlocks the non-developer audience and makes Layers 2 and 3 reachable.
Priority order when we build:
Related signals
The demand signal for easier cross-platform flashing has already arrived this week, across three operating systems in two days:
option_bytes48.binconfusion (Makefile rule was missing)Three of the first four external users hit first-flash friction. That's the confirmation that the distribution layer matters — the remaining gate is just FPGA SPI3 working so there's something worth flashing easily.
Not in scope for this issue
Filing this now so the idea is documented and searchable when the time comes. Feedback and alternate proposals welcome — this is a sketch, not a commitment.