Add end-to-end USB flashing for the app firmware via UF2
Adds uf2conv.py (minimal, dependency-free .bin -> .uf2 converter matching bootloader/inc/uf2format.h's block layout) and upload_uf2.py, a PlatformIO upload hook for env:versapad_usb that finds the mounted VERSABOOT volume and copies the converted firmware onto it. env:versapad_usb previously used upload_protocol=sam-ba, the classic Arduino/Atmel protocol -- the actual bootloader speaks UF2/mass storage, not SAM-BA, so that upload path never worked. Switched to upload_protocol=custom with the new hook, and cleaned the now-unused SAM-BA-specific fields out of boards/versapad.json. Verified end to end on real hardware: pio run -e versapad_usb --target upload builds, converts, copies to the VERSABOOT drive, and the bootloader jumps into the freshly written app on its own. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
f60a29137c
commit
d325297063
7 changed files with 210 additions and 32 deletions
72
upload_uf2.py
Normal file
72
upload_uf2.py
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
"""PlatformIO upload hook for env:versapad_usb.
|
||||
|
||||
The board's actual bootloader (bootloader/, UF2/mass-storage) does not speak
|
||||
SAM-BA, so upload_protocol=sam-ba (the board.json default, inherited from an
|
||||
Arduino-Zero-style template) does not work here. This converts the built
|
||||
.bin to .uf2 and copies it onto the VERSABOOT mass-storage volume instead --
|
||||
Windows only for now, matching the rest of this project's dev environment.
|
||||
"""
|
||||
import ctypes
|
||||
import os
|
||||
import string
|
||||
import sys
|
||||
|
||||
Import("env")
|
||||
|
||||
sys.path.insert(0, env.subst("$PROJECT_DIR"))
|
||||
import uf2conv
|
||||
|
||||
VOLUME_LABEL = "VERSABOOT"
|
||||
DRIVE_UNKNOWN = 0
|
||||
DRIVE_NO_ROOT_DIR = 1
|
||||
|
||||
|
||||
def find_versaboot_drive(label=VOLUME_LABEL):
|
||||
for letter in string.ascii_uppercase:
|
||||
root = f"{letter}:\\"
|
||||
drive_type = ctypes.windll.kernel32.GetDriveTypeW(root)
|
||||
if drive_type in (DRIVE_UNKNOWN, DRIVE_NO_ROOT_DIR):
|
||||
continue
|
||||
vol_name_buf = ctypes.create_unicode_buffer(261)
|
||||
fs_name_buf = ctypes.create_unicode_buffer(261)
|
||||
ok = ctypes.windll.kernel32.GetVolumeInformationW(
|
||||
ctypes.c_wchar_p(root),
|
||||
vol_name_buf,
|
||||
ctypes.sizeof(vol_name_buf),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
fs_name_buf,
|
||||
ctypes.sizeof(fs_name_buf),
|
||||
)
|
||||
if ok and vol_name_buf.value == label:
|
||||
return root
|
||||
return None
|
||||
|
||||
|
||||
def upload_via_uf2(source, target, env):
|
||||
build_dir = env.subst("$BUILD_DIR")
|
||||
bin_path = os.path.join(build_dir, "firmware.bin")
|
||||
uf2_path = os.path.join(build_dir, "firmware.uf2")
|
||||
|
||||
if not os.path.isfile(bin_path):
|
||||
print(f"error: {bin_path} not found (expected as a normal build product)")
|
||||
env.Exit(1)
|
||||
|
||||
num_blocks = uf2conv.convert(bin_path, uf2_path, base_addr=0x2000, family_id=uf2conv.SAMD21_FAMILY_ID)
|
||||
print(f"Wrote {uf2_path}: {num_blocks} blocks")
|
||||
|
||||
drive = find_versaboot_drive()
|
||||
if drive is None:
|
||||
print(f"error: no drive labeled '{VOLUME_LABEL}' found.")
|
||||
print("Hold the bottom-right Cherry MX key while plugging in USB to enter the bootloader.")
|
||||
env.Exit(1)
|
||||
|
||||
dest = os.path.join(drive, "firmware.uf2")
|
||||
print(f"Copying {uf2_path} -> {dest}")
|
||||
with open(uf2_path, "rb") as src, open(dest, "wb") as dst:
|
||||
dst.write(src.read())
|
||||
print("Upload triggers a reset into the app on the device side; no further action needed.")
|
||||
|
||||
|
||||
env.Replace(UPLOADCMD=upload_via_uf2)
|
||||
Loading…
Add table
Add a link
Reference in a new issue