The first time you flash custom firmware, you need to enter the AT32's ROM DFU mode by pulling the BOOT0 pin high while resetting the MCU. After the initial flash installs the USB HID bootloader, you'll never need to do this again — all future updates go over USB-C with the case closed.
Two bootloaders, don't mix them up. This device has two completely separate bootloaders:
- ROM DFU — baked into AT32 silicon, entered only via BOOT0 + pinhole reset. LCD stays dark. Enumerates as
2e3c:df11. This is the only mode that can write option bytes (needed once to set EOPB0 for 224KB SRAM).- USB HID bootloader — our custom bootloader at
0x08000000, entered from Settings → Firmware Update. Shows "BOOTLOADER MODE" on the LCD. Used bymake flashfor all normal updates. Cannot write option bytes.If
dfu-util -lshows "No DFU capable USB device available" while the scope is sitting on the "BOOTLOADER MODE" screen, that's why — you're in the wrong mode for whatdfu-utilexpects.
- Phillips screwdriver (to open the case)
- A short DuPont jumper wire (female-to-female or bare ends)
- USB-C cable connected to your computer
- A pin, plastic spudger, or small screwdriver (to press the pinhole reset button)
Open the case by removing the 6 Phillips screws on the back.
The 3.3V source is on the SWD debug header, located next to the USB-C port. There are 5 labeled through-hole pads: 3V3, SWDIO, GND, SWCLK, and one unlabeled. You may need to solder a pin header into the 3V3 pad for a reliable connection, or carefully hold a jumper wire against it.
The BOOT0 pin is accessible on the MCU side of a pull-down resistor near the bottom edge of the main IC (AT32F403A). The resistor holds BOOT0 low during normal boot. You need to touch the MCU-side pad of this resistor — the side closest to the microcontroller.
Note (unconfirmed): You can likely perform this entire procedure without the battery connected. Unplug the JST battery connector, then plug in USB-C — the USB charge circuit appears to power the board independently. This gives you more room to work inside the case and avoids any risk to the battery.
Evidence: with USB plugged in, the device stays powered even when the power kill switch is pressed — USB holds the rails up on its own. The ROM DFU bootloader is baked into the AT32 silicon and doesn't depend on any user firmware, so PC9 (power hold) shouldn't matter.
If you can confirm this works, please let us know in issue #1!
-
Open the case and connect USB-C to your computer (see note above — you may be able to disconnect the battery first).
-
Prepare the jumper wire. Take a DuPont wire and connect one end to the 3V3 pad on the SWD header (you may need to solder a pin into the through-hole for a solid connection).
-
Touch the other end to BOOT0. Carefully touch the free end of the jumper wire to the resistor pad on the MCU side (see the red arrow in the photo above). This pulls BOOT0 high (3.3V).
-
While holding 3.3V on BOOT0, press and hold the reset button. The pinhole reset button is accessible from the outside of the case, or you can press the NRST tactile switch on the PCB directly.
-
Release the reset button, then release the 3.3V jumper. The order matters — release reset first so the MCU samples BOOT0 = HIGH during startup.
-
Verify DFU mode. The device should enumerate as a USB DFU device:
dfu-util -l # Should show: "AT32 Bootloader DFU" with ID 2e3c:df11
Run cd firmware && make first — this generates build/firmware.bin, build/bootloader.bin, and the 48-byte build/option_bytes48.bin blob used in step 1 below.
Once in ROM DFU mode (confirmed by dfu-util -l showing 2e3c:df11 with alt interfaces 0 and 1):
cd firmware
# 1. Set EOPB0 = 0xFE → 224KB SRAM mode (one-time, AT32 defaults to 96KB)
dfu-util -a 1 -d 2e3c:df11 -s 0x1FFFF800 -D build/option_bytes48.bin
# 2. Pinhole reset to stay in DFU, then flash bootloader + application
make flash-allHarmless warnings you can ignore during step 1:
Invalid DFU suffix signature— our blob doesn't carry a CRC trailer; dfu-util just notes it.Error sending dfu abort request— AT32 ROM resets before acknowledging the session teardown.
The line that matters is Download done. / File downloaded successfully.
After this, close the case. All future updates use the USB HID bootloader:
- On the device: Settings > Firmware Update
- On your computer:
cd firmware && make flash
Once you've successfully entered DFU mode, the device shows up as a USB DFU device. Here's how to verify on each platform:
macOS:
# Check with dfu-util
dfu-util -l
# Expected output includes:
# Found DFU: [2e3c:df11] ver=0200, devnum=XX, cfg=1, intf=0, path="X-X", alt=0, name="@Internal Flash /0x08000000/0512*002Kg"
# Or check System Information → USB
# You should see "AT32 Bootloader DFU" listedLinux:
dfu-util -l
# Same output as above
# Or check with lsusb:
lsusb | grep 2e3c
# Expected: Bus XXX Device XXX: ID 2e3c:df11Windows:
- Open Device Manager — look for "AT32 Bootloader DFU" under USB devices
- You may need to install the WinUSB driver via Zadig for
dfu-utilto work
If you don't see the device, the BOOT0 jump didn't take. Try the procedure again — the timing can be finicky.
The dfu-util + make flash-all path above is what I use and test on macOS. Users on other platforms have reported success with the alternatives below. I haven't personally verified these — they're documented here because they worked for real users, and they may be easier than fighting dfu-util on Windows or getting udev rules right on Linux.
Artery ships a Windows GUI flasher that speaks the same ROM DFU protocol as dfu-util. A user on Windows 11 reported (see #4) that after fighting WinUSB/dfu-util setup they flashed successfully using Artery's tool instead.
Rough flow (if you try this and it works, please post the exact steps on #4 so I can tighten this up):
- Build the firmware on Windows (MSYS2/WSL) so you have
firmware/build/firmware.bin,firmware/build/bootloader.bin, andfirmware/build/option_bytes48.bin. - Put the device in ROM DFU mode using the BOOT0 + pinhole-reset procedure above. You're still entering the same mode — only the host-side tool changes.
- Download Artery ISP Programmer from the ArteryTek website (search for "AT32 ISP Programmer").
- In the tool, select the USB DFU interface, load each
.binat its flash address, and program. You'll need to program the option byte region (0x1FFFF800) fromoption_bytes48.binas well — this is whatdfu-util -a 1 ... -s 0x1FFFF800does in the command-line flow. - After the first successful flash, close the case. All future updates still go through
make flashover USB-C via the HID bootloader — you're only using Artery ISP for the one-time setup.
If you hit this and it works, please post your exact steps on #4 — it'll help the next Windows user and let me turn this stub into a proper walkthrough.
Consolidated from #2, #3, and #4. I develop on macOS, so this path is community-tested rather than something I run on every release.
# 1. Install toolchain + DFU tool
sudo apt install gcc-arm-none-eabi libnewlib-arm-none-eabi dfu-util make git
# 2. Clone the repo and the two external libraries it depends on
git clone https://github.com/DavidClawson/OpenScope-2C53T.git
cd OpenScope-2C53T/firmware
git clone https://github.com/ArteryTek/AT32F403A_407_Firmware_Library.git at32f403a_lib
git clone https://github.com/FreeRTOS/FreeRTOS-Kernel.git FreeRTOS
# 3. Build — this is what generates build/option_bytes48.bin (48 bytes)
make
ls -l build/option_bytes48.bin # sanity check: should exist and be 48 bytes
# 4. Enter ROM DFU mode (open case, BOOT0 jumper, pinhole reset — see above).
# Verify:
dfu-util -l
# Expect: Found DFU: [2e3c:df11] ... alt=0 ... alt=1
# 5. One-time option-byte write (sets EOPB0 = 0xFE → 224KB SRAM mode)
dfu-util -a 1 -d 2e3c:df11 -s 0x1FFFF800 -D build/option_bytes48.bin
# Ignore: "Invalid DFU suffix signature" and "Error sending dfu abort request" — cosmetic.
# Look for: "Download done." and "File downloaded successfully"
# 6. Pinhole reset (stays in DFU), then flash bootloader + app
make flash-all
# 7. Remove jumper, pinhole reset, close case. Done.
# All future updates: Settings → Firmware Update on device, then `make flash` on host.Linux gotchas:
- Permission denied on
dfu-util -l: add a udev rule or run withsudoonce to confirm it works. Minimal udev rule (save as/etc/udev/rules.d/40-at32-dfu.rules, thensudo udevadm control --reload-rules):SUBSYSTEM=="usb", ATTRS{idVendor}=="2e3c", ATTRS{idProduct}=="df11", MODE="0666" - Build succeeds but
option_bytes48.binis missing: you're on an old commit. This file is generated by a Makefile rule added here —git pulland rebuild. - ModemManager grabs the USB device: on some distros, temporarily stop it with
sudo systemctl stop ModemManagerbefore flashing.
- Device doesn't enumerate as DFU: Make sure you're touching the correct side of the resistor (MCU side, not ground side). Try again — the timing can be tricky.
dfu-utilnot found: Install withbrew install dfu-util(macOS) orapt install dfu-util(Linux).- Permission denied: On Linux, you may need udev rules for the AT32 DFU device. Try running with
sudofirst. - Bricked after a bad flash: You can always re-enter DFU mode with the BOOT0 procedure above. The ROM bootloader is permanent and cannot be overwritten.

