commit 8028dfd5fc4e83663568c83a4ec8c4bc164f62d3 Author: wieerwill Date: Mon May 25 18:16:02 2026 +0200 init basic examples and setup diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..5f45f36 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,23 @@ +[build] +target = "thumbv7m-none-eabi" + +[target.thumbv7m-none-eabi] +linker = "flip-link" +rustflags = [ + "-C", + "link-arg=-Tlink.x", + "-C", + "link-arg=-Tdefmt.x", +] + +[target.thumbv6m-none-eabi] +linker = "flip-link" +rustflags = [ + "-C", + "link-arg=-Tlink.x", + "-C", + "link-arg=-Tdefmt.x", +] + +[env] +DEFMT_LOG = "info" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8d41448 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +target/ +result +.direnv/ +.DS_Store +*.log +Embed.local.* +.embed.local.* diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..5aab2f8 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,77 @@ +# AGENTS + +## Map + +- Root has workspace files. +- `examples/` has one crate per demo. +- `docs/hardware/` has board and wiring notes. +- `memory.x` is shared. +- `justfile` is source of truth for commands. + +## Rules + +- Read before edit. +- Keep fixes small. +- No broad refactor. +- No dependency upgrade unless asked. +- Keep examples independent. +- Keep demo reliability first. +- Use simple code. +- No hidden IDE steps. +- No fake hardware claims. + +## Preserve + +- `nix develop` +- `just fmt` +- `just check` +- `just build` + +## Hardware + +- Blue Pill first. +- `thumbv7m-none-eabi` first. +- Do not mix STM32F0 with STM32F103. +- If hardware detail is unclear: + - write the assumption + - add a TODO + - keep build green + +## Style + +- Caveman style. +- Short names. +- Short comments. +- Explain embedded idea. +- Do not explain obvious Rust syntax. +- No heap. +- No dynamic dispatch unless teaching needs it. +- No async before Embassy examples. +- `unsafe` only if required and justified. + +## Commands + +- `just build` +- `just build-blinky` +- `just build-timer` +- `just build-button` +- `just build-embassy-blinky` +- `just build-embassy-button` +- `just flash-blinky` +- `just flash-timer` +- `just flash-button` +- `just flash-embassy-blinky` +- `just flash-embassy-button` +- `just run-blinky` +- `just run-embassy-blinky` +- `just fmt` +- `just clippy` +- `just check` +- `just clean` + +## Do Not + +- Do not invent board output. +- Do not claim flash or debug worked on hardware unless tested. +- Do not hide chip mismatches. +- Do not add abstractions for one use. diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..8437a37 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1276 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "aligned" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee4508988c62edf04abd8d92897fca0c2995d907ce1dfeaf369dac3716a40685" +dependencies = [ + "as-slice", +] + +[[package]] +name = "as-slice" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "516b6b4f0e40d50dcda9365d53964ec74560ad4284da2e7fc97122cd83174516" +dependencies = [ + "stable_deref_trait", +] + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "bare-metal" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" +dependencies = [ + "rustc_version", +] + +[[package]] +name = "bit_field" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6" + +[[package]] +name = "bitfield" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" + +[[package]] +name = "blinky-basic" +version = "0.1.0" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "defmt 1.1.0", + "defmt-rtt", + "panic-probe", + "stm32f1xx-hal", +] + +[[package]] +name = "blinky-timer" +version = "0.1.0" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "defmt 1.1.0", + "defmt-rtt", + "nb 1.1.0", + "panic-probe", + "stm32f1xx-hal", +] + +[[package]] +name = "block-device-driver" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c051592f59fe68053524b4c4935249b806f72c1f544cfb7abe4f57c3be258e" +dependencies = [ + "aligned", +] + +[[package]] +name = "button-input" +version = "0.1.0" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "defmt 1.1.0", + "defmt-rtt", + "panic-probe", + "stm32f1xx-hal", +] + +[[package]] +name = "bxcan" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3110c36f496cf7110ab17c48ad714225330862101ec30197a9898006cd3e2862" +dependencies = [ + "bitflags 1.3.2", + "embedded-can", + "nb 1.1.0", + "vcell", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cc" +version = "1.2.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cordyceps" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "688d7fbb8092b8de775ef2536f36c8c31f2bc4006ece2e8d8ad2d17d00ce0a2a" +dependencies = [ + "loom", + "tracing", +] + +[[package]] +name = "cortex-m" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" +dependencies = [ + "bare-metal", + "bitfield", + "critical-section", + "embedded-hal 0.2.7", + "volatile-register", +] + +[[package]] +name = "cortex-m-rt" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d4dec46b34c299ccf6b036717ae0fce602faa4f4fe816d9013b9a7c9f5ba6" +dependencies = [ + "cortex-m-rt-macros", +] + +[[package]] +name = "cortex-m-rt-macros" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e37549a379a9e0e6e576fd208ee60394ccb8be963889eebba3ffe0980364f472" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.117", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "defmt" +version = "0.3.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0963443817029b2024136fc4dd07a5107eb8f977eaf18fcd1fdeb11306b64ad" +dependencies = [ + "defmt 1.1.0", +] + +[[package]] +name = "defmt" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6e524506490a1953d237cb87b1cfc1e46f88c18f10a22dfe0f507dc6bfc7f7f" +dependencies = [ + "bitflags 1.3.2", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0a27770e9c8f719a79d8b638281f4d828f77d8fd61e0bd94451b9b85e576a0b" +dependencies = [ + "defmt-parser", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "defmt-parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" +dependencies = [ + "thiserror", +] + +[[package]] +name = "defmt-rtt" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0f73a4a4a91609e977ae3b7bd831ffa292edfd42ad140a3244a61d805b0e05e" +dependencies = [ + "critical-section", + "defmt 1.1.0", +] + +[[package]] +name = "document-features" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +dependencies = [ + "litrs", +] + +[[package]] +name = "embassy-blinky" +version = "0.1.0" +dependencies = [ + "cortex-m-rt", + "defmt 1.1.0", + "defmt-rtt", + "embassy-executor", + "embassy-stm32", + "embassy-time", + "panic-probe", +] + +[[package]] +name = "embassy-button" +version = "0.1.0" +dependencies = [ + "cortex-m-rt", + "defmt 1.1.0", + "defmt-rtt", + "embassy-executor", + "embassy-stm32", + "embassy-time", + "panic-probe", +] + +[[package]] +name = "embassy-embedded-hal" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0641612053b2f34fc250bb63f6630ae75de46e02ade7f457268447081d709ce" +dependencies = [ + "defmt 1.1.0", + "embassy-futures", + "embassy-hal-internal 0.4.0", + "embassy-sync", + "embassy-time", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "embedded-hal-async", + "embedded-storage", + "embedded-storage-async", + "nb 1.1.0", +] + +[[package]] +name = "embassy-executor" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0d3b15c9d7dc4fec1d8cb77112472fb008b3b28c51ad23838d83587a6d2f1e" +dependencies = [ + "cordyceps", + "cortex-m", + "critical-section", + "defmt 1.1.0", + "document-features", + "embassy-executor-macros", + "embassy-executor-timer-queue", +] + +[[package]] +name = "embassy-executor-macros" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d11a246f53de5f97a387f40ac24726817cd0b6f833e7603baac784f29d6ff276" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "embassy-executor-timer-queue" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fc328bf943af66b80b98755db9106bf7e7471b0cf47dc8559cd9a6be504cc9c" + +[[package]] +name = "embassy-futures" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc2d050bdc5c21e0862a89256ed8029ae6c290a93aecefc73084b3002cdebb01" + +[[package]] +name = "embassy-hal-internal" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f10ce10a4dfdf6402d8e9bd63128986b96a736b1a0a6680547ed2ac55d55dba" +dependencies = [ + "num-traits", +] + +[[package]] +name = "embassy-hal-internal" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "568659fc53866d3d85c60fa33723fb751aa69e71507634fc2c19e7649432fb75" +dependencies = [ + "cortex-m", + "critical-section", + "defmt 1.1.0", + "num-traits", +] + +[[package]] +name = "embassy-net-driver" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524eb3c489760508f71360112bca70f6e53173e6fe48fc5f0efd0f5ab217751d" +dependencies = [ + "defmt 0.3.100", +] + +[[package]] +name = "embassy-stm32" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "486c0622deb5a519fc4d2cb8e3ef324f7568fcdfff201ff8fcab46557d663ceb" +dependencies = [ + "aligned", + "bit_field", + "bitflags 2.11.1", + "block-device-driver", + "cfg-if", + "cortex-m", + "cortex-m-rt", + "critical-section", + "defmt 1.1.0", + "document-features", + "embassy-embedded-hal", + "embassy-futures", + "embassy-hal-internal 0.5.0", + "embassy-net-driver", + "embassy-sync", + "embassy-time", + "embassy-time-driver", + "embassy-time-queue-utils", + "embassy-usb-driver", + "embassy-usb-synopsys-otg", + "embedded-can", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "embedded-hal-async", + "embedded-hal-nb", + "embedded-io 0.7.1", + "embedded-io-async", + "embedded-storage", + "embedded-storage-async", + "futures-util", + "heapless 0.9.3", + "nb 1.1.0", + "proc-macro2", + "quote", + "rand_core 0.6.4", + "rand_core 0.9.5", + "regex", + "sdio-host", + "static_assertions", + "stm32-fmc", + "stm32-metapac", + "trait-set", + "vcell", + "volatile-register", +] + +[[package]] +name = "embassy-sync" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bbd85cf5a5ae56bdf26f618364af642d1d0a4e245cdd75cd9aabda382f65a81" +dependencies = [ + "cfg-if", + "critical-section", + "defmt 1.1.0", + "embedded-io-async", + "futures-core", + "futures-sink", + "heapless 0.9.3", +] + +[[package]] +name = "embassy-time" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "592b0c143ec626e821d4d90da51a2bd91d559d6c442b7c74a47d368c9e23d97a" +dependencies = [ + "cfg-if", + "critical-section", + "defmt 1.1.0", + "document-features", + "embassy-time-driver", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "embedded-hal-async", + "futures-core", +] + +[[package]] +name = "embassy-time-driver" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ee71af1b3a0deaa53eaf2d39252f83504c853646e472400b763060389b9fcc9" +dependencies = [ + "document-features", +] + +[[package]] +name = "embassy-time-queue-utils" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168297bf80aaf114b3c9ad589bf38b01b3009b9af7f97cd18086c5bbf96f5693" +dependencies = [ + "embassy-executor-timer-queue", + "heapless 0.9.3", +] + +[[package]] +name = "embassy-usb-driver" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a189cbf1d8ab3c591f88632f85c1df892b6ab04116037cbee39dc37cbdcd79f" +dependencies = [ + "defmt 1.1.0", + "embedded-io-async", +] + +[[package]] +name = "embassy-usb-synopsys-otg" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb205e26d59e483e8c48f91f637ec217ec7e2cfb0b61d50482301b991b4ff431" +dependencies = [ + "critical-section", + "defmt 1.1.0", + "embassy-sync", + "embassy-time", + "embassy-usb-driver", + "portable-atomic", +] + +[[package]] +name = "embedded-can" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9d2e857f87ac832df68fa498d18ddc679175cf3d2e4aa893988e5601baf9438" +dependencies = [ + "nb 1.1.0", +] + +[[package]] +name = "embedded-dma" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "994f7e5b5cb23521c22304927195f236813053eb9c065dd2226a32ba64695446" +dependencies = [ + "stable_deref_trait", +] + +[[package]] +name = "embedded-hal" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" +dependencies = [ + "nb 0.1.3", + "void", +] + +[[package]] +name = "embedded-hal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" + +[[package]] +name = "embedded-hal-async" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884" +dependencies = [ + "embedded-hal 1.0.0", +] + +[[package]] +name = "embedded-hal-nb" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fba4268c14288c828995299e59b12babdbe170f6c6d73731af1b4648142e8605" +dependencies = [ + "embedded-hal 1.0.0", + "nb 1.1.0", +] + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + +[[package]] +name = "embedded-io" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eb1aa714776b75c7e67e1da744b81a129b3ff919c8712b5e1b32252c1f07cc7" +dependencies = [ + "defmt 1.1.0", +] + +[[package]] +name = "embedded-io-async" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2564b9f813c544241430e147d8bc454815ef9ac998878d30cc3055449f7fd4c0" +dependencies = [ + "defmt 1.1.0", + "embedded-io 0.7.1", +] + +[[package]] +name = "embedded-storage" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21dea9854beb860f3062d10228ce9b976da520a73474aed3171ec276bc0c032" + +[[package]] +name = "embedded-storage-async" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1763775e2323b7d5f0aa6090657f5e21cfa02ede71f5dc40eead06d64dcd15cc" +dependencies = [ + "embedded-storage", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "fugit" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e639847d312d9a82d2e75b0edcc1e934efcc64e6cb7aa94f0b1fbec0bc231d6" +dependencies = [ + "gcd", +] + +[[package]] +name = "fugit-timer" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9607bfc4c388f9d629704f56ede4a007546cad417b3bcd6fc7c87dc7edce04a" +dependencies = [ + "fugit", + "nb 1.1.0", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", +] + +[[package]] +name = "gcd" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" + +[[package]] +name = "generator" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52f04ae4152da20c76fe800fa48659201d5cf627c5149ca0b707b69d7eef6cf9" +dependencies = [ + "cc", + "cfg-if", + "libc", + "log", + "rustversion", + "windows-link", + "windows-result", +] + +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32", + "stable_deref_trait", +] + +[[package]] +name = "heapless" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ba4bd83f9415b58b4ed8dc5714c76e626a105be4646c02630ad730ad3b5aa4" +dependencies = [ + "hash32", + "stable_deref_trait", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "litrs" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" + +[[package]] +name = "log" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616ec5685824bcc94416c6d4a7a446eea774a31efd7062c8480ba6fd06d7a6e5" + +[[package]] +name = "loom" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "nb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" +dependencies = [ + "nb 1.1.0", +] + +[[package]] +name = "nb" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "panic-probe" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd402d00b0fb94c5aee000029204a46884b1262e0c443f166d86d2c0747e1a1a" +dependencies = [ + "cortex-m", + "defmt 1.1.0", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "sdio-host" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b328e2cb950eeccd55b7f55c3a963691455dcd044cfb5354f0c5e68d2c2d6ee2" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "stm32-fmc" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72692594faa67f052e5e06dd34460951c21e83bc55de4feb8d2666e2f15480a2" +dependencies = [ + "embedded-hal 1.0.0", +] + +[[package]] +name = "stm32-metapac" +version = "21.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e74b78632cea498cfb28386a29f8bfae7476d6570a78733eb5fecbee66c2f4ce" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "defmt 0.3.100", +] + +[[package]] +name = "stm32-usbd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e633d559b5fe03caed24e1df85c9fa3916fe6191fc7099ac6fcb0281f380e9f0" +dependencies = [ + "cortex-m", + "usb-device", + "vcell", +] + +[[package]] +name = "stm32f1" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f2b32d5afdbd179dbfa05ad835e4623fb3790c187c2a8d6301eff1507b2c6c9" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "critical-section", + "portable-atomic", + "vcell", +] + +[[package]] +name = "stm32f1xx-hal" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f15ad470c8df998f9ef3a28dd625c7696179f091122235a971266999f8b0a66" +dependencies = [ + "bitflags 1.3.2", + "bxcan", + "cortex-m", + "cortex-m-rt", + "embedded-dma", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "embedded-hal-nb", + "embedded-io 0.6.1", + "fugit", + "fugit-timer", + "nb 1.1.0", + "stm32-usbd", + "stm32f1", + "vcell", + "void", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "trait-set" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b79e2e9c9ab44c6d7c20d5976961b47e8f49ac199154daa514b77cd1ab536625" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "usb-device" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98816b1accafbb09085168b90f27e93d790b4bfa19d883466b5e53315b5f06a6" +dependencies = [ + "heapless 0.8.0", + "portable-atomic", +] + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "vcell" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "volatile-register" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc" +dependencies = [ + "vcell", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..4a192ff --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,24 @@ +[workspace] +members = [ + "examples/blinky-basic", + "examples/blinky-timer", + "examples/button-input", + "examples/embassy-blinky", + "examples/embassy-button", +] +resolver = "2" + +[workspace.package] +edition = "2024" + +[workspace.dependencies] +cortex-m = { version = "=0.7.7", features = ["critical-section-single-core"] } +cortex-m-rt = "=0.7.5" +defmt = "=1.1.0" +defmt-rtt = "=1.2.0" +embassy-executor = "=0.10.0" +embassy-stm32 = "=0.6.0" +embassy-time = "=0.5.1" +nb = "=1.1.0" +panic-probe = { version = "=1.0.0", features = ["print-defmt"] } +stm32f1xx-hal = "=0.11.0" diff --git a/README.md b/README.md new file mode 100644 index 0000000..a4228e7 --- /dev/null +++ b/README.md @@ -0,0 +1,149 @@ +# Rust on STM32 + +## Hardware Baseline + +- Default board: STM32F103C8T6 Blue Pill, Cortex-M3 +- Default target: `thumbv7m-none-eabi` +- Default `probe-rs` chip name: `STM32F103C8` +- Default probe: ST-Link v2 +- Also supported in docs: Rusty Probe and other `probe-rs` compatible probes +- Onboard LED: usually `PC13`, active-low on most Blue Pill boards + +See [blue-pill.md](docs/hardware/blue-pill.md) for wiring notes. + +## Important Target Note + +- Blue Pill `STM32F103` is Cortex-M3 and uses `thumbv7m-none-eabi`. +- STM32F0 is Cortex-M0 and uses `thumbv6m-none-eabi`. +- Do not mix them. +- This repo leaves room for STM32F0 later, but the default path is STM32F103 only. + +## Repo Layout + +- [Cargo.toml](Cargo.toml) - workspace root and pinned shared dependencies +- [flake.nix](flake.nix) - reproducible development shell +- [.cargo/config.toml](.cargo/config.toml) - default target and linker settings +- [memory.x](memory.x) - conservative Blue Pill memory map +- [justfile](justfile) - build, flash, run, and lint commands +- [examples/README.md](examples/README.md) - example index + +## Nix Setup + +Use Nix flakes. No global `rustup`. No global `cargo install`. + +```bash +nix develop +``` + +The dev shell provides: + +- pinned Rust toolchain +- `cargo`, `rustc`, `rustfmt`, `clippy` +- `rust-src` +- targets for `thumbv7m-none-eabi` and `thumbv6m-none-eabi` +- `probe-rs` +- `flip-link` +- `cargo-binutils` +- `just` + +## First Commands + +```bash +nix develop +just build +just flash-blinky +just run-blinky +``` + +If your chip name differs from the default, override it: + +```bash +PROBE_RS_CHIP=STM32F103C8 just flash-blinky +``` + +If you need to inspect available names: + +```bash +probe-rs chip list | rg STM32F103 +``` + +## Examples + +- `blinky-basic` - plain `no_std` blink with a simple delay +- `blinky-timer` - periodic blink driven by a timer abstraction +- `button-input` - poll a button on `PA0`, mirror state on the LED, log transitions +- `embassy-blinky` - minimal async blink with Embassy +- `embassy-button` - minimal Embassy polling loop for a button on `PA0` + +The button examples assume a simple external button: + +- one side to `PA0` +- one side to `3V3` +- internal pull-down enabled in firmware +- common ground still required for the probe + +## ST-Link Setup + +Typical SWD wiring: + +- `SWDIO` -> `SWDIO` +- `SWCLK` -> `SWCLK` +- `GND` -> `GND` +- `3V3` -> `3V3` reference + +Keep `BOOT0` low for normal flash-and-run. + +## Rusty Probe / probe-rs Note + +- `probe-rs` is the primary flash, run, and debug path in this repo. +- Rusty Probe works if the host sees it as a `probe-rs` compatible probe. +- Start with `probe-rs list` to confirm the probe is visible. + +## Memory Note + +Many Blue Pill boards have 64K or 128K flash despite markings. +This repo uses a conservative 64K flash map in [memory.x](memory.x). + +## Troubleshooting + +### Probe not found + +- Run `probe-rs list`. +- Check USB cable and power. +- Check `SWDIO`, `SWCLK`, `GND`, and `3V3`. + +### Linux udev permissions + +- You may need udev rules for ST-Link or your probe. +- Install the vendor or distro rules, then replug the probe. + +### Wrong chip selected + +- Run `probe-rs chip list | rg STM32F103`. +- Override the default with `PROBE_RS_CHIP=...`. + +### No RTT or defmt output + +- Use `just run-blinky` or `just run-embassy-blinky`. +- Confirm the firmware did not crash early. +- Confirm the probe stays attached. +- Confirm `BOOT0` is low. + +### Blue Pill LED looks inverted + +- That is expected on most boards. +- `PC13` is usually active-low, so driving it low turns the LED on. + +## Safety + +- Check board voltage before connecting anything. +- Check `SWDIO`, `SWCLK`, `GND`, and `3V3` wiring before flashing. +- Do not assume a random button or LED pinout without checking the board. + +## Contribution + +- Keep examples independent. +- Keep demo reliability first. +- Keep `nix develop`, `just fmt`, `just check`, and `just build` working. +- Document hardware assumptions when they matter. +- Do not claim hardware-tested behavior unless it was actually tested on hardware. diff --git a/docs/hardware/blue-pill.md b/docs/hardware/blue-pill.md new file mode 100644 index 0000000..f4206df --- /dev/null +++ b/docs/hardware/blue-pill.md @@ -0,0 +1,28 @@ +# Blue Pill Notes + +## Baseline + +- Board: STM32F103C8T6 Blue Pill +- Core: Cortex-M3 +- Default target: `thumbv7m-none-eabi` + +## LED + +- Most Blue Pill boards wire the onboard LED to `PC13` +- It is usually active-low +- `set_low()` usually turns it on +- `set_high()` usually turns it off + +## Button Assumption + +- The repo button examples use `PA0` +- Assumed wiring: + - button between `PA0` and `3V3` + - firmware enables internal pull-down + +## Probe Wiring + +- `SWDIO` -> `SWDIO` +- `SWCLK` -> `SWCLK` +- `GND` -> `GND` +- `3V3` -> `3V3` reference diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..139ee9c --- /dev/null +++ b/examples/README.md @@ -0,0 +1,38 @@ +# Examples + +Each example is its own Cargo package. + +## Packages + +- `blinky-basic` - simple delay, simple LED ownership story +- `blinky-timer` - periodic blink with a timer abstraction +- `button-input` - poll `PA0`, mirror state to `PC13`, log transitions +- `embassy-blinky` - minimal Embassy executor and async blink +- `embassy-button` - minimal Embassy polling loop for `PA0` + +## Build One Example + +```bash +just build-blinky +just build-timer +just build-button +just build-embassy-blinky +just build-embassy-button +``` + +## Flash One Example + +```bash +just flash-blinky +just flash-timer +just flash-button +just flash-embassy-blinky +just flash-embassy-button +``` + +## Run With Logs + +```bash +just run-blinky +just run-embassy-blinky +``` diff --git a/examples/blinky-basic/Cargo.toml b/examples/blinky-basic/Cargo.toml new file mode 100644 index 0000000..08c0a95 --- /dev/null +++ b/examples/blinky-basic/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "blinky-basic" +version = "0.1.0" +edition = "2024" +publish = false +build = "build.rs" + +[dependencies] +cortex-m.workspace = true +cortex-m-rt.workspace = true +defmt.workspace = true +defmt-rtt.workspace = true +panic-probe.workspace = true +stm32f1xx-hal = { workspace = true, features = ["medium", "stm32f103"] } diff --git a/examples/blinky-basic/build.rs b/examples/blinky-basic/build.rs new file mode 100644 index 0000000..1295cd7 --- /dev/null +++ b/examples/blinky-basic/build.rs @@ -0,0 +1,9 @@ +fn main() { + println!("cargo:rerun-if-changed=../../memory.x"); + println!( + "cargo:rustc-link-search={}", + std::path::PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()) + .join("../..") + .display() + ); +} diff --git a/examples/blinky-basic/src/main.rs b/examples/blinky-basic/src/main.rs new file mode 100644 index 0000000..a0f22fe --- /dev/null +++ b/examples/blinky-basic/src/main.rs @@ -0,0 +1,37 @@ +#![deny(unsafe_code)] +#![no_std] +#![no_main] + +use cortex_m_rt::entry; +use defmt::info; +use defmt_rtt as _; +use panic_probe as _; +use stm32f1xx_hal::{pac, prelude::*}; + +const ON_MS: u16 = 500; +const OFF_MS: u16 = 500; + +#[entry] +fn main() -> ! { + let dp = pac::Peripherals::take().unwrap(); + let cp = cortex_m::Peripherals::take().unwrap(); + + let mut rcc = dp.RCC.constrain(); + let mut gpioc = dp.GPIOC.split(&mut rcc); + + // Splitting the GPIO block gives this function ownership of the LED pin. + let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh); + let mut delay = cp.SYST.delay(&rcc.clocks); + + info!("blinky-basic: PC13 LED is assumed active-low"); + + loop { + led.set_low(); + info!("led on"); + delay.delay_ms(ON_MS); + + led.set_high(); + info!("led off"); + delay.delay_ms(OFF_MS); + } +} diff --git a/examples/blinky-timer/Cargo.toml b/examples/blinky-timer/Cargo.toml new file mode 100644 index 0000000..62222f9 --- /dev/null +++ b/examples/blinky-timer/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "blinky-timer" +version = "0.1.0" +edition = "2024" +publish = false +build = "build.rs" + +[dependencies] +cortex-m.workspace = true +cortex-m-rt.workspace = true +defmt.workspace = true +defmt-rtt.workspace = true +nb.workspace = true +panic-probe.workspace = true +stm32f1xx-hal = { workspace = true, features = ["medium", "stm32f103"] } diff --git a/examples/blinky-timer/build.rs b/examples/blinky-timer/build.rs new file mode 100644 index 0000000..1295cd7 --- /dev/null +++ b/examples/blinky-timer/build.rs @@ -0,0 +1,9 @@ +fn main() { + println!("cargo:rerun-if-changed=../../memory.x"); + println!( + "cargo:rustc-link-search={}", + std::path::PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()) + .join("../..") + .display() + ); +} diff --git a/examples/blinky-timer/src/main.rs b/examples/blinky-timer/src/main.rs new file mode 100644 index 0000000..62d5b81 --- /dev/null +++ b/examples/blinky-timer/src/main.rs @@ -0,0 +1,35 @@ +#![deny(unsafe_code)] +#![no_std] +#![no_main] + +use cortex_m_rt::entry; +use defmt::info; +use defmt_rtt as _; +use nb::block; +use panic_probe as _; +use stm32f1xx_hal::{pac, prelude::*, timer::Timer}; + +const BLINK_HZ: u32 = 2; + +#[entry] +fn main() -> ! { + let dp = pac::Peripherals::take().unwrap(); + let cp = cortex_m::Peripherals::take().unwrap(); + + let mut rcc = dp.RCC.constrain(); + let mut gpioc = dp.GPIOC.split(&mut rcc); + let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh); + + // A timer gives stable periodic work without burning cycles in a delay loop. + let mut timer = Timer::syst(cp.SYST, &rcc.clocks).counter_hz(); + timer.start(BLINK_HZ.Hz()).unwrap(); + + led.set_high(); + info!("blinky-timer: {} Hz toggle loop", BLINK_HZ); + + loop { + block!(timer.wait()).unwrap(); + led.toggle(); + info!("tick"); + } +} diff --git a/examples/button-input/Cargo.toml b/examples/button-input/Cargo.toml new file mode 100644 index 0000000..3d175f8 --- /dev/null +++ b/examples/button-input/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "button-input" +version = "0.1.0" +edition = "2024" +publish = false +build = "build.rs" + +[dependencies] +cortex-m.workspace = true +cortex-m-rt.workspace = true +defmt.workspace = true +defmt-rtt.workspace = true +panic-probe.workspace = true +stm32f1xx-hal = { workspace = true, features = ["medium", "stm32f103"] } diff --git a/examples/button-input/build.rs b/examples/button-input/build.rs new file mode 100644 index 0000000..1295cd7 --- /dev/null +++ b/examples/button-input/build.rs @@ -0,0 +1,9 @@ +fn main() { + println!("cargo:rerun-if-changed=../../memory.x"); + println!( + "cargo:rustc-link-search={}", + std::path::PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()) + .join("../..") + .display() + ); +} diff --git a/examples/button-input/src/main.rs b/examples/button-input/src/main.rs new file mode 100644 index 0000000..987ee44 --- /dev/null +++ b/examples/button-input/src/main.rs @@ -0,0 +1,47 @@ +#![deny(unsafe_code)] +#![no_std] +#![no_main] + +use cortex_m_rt::entry; +use defmt::info; +use defmt_rtt as _; +use panic_probe as _; +use stm32f1xx_hal::{pac, prelude::*}; + +const POLL_MS: u8 = 25; + +#[entry] +fn main() -> ! { + let dp = pac::Peripherals::take().unwrap(); + let cp = cortex_m::Peripherals::take().unwrap(); + + let mut rcc = dp.RCC.constrain(); + let mut gpioa = dp.GPIOA.split(&mut rcc); + let mut gpioc = dp.GPIOC.split(&mut rcc); + + let button = gpioa.pa0.into_pull_down_input(&mut gpioa.crl); + let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh); + let mut delay = cp.SYST.delay(&rcc.clocks); + let mut was_pressed = button.is_high(); + + led.set_high(); + info!("button-input: PA0 button to 3V3 with internal pull-down"); + + loop { + let pressed = button.is_high(); + + if pressed != was_pressed { + was_pressed = pressed; + + if pressed { + led.set_low(); + info!("button pressed"); + } else { + led.set_high(); + info!("button released"); + } + } + + delay.delay_ms(POLL_MS); + } +} diff --git a/examples/embassy-blinky/Cargo.toml b/examples/embassy-blinky/Cargo.toml new file mode 100644 index 0000000..c04a020 --- /dev/null +++ b/examples/embassy-blinky/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "embassy-blinky" +version = "0.1.0" +edition = "2024" +publish = false +build = "build.rs" + +[dependencies] +cortex-m-rt.workspace = true +defmt.workspace = true +defmt-rtt.workspace = true +embassy-executor = { workspace = true, features = ["defmt", "executor-thread", "platform-cortex-m"] } +embassy-stm32 = { workspace = true, features = ["defmt", "stm32f103c8", "time-driver-tim2"] } +embassy-time.workspace = true +panic-probe.workspace = true diff --git a/examples/embassy-blinky/build.rs b/examples/embassy-blinky/build.rs new file mode 100644 index 0000000..1295cd7 --- /dev/null +++ b/examples/embassy-blinky/build.rs @@ -0,0 +1,9 @@ +fn main() { + println!("cargo:rerun-if-changed=../../memory.x"); + println!( + "cargo:rustc-link-search={}", + std::path::PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()) + .join("../..") + .display() + ); +} diff --git a/examples/embassy-blinky/src/main.rs b/examples/embassy-blinky/src/main.rs new file mode 100644 index 0000000..ac62e60 --- /dev/null +++ b/examples/embassy-blinky/src/main.rs @@ -0,0 +1,28 @@ +#![deny(unsafe_code)] +#![no_std] +#![no_main] + +use defmt::info; +use defmt_rtt as _; +use embassy_executor::Spawner; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_time::Timer; +use panic_probe as _; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + let mut led = Output::new(p.PC13, Level::High, Speed::Low); + + info!("embassy-blinky: async blink on PC13"); + + loop { + led.set_low(); + info!("led on"); + Timer::after_millis(500).await; + + led.set_high(); + info!("led off"); + Timer::after_millis(500).await; + } +} diff --git a/examples/embassy-button/Cargo.toml b/examples/embassy-button/Cargo.toml new file mode 100644 index 0000000..3b81746 --- /dev/null +++ b/examples/embassy-button/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "embassy-button" +version = "0.1.0" +edition = "2024" +publish = false +build = "build.rs" + +[dependencies] +cortex-m-rt.workspace = true +defmt.workspace = true +defmt-rtt.workspace = true +embassy-executor = { workspace = true, features = ["defmt", "executor-thread", "platform-cortex-m"] } +embassy-stm32 = { workspace = true, features = ["defmt", "stm32f103c8", "time-driver-tim2"] } +embassy-time.workspace = true +panic-probe.workspace = true diff --git a/examples/embassy-button/build.rs b/examples/embassy-button/build.rs new file mode 100644 index 0000000..1295cd7 --- /dev/null +++ b/examples/embassy-button/build.rs @@ -0,0 +1,9 @@ +fn main() { + println!("cargo:rerun-if-changed=../../memory.x"); + println!( + "cargo:rustc-link-search={}", + std::path::PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()) + .join("../..") + .display() + ); +} diff --git a/examples/embassy-button/src/main.rs b/examples/embassy-button/src/main.rs new file mode 100644 index 0000000..7fbdd80 --- /dev/null +++ b/examples/embassy-button/src/main.rs @@ -0,0 +1,38 @@ +#![deny(unsafe_code)] +#![no_std] +#![no_main] + +use defmt::info; +use defmt_rtt as _; +use embassy_executor::Spawner; +use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; +use embassy_time::Timer; +use panic_probe as _; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + let button = Input::new(p.PA0, Pull::Down); + let mut led = Output::new(p.PC13, Level::High, Speed::Low); + let mut was_pressed = button.is_high(); + + info!("embassy-button: polling PA0 every 25 ms"); + + loop { + let pressed = button.is_high(); + + if pressed != was_pressed { + was_pressed = pressed; + + if pressed { + led.set_low(); + info!("button pressed"); + } else { + led.set_high(); + info!("button released"); + } + } + + Timer::after_millis(25).await; + } +} diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..88af6b9 --- /dev/null +++ b/flake.lock @@ -0,0 +1,96 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1767313136, + "narHash": "sha256-16KkgfdYqjaeRGBaYsNrhPRRENs0qzkQVUooNHtoy2w=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "ac62194c3917d5f474c1a844b6fd6da2db95077d", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-25.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1744536153, + "narHash": "sha256-awS2zRgF4uTwrOKwwiJcByDzDOdo3Q1rPZbiHQg/N38=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "18dd725c29603f582cf1900e0d25f9f1063dbf11", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs", + "rust-overlay": "rust-overlay" + } + }, + "rust-overlay": { + "inputs": { + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1779679233, + "narHash": "sha256-qSIAAfK66X6waos6alIYxVze1ZU3C/WPp7NlN4ooP54=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "47ab6c7b3c6a68beac60067490240efa32ae344c", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..10fc3c3 --- /dev/null +++ b/flake.nix @@ -0,0 +1,55 @@ +{ + description = "Rust on STM32"; + + inputs = { + flake-utils.url = "github:numtide/flake-utils"; + nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05"; + rust-overlay.url = "github:oxalica/rust-overlay"; + }; + + outputs = { + self, + flake-utils, + nixpkgs, + rust-overlay, + }: + flake-utils.lib.eachDefaultSystem (system: let + pkgs = import nixpkgs { + inherit system; + overlays = [(import rust-overlay)]; + }; + + rustToolchain = + pkgs.rust-bin.stable."1.95.0".default.override { + extensions = [ + "clippy" + "llvm-tools-preview" + "rust-src" + "rustfmt" + ]; + targets = [ + "thumbv7m-none-eabi" + "thumbv6m-none-eabi" + ]; + }; + in { + devShells.default = pkgs.mkShell { + packages = [ + rustToolchain + pkgs.cargo-binutils + pkgs.flip-link + pkgs.just + pkgs.llvmPackages.bintools + pkgs.probe-rs + ]; + + RUST_SRC_PATH = "${rustToolchain}/lib/rustlib/src/rust/library"; + + shellHook = '' + echo "Rust on STM32 dev shell" + echo "Default target: thumbv7m-none-eabi" + echo "Flash and run commands use PROBE_RS_CHIP if you need to override the default." + ''; + }; + }); +} diff --git a/justfile b/justfile new file mode 100644 index 0000000..f284d5d --- /dev/null +++ b/justfile @@ -0,0 +1,62 @@ +set shell := ["bash", "-eu", "-o", "pipefail", "-c"] + +target := "thumbv7m-none-eabi" +chip := env_var_or_default("PROBE_RS_CHIP", "STM32F103C8") + +build: + cargo build --workspace + +build-blinky: + cargo build -p blinky-basic + +build-timer: + cargo build -p blinky-timer + +build-button: + cargo build -p button-input + +build-embassy-blinky: + cargo build -p embassy-blinky + +build-embassy-button: + cargo build -p embassy-button + +flash-blinky: + cargo build -p blinky-basic + probe-rs download --chip {{chip}} target/{{target}}/debug/blinky-basic + +flash-timer: + cargo build -p blinky-timer + probe-rs download --chip {{chip}} target/{{target}}/debug/blinky-timer + +flash-button: + cargo build -p button-input + probe-rs download --chip {{chip}} target/{{target}}/debug/button-input + +flash-embassy-blinky: + cargo build -p embassy-blinky + probe-rs download --chip {{chip}} target/{{target}}/debug/embassy-blinky + +flash-embassy-button: + cargo build -p embassy-button + probe-rs download --chip {{chip}} target/{{target}}/debug/embassy-button + +run-blinky: + cargo build -p blinky-basic + probe-rs run --chip {{chip}} target/{{target}}/debug/blinky-basic + +run-embassy-blinky: + cargo build -p embassy-blinky + probe-rs run --chip {{chip}} target/{{target}}/debug/embassy-blinky + +fmt: + cargo fmt --all + +clippy: + cargo clippy --workspace --bins -- -D warnings + +check: + cargo check --workspace + +clean: + cargo clean diff --git a/memory.x b/memory.x new file mode 100644 index 0000000..75ffdd9 --- /dev/null +++ b/memory.x @@ -0,0 +1,7 @@ +/* Conservative Blue Pill memory map. + Some boards expose 128K flash, but this repo stays within 64K. */ +MEMORY +{ + FLASH : ORIGIN = 0x08000000, LENGTH = 64K + RAM : ORIGIN = 0x20000000, LENGTH = 20K +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..3c625f4 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,5 @@ +[toolchain] +channel = "1.95.0" +components = ["clippy", "rustfmt", "rust-src", "llvm-tools-preview"] +targets = ["thumbv7m-none-eabi", "thumbv6m-none-eabi"] +profile = "minimal"