Skip to content

tooling: Add firmware build and deploy targets.#246

Merged
nedseb merged 6 commits intomainfrom
tooling/firmware-build-deploy
Mar 26, 2026
Merged

tooling: Add firmware build and deploy targets.#246
nedseb merged 6 commits intomainfrom
tooling/firmware-build-deploy

Conversation

@nedseb
Copy link
Copy Markdown
Contributor

@nedseb nedseb commented Mar 25, 2026

Summary

Add Makefile targets for building, deploying, and running MicroPython firmware with current drivers.

Closes #245

New targets

Target Description
make firmware Clone micropython-steami (if absent), pull latest, symlink local drivers, build firmware
make deploy Flash firmware via OpenOCD (requires clone to exist)
make run SCRIPT=... Run a script on the board with live output via mpremote run
make deploy-script SCRIPT=... Copy a script as main.py for autonomous execution
make run-main Re-execute the deployed main.py and capture output
make firmware-clean Clean firmware build artifacts

Architecture

The firmware source is cloned into .build/micropython-steami/ (gitignored). A symbolic link replaces the submodule lib/micropython-steami-lib with the local working directory. This means the firmware always includes the latest driver changes — even uncommitted ones — without needing to commit or push first.

.build/
└── micropython-steami/
    └── lib/
        └── micropython-steami-lib -> /path/to/micropython-steami-lib  (symlink)

Configuration

Variables in env.mk (all overridable):

MICROPYTHON_REPO ?= https://github.com/steamicc/micropython-steami.git
MICROPYTHON_BRANCH ?= stm32-steami-rev1d-final
BOARD ?= STEAM32_WB55RG
BUILD_DIR ?= .build

Typical workflow

# First time
make firmware        # Clone + build (~5 min)
make deploy          # Flash to board

# Development cycle
# ... modify a driver ...
make firmware        # Rebuild (incremental, ~30s)
make deploy          # Flash

# Test an example
make run SCRIPT=lib/steami_config/examples/show_config.py

# Deploy for autonomous use (without USB)
make deploy-script SCRIPT=lib/steami_config/examples/calibrate_magnetometer.py
make run-main        # Re-execute later

Requirements

  • arm-none-eabi-gcc toolchain
  • OpenOCD for flashing
  • mpremote for running scripts

Review feedback addressed

  • mkdir -p before clone to handle missing parent directories
  • Symlink instead of git fetch for submodule (includes uncommitted changes)
  • deploy depends on $(MPY_DIR) (clone must exist, but no forced rebuild)
  • Clarified run vs deploy-script vs run-main roles
  • Quoted $(BUILD_DIR) in rm -rf for safety
  • Updated CONTRIBUTING.md with mpremote requirement and symlink docs

Copilot AI review requested due to automatic review settings March 25, 2026 14:53
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a local firmware workflow to this repository so developers can build MicroPython firmware with the repo’s drivers frozen in, flash it via OpenOCD, and push a main.py to the board for quick iteration.

Changes:

  • Introduces Makefile targets for firmware clone/build, deploy (OpenOCD), run (copy script + reset), and firmware-clean.
  • Adds firmware-related configuration variables to env.mk (repo/branch/board/build dirs).
  • Documents the workflow in CONTRIBUTING.md and gitignores the local build directory.

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 6 comments.

File Description
env.mk Adds firmware build configuration variables (repo/branch/board/build paths).
Makefile Adds firmware, deploy, run, firmware-clean targets and extends deepclean to remove firmware build dir.
CONTRIBUTING.md Documents the new firmware build/deploy/run workflow and requirements.
.gitignore Ignores .build/ where firmware sources/artifacts are cloned/built.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread Makefile

# --- Firmware ---

$(MPY_DIR):
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

git clone ... $(MPY_DIR) will fail on a fresh checkout if $(BUILD_DIR) (default .build) doesn’t exist, because git clone won’t create missing parent directories. Create $(BUILD_DIR) first (e.g., mkdir -p $(BUILD_DIR)) before cloning, or set MPY_DIR to a path whose parents are guaranteed to exist.

Suggested change
$(MPY_DIR):
$(MPY_DIR):
@mkdir -p $(dir $(MPY_DIR))

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 95028ee. Added mkdir -p before clone.

Comment thread Makefile Outdated
Comment on lines +91 to +94
@echo "Updating submodule to current HEAD..."
cd $(MPY_DIR)/lib/micropython-steami-lib && \
git fetch origin && \
git checkout $$(cd $(CURDIR) && git rev-parse HEAD)
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The “update submodule to current HEAD” logic is unlikely to work for local/unpushed commits: the submodule fetches only from its own origin, then tries to checkout a SHA from the parent repo. If that SHA isn’t present in the submodule clone, this will fail and it also won’t include uncommitted local changes. Consider fetching from the local working tree path (or setting the submodule URL to the local repo) and clarify whether users must commit changes before building firmware.

Suggested change
@echo "Updating submodule to current HEAD..."
cd $(MPY_DIR)/lib/micropython-steami-lib && \
git fetch origin && \
git checkout $$(cd $(CURDIR) && git rev-parse HEAD)
@echo "Updating submodule to current committed HEAD from local repo (uncommitted changes are not included)..."
cd $(MPY_DIR)/lib/micropython-steami-lib && \
git fetch "$(CURDIR)" HEAD && \
git checkout FETCH_HEAD

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 95028ee. Replaced git fetch origin with a symlink: rm -rf ... && ln -s $(CURDIR) .... This way the firmware includes all local changes — even uncommitted ones — without needing to fetch or push.

Comment thread Makefile Outdated
@echo "Firmware ready: $(MPY_DIR)/ports/stm32/build-$(BOARD)/firmware.hex"

.PHONY: deploy
deploy: ## Flash firmware to the board via OpenOCD
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deploy assumes $(MPY_DIR) already exists; running make deploy in a clean repo will fail because the clone hasn’t happened yet. Make deploy depend on $(MPY_DIR) (and likely firmware if you expect a freshly built hex) so it works from a fresh checkout.

Suggested change
deploy: ## Flash firmware to the board via OpenOCD
deploy: firmware ## Flash firmware to the board via OpenOCD

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 95028ee. deploy now depends on $(MPY_DIR) — ensures the clone exists but doesn't force a rebuild. Use make firmware deploy for a full build+flash.

Comment thread Makefile
Comment on lines +103 to +110
.PHONY: run
run: ## Copy and run a script on the board (SCRIPT=path/to/file.py)
@if [ -z "$(SCRIPT)" ]; then \
echo "Error: SCRIPT is required. Usage: make run SCRIPT=lib/.../example.py"; exit 1; \
fi
mpremote connect $(PORT) cp $(SCRIPT) :main.py
mpremote connect $(PORT) reset
@echo "Script deployed as main.py and board reset."
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This run implementation uses mpremote ... cp directly and does not implement the “wait for PORT” step or the REPL chunked-write workaround described in issue #245 / #244. If the intent is to close #245, the target should match that workflow (or the docs/issue closure should be adjusted).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarified in 95028ee. make run now uses mpremote run for live output (no copy needed). The chunked-write workaround was only needed for mpremote cp with large files — tracked separately in #244. Added deploy-script for the autonomous copy-as-main.py use case.

Comment thread Makefile Outdated
deepclean: clean ## Remove everything including node_modules
deepclean: clean ## Remove everything including node_modules and firmware
rm -rf node_modules
@if [ -d "$(BUILD_DIR)" ]; then rm -rf $(BUILD_DIR); fi
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In .ONESHELL mode, prefer quoting $(BUILD_DIR) in rm -rf (and you can usually drop the -d guard since rm -rf is already idempotent). Unquoted paths can behave unexpectedly if the variable is overridden with spaces or glob characters.

Suggested change
@if [ -d "$(BUILD_DIR)" ]; then rm -rf $(BUILD_DIR); fi
rm -rf "$(BUILD_DIR)"

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 95028ee. Quoted $(BUILD_DIR) in rm -rf.

Comment thread CONTRIBUTING.md Outdated
Comment on lines +136 to +138
The firmware source is cloned into `.build/micropython-steami/` (gitignored). The submodule `lib/micropython-steami-lib` is pointed to the current HEAD of your local branch, so the firmware always includes your latest driver changes.

**Requirements**: `arm-none-eabi-gcc` toolchain and OpenOCD for flashing.
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docs say the firmware submodule is pointed to “the current HEAD of your local branch” and list requirements only as GCC + OpenOCD, but the Makefile currently fetches from the submodule’s origin (so local/unpushed commits won’t be available) and make run requires mpremote to be installed. Please align this section with the actual behavior and list mpremote as a requirement for deploy/run.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 95028ee. Updated CONTRIBUTING.md: added mpremote to requirements, clarified symlink behavior (local working directory, includes uncommitted changes), and documented all new targets (run, deploy-script, run-main).

@nedseb nedseb merged commit ecc704b into main Mar 26, 2026
3 checks passed
@nedseb nedseb deleted the tooling/firmware-build-deploy branch March 26, 2026 06:40
@semantic-release-updater
Copy link
Copy Markdown

🎉 This PR is included in version 0.1.1 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

tooling: Add firmware build, deploy and run targets to Makefile.

2 participants