A cross-platform, scriptable command-line tool for programming and inspecting
Puya PY32 / MS32 series Cortex-M0 microcontrollers — a terminal-first
complement to Puya's official PY32Programmer GUI, aimed at CI pipelines,
production-line scripting, and anyone who'd rather not open a GUI to flash a
chip.
Early-stage / actively evolving. Not affiliated with or endorsed by Puya Semiconductor Co., Ltd. "PY32" and "PY-Link" are trademarks of their respective owner; this is an independent, community-built tool.
The official GUI tool is fine for one-off bench work, but it doesn't fit
headless or automated workflows: no CI integration, no scripting, no
composability with other command-line tooling. py32cli targets the same
capabilities — flashing, erasing, verifying, reading back, option-byte
management — through a modern, discoverable CLI with a rich terminal UI
(progress bars, spinners, tables) instead of a window.
Every command follows a strict exit-code contract: 0 only on genuine
success, non-zero on any failure (including a silently-rejected write that a
naive tool might otherwise report as "done"). Whatever invokes py32cli — a
CI job, a production-line script, another program — can trust the exit code
alone to know whether the operation actually worked, without having to parse
terminal output.
| Area | Status |
|---|---|
| Device catalog (list/inspect 170+ PY32/MS32 part numbers) | ✅ working |
| Serial port discovery | ✅ working |
| UART/USB ISP bootloader (connect, erase, program, verify, read, option bytes, auto-remove RDP) | ✅ working |
| PY-Link probe support (info, read, reset, erase, program, verify, option bytes, interactive console) | ✅ working |
| Option bytes (read / decode / modify / write) — over both UART and PY-Link | ✅ working |
| Intel HEX / raw binary input | ✅ working |
| ELF input | 🚧 planned |
| Optional SEGGER J-Link passthrough | 🚧 planned (not started) |
The bundled catalog covers the full published PY32/MS32 lineup. Note that
not every part has a ROM UART bootloader — e.g. PY32F002B does not, and
requires SWD-based programming (PY-Link probe or J-Link) instead of the
UART/USB ISP path. Check a given part with py32cli devices show <part>.
Actually tested against real hardware so far: only PY32F040ER1BT7
(on a PY32F040R1xT_START_V2.0 board), over both the UART/USB ISP bootloader
and PY-Link. Every other part in the catalog is supported per its published
memory layout and flash algorithm, but hasn't been validated on real silicon
yet. Contributions from anyone testing other PY32/MS32 parts — bug reports,
fixes, or just a confirmation that a given part works — are very welcome.
The quickest way to get running: download the binary for your platform from
the latest GitHub Release,
verify it against the accompanying .sha256 file, and run it directly — no
.NET runtime or install step needed. To build one yourself instead, see
"Build from source" below.
py32cli is published on NuGet.org
as a real dotnet tool:
dotnet tool install --global Py32ProgrammerCli
py32cli devices listYou can also install from a local build instead:
dotnet pack src/PY32Programmer.Cli -c Release -o ./nupkg
dotnet tool install --global --add-source ./nupkg Py32ProgrammerCli
py32cli devices listThis install path requires the .NET 10
runtime to already be on the
machine. pylink commands work too — the tool package bundles the official
libusb-1.0.dll (win-x64) that LibUsbDotNet needs, right next to the tool
itself, confirmed end to end (dotnet tool install --global from a clean
machine state, then a real pylink read against hardware). See
THIRD-PARTY-NOTICES.md for that binary's
license/provenance. win-x86 and other platforms aren't bundled this way yet
(a portable tool package can only carry one native binary per OS without
collisions) — use a self-contained publish (below) for those.
Requires the .NET 10 SDK or later.
git clone https://github.com/ivancmz/py32cli.git
cd py32cli
dotnet build
# Explore the bundled device catalog
dotnet run --project src/PY32Programmer.Cli -- devices list --filter PY32F002
dotnet run --project src/PY32Programmer.Cli -- devices show PY32F040x8
# List serial ports visible to the OS
dotnet run --project src/PY32Programmer.Cli -- ports list
dotnet run --project src/PY32Programmer.Cli -- --helpTo build your own self-contained single-file binary instead (no .NET runtime required to run the result, though you still need the SDK to build it):
dotnet publish src/PY32Programmer.Cli -c Release -r win-x64 \
--self-contained true -p:PublishSingleFile=true \
-p:IncludeNativeLibrariesForSelfExtract=true \
-p:PublishTrimmed=true -p:TrimMode=partial -o ./publishSwap win-x64 for linux-x64, osx-arm64, etc.
PY32ProgrammerCLI.sln
├── src/
│ ├── PY32Programmer.Core/ # Device database, transports, wire protocols — no UI concerns
│ └── PY32Programmer.Cli/ # System.CommandLine command tree + Spectre.Console rendering
└── tests/
└── PY32Programmer.Core.Tests/
PY32Programmer.Core has no dependency on the CLI framework or on
Spectre.Console, so the same protocol/device logic could back a different
front end (a library, a GUI, a web service) later without rework.
- .NET 10 — long-term-support runtime, genuinely cross-platform (win/linux/osx, x64/arm64), publishable as self-contained single-file binaries per platform.
- System.CommandLine —
command/subcommand parsing,
--helpgeneration, argument validation. - Spectre.Console — tables, panels, progress bars, spinners, and prompts for the terminal UI.
- xUnit — unit tests for anything that doesn't require physical hardware (device catalog parsing today; protocol framing/encoding logic later).
| Transport | Platforms | Notes |
|---|---|---|
| UART/USB ISP bootloader | Windows, Linux, (macOS with caveats) | Uses the standard System.IO.Ports serial API; macOS's serial backend is historically less reliable and will be validated explicitly before being called "supported". |
| PY-Link probe | Windows, Linux, macOS (planned) | Cross-platform USB access; Windows may require a WinUSB/libusbK driver swap for the probe depending on how it enumerates. |
| SEGGER J-Link passthrough | Windows, Linux, macOS (planned, optional) | Requires the user to have SEGGER's J-Link Software installed; that pack itself ships for all three platforms. |
Licensed under the MIT License.
There's no formal contribution process yet (no CONTRIBUTING.md, no issue/PR
templates) — for now, just open an issue or PR on
GitHub. The most valuable contribution
right now is real-hardware testing: as noted under "Supported devices" above,
only PY32F040ER1BT7 has actually been validated, so a bug report or even
just a confirmation that a given part works on real silicon is genuinely
useful. See CHANGELOG.md for what's landed so far and
THIRD-PARTY-NOTICES.md for bundled third-party
license attribution (the vendored libusb-1.0.dll, LGPL-2.1).