Contributing
Thanks for your interest in tinyboot. This page covers the dev setup, test procedures, and workflow conventions.
Before starting
- For anything bigger than a typo fix, please open an issue first so we can discuss the approach.
- New chip ports are especially welcome — see the porting guide for the trait surface you’d need to implement.
AI assistance
Parts of this project — including code, tests, and this handbook — were written with AI assistance. We’re open about that, and AI-assisted contributions from others are welcome under the same ground rules we hold ourselves to:
- AI-assisted code, tests, and documentation are accepted — but disclose it. If an AI assistant helped produce your contribution, say so in the PR description. A one-liner is enough. No need to itemize what came from where.
- You are the decision maker. Architecture, design, code quality, and correctness are your calls, not the AI’s. Don’t hand off judgment.
- You own the code, not the AI. Use your best judgment before submitting — if you wouldn’t be comfortable putting your name on it, don’t send it.
- Test on real hardware. No “it compiles” submissions for anything that touches flash, peripherals, or the boot path. Run the hardware validation checklist where it applies.
- Keep core features in system flash. The bootloader has to fit in the system-flash budget (see design notes). Non-core features can be
cfg-gated if they don’t fit for everyone. - Slop PRs will be rejected. AI-generated or not, PRs that show no sign of human review — unused code, wrong abstractions, duplicated logic, tests that don’t exercise the change, docs that hallucinate — will be closed. The policy is about thoughtfulness, not tooling.
Workspace layout
lib/ platform-agnostic core
core/ tinyboot-core
protocol/ tinyboot-protocol
ch32/ CH32 HAL + platform
rt/ tinyboot-ch32-rt (minimal bootloader runtime)
cli/ tinyboot host CLI
examples/ch32/v003/ V003 boot + app (CI testbed)
examples/ch32/v00x/ V00x boot + app
examples/ch32/v103/ V103 boot + app
docs/ user-facing documentation
Each directory is its own Cargo workspace with an independent Cargo.lock. A “clean compile” of the project therefore means wiping target/ under every workspace — see below.
Rust toolchain
- Library crates (
lib/,cli/) — stable Rust 1.85+, edition 2024. - CH32 example binaries — nightly, for
-Zbuild-stdonriscv32ec-unknown-none-elf(V003 / V00x) or the stableriscv32imc-unknown-none-elftarget (V103).
Each example workspace pins its toolchain via rust-toolchain.toml.
Running tests
# Unit tests for the platform-agnostic crates
cd lib && cargo test
# Build every example to make sure all feature combinations compile
cd examples/ch32/v003 && cargo build --release
cd examples/ch32/v00x && cargo build --release
cd examples/ch32/v103 && cargo build --release
# Host CLI
cd cli && cargo test
CI runs a matrix across chip variants and flash modes. Match that before opening a PR.
Clean compile
When hunting size regressions or build issues, a “clean compile” means removing target/ from every workspace. A leftover target/ in one workspace can mask issues in another:
find . -type d -name target -prune -exec rm -rf {} +
Then rebuild the affected workspaces.
Hardware validation
Some changes (particularly to flash, BootCtl, or the RS-485 transport) can’t be caught by unit tests and need on-hardware validation.
Integration test checklist (user-flash mode)
This is the acceptance test we run before merging flash-touching changes on CH32V003 / V103 in user-flash mode:
- Erase user flash via
wlink. - Build and flash the bootloader to the
BOOTregion. - Power-cycle the board.
- Confirm
tinyboot inforeportsmode = 0and the expectedboot_version. - Build the app.
- Flash the app via
tinyboot flash <app> --reset. - Confirm the app is running (LED blinks,
tinyboot inforeportsmode = 1). - Re-flash a different app version to exercise the update flow end-to-end.
- Trigger bootloader re-entry via
tinyboot reset --bootloader. - Re-flash the original app, confirm it still runs.
- Simulate an app that never confirms — boot should fall back to the bootloader after trials run out.
- Simulate a power loss mid-flash (disconnect power during a write); confirm recovery.
- Confirm
METAis in the expected location post-update.
Note
On CH32V103 in user-flash mode with the BOOT_CTL RC network installed, temporarily disconnect the PB1 → BOOT0 trace before running this procedure. A soft reset can otherwise latch BOOT0 HIGH and route you into system flash.
System-flash mode
System-flash validation follows the same shape but uses wlink to write to the system flash address (0x1FFFF000 on V003 / V103, 0x1FFF0000 on V00x). After writing system flash, always power-cycle before testing.
Commit and PR conventions
- Small, focused commits. Commit messages in imperative mood (e.g. “Add V00x feature flag”, “Fix FTPG partial page write”).
- A PR covering a behavior change should note how you validated it (unit test added, hardware procedure run, both).
- Keep docs changes in the same PR as the code change they describe, unless the docs are big enough to deserve their own review.
Releases
Crates release independently: bump the crate’s version, add a ## [<crate> X.Y.Z] - <date> changelog section, and tag <crate>-vX.Y.Z. tinyboot-ch32 stays git-only (not published to crates.io) while it depends on an unreleased ch32-metapac. The rest (tinyboot-core, tinyboot-protocol, tinyboot, tinyboot-ch32-rt) also publish to crates.io.