embflasher
Cross-platform CMSIS-DAP firmware programmer driven by CMSIS FLM flash algorithms, built on pyOCD.
CLI
↓
Python API (embflasher.flash)
↓
pyOCD
↓
DAPLink / CMSIS-DAP
↓
MCU
Supports macOS, Windows, and Linux (Ubuntu).
Installation
pip install embflasher
Local development:
git clone <repo-url>
cd embflasher
pip install -e .
Usage
embflasher --help
embflasher probe list
embflasher flash firmware.hex --flm chip.flm
Minimal usage — only firmware and --flm are required, everything else uses a sensible default (sector erase, verify on, reset on, 100k SWD frequency, cortex_m target):
embflasher flash firmware.bin --flm NS800RT50x9.FLM
If more than one DAPLink/CMSIS-DAP probe is connected, select one explicitly:
embflasher probe list
embflasher flash firmware.hex --flm chip.flm --probe <unique-id>
Full option list:
embflasher flash firmware.{bin,hex,elf} --flm chip.flm
[--probe <unique-id>]
[--erase auto|sector|chip] (default: sector)
[--no-verify]
[--no-reset]
[--bin-address 0x...] (.bin only; default: FLM's Flash start)
[--frequency 100k] (default: 100k)
[--connect halt|pre-reset|under-reset|attach] (default: under-reset)
[--target cortex_m] (default: cortex_m)
[--ram-start 0x20000000] (default: 0x20000000)
[--ram-size 0x...] (default: max(64KiB, FLM minimum))
Python API
from embflasher import flash, list_probes
flash(firmware="app.hex", flm="chip.flm")
# with overrides
flash(
firmware="app.bin",
flm="chip.flm",
probe="0123456789ABCDEF",
target="cortex_m",
frequency="4M",
erase="chip",
verify=True,
reset=True,
)
print(list_probes())
Requirements
- Python >= 3.10
- A DAPLink or CMSIS-DAP compatible debug probe
- pyOCD (installed automatically as a dependency)
USB permissions on Linux
On Ubuntu/Linux, the debug probe usually needs a udev rule to be accessible without root. pyOCD ships one:
python -m pyocd pack update # optional, first run
sudo curl -o /etc/udev/rules.d/50-cmsis-dap.rules \
https://raw.githubusercontent.com/pyocd/pyOCD/main/udev/50-cmsis-dap.rules
sudo udevadm control --reload-rules
sudo udevadm trigger
Then unplug and replug the probe.
Releasing a new version (maintainers)
Pushing commits to main does not publish anything by itself. Publishing to PyPI only happens when a GitHub Release is created, and that Release must point at a tag. The chain is:
bump version in pyproject.toml
↓
git commit + git push (to main)
↓
git tag vX.Y.Z + git push origin vX.Y.Z
↓
gh release create vX.Y.Z (or create it from the GitHub web UI)
↓
GitHub Actions: .github/workflows/publish.yml runs automatically
↓
1. checkout, python -m build → builds dist/*.whl and dist/*.tar.gz
2. uploads them as a workflow artifact
3. downloads the artifact into the `pypi` environment job
4. pypa/gh-action-pypi-publish uploads them to PyPI via
Trusted Publishing (OIDC) — no API token needed
↓
pip install embflasher ← now installs the new version
Step-by-step for a real release:
# 1. bump the version
# edit pyproject.toml: version = "0.1.2"
git add pyproject.toml
git commit -m "Bump version to 0.1.2"
git push origin main
# 2. tag the commit that should be released
git tag -a v0.1.2 -m "v0.1.2"
git push origin v0.1.2
# 3. create the GitHub Release — THIS is what triggers the publish workflow
gh release create v0.1.2 --title "v0.1.2" --notes "..."
After step 3, check progress with:
gh run list --workflow=publish.yml --limit 1
gh run watch
Notes:
- Creating just a tag does not trigger anything. The workflow only fires
on: release: types: [published]. - The PyPI project must have a "pending publisher" (or an existing Trusted Publisher) configured once, at https://pypi.org/manage/account/publishing/, pointing at this repo (
codeing-link/embflasher), workflow filepublish.yml, and environment namepypi. This is a one-time, manual step done on pypi.org — it cannot be automated from the repo. - The repo also needs a GitHub Environment named
pypi(Settings → Environments) for the OIDC trust relationship declared inpublish.yml(environment: pypi,permissions: id-token: write). - PyPI does not allow re-uploading the same version number. If a release fails partway, bump the version again rather than retrying the same tag.
- This works the same whether the repository is public or private — Trusted Publishing is based on the OIDC token GitHub issues for the workflow run, not on repo visibility.
License
MIT
Metadata
Release files for embflasher 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| embflasher-0.1.1.tar.gz | 11.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| embflasher-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 21.7 kB
Release files / embflasher-0.1.1.tar.gz
| Download URL | embflasher-0.1.1.tar.gz |
|---|---|
| Size | 11.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a23e31a857a9810d3593336e2e49c1e4e7f93ea0449a1a6b15e16d47edaa8ed0
|
|
BLAKE2b-256 checksum How to use checksums |
b5c918621ae6f6af77c30c39ba7d4469c5585b4ad4729030a38836e823a915b3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 20, 2026.
Transparency logRelease files / embflasher-0.1.1-py3-none-any.whl
| Download URL | embflasher-0.1.1-py3-none-any.whl |
|---|---|
| Size | 10.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
227950a5e13afa6788f75469607b7c0e1c04a35098915473cf9541ecfa668cf0
|
|
BLAKE2b-256 checksum How to use checksums |
7afa262a5313e830375b1c64662adc3a97f115e8deaca70b5dfff18800779123
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 20, 2026.
Transparency log