From b70026d5624c69c0624a3ede0ead87b8dcc7b34c Mon Sep 17 00:00:00 2001 From: Geens Date: Tue, 10 Jun 2025 21:12:18 +0200 Subject: [PATCH] Basis for firmware --- firmware/.cargo/config.toml | 12 + firmware/.gitignore | 1 + firmware/Cargo.lock | 350 ++++++++++++++++++++++++++ firmware/Cargo.toml | 24 ++ firmware/build.rs | 16 ++ firmware/guide.md | 489 ++++++++++++++++++++++++++++++++++++ firmware/memory.x | 18 ++ firmware/src/main.rs | 45 ++++ 8 files changed, 955 insertions(+) create mode 100644 firmware/.cargo/config.toml create mode 100644 firmware/.gitignore create mode 100644 firmware/Cargo.lock create mode 100644 firmware/Cargo.toml create mode 100644 firmware/build.rs create mode 100644 firmware/guide.md create mode 100644 firmware/memory.x create mode 100644 firmware/src/main.rs diff --git a/firmware/.cargo/config.toml b/firmware/.cargo/config.toml new file mode 100644 index 0000000..a88825f --- /dev/null +++ b/firmware/.cargo/config.toml @@ -0,0 +1,12 @@ +[build] +target = "thumbv6m-none-eabi" + +[target.thumbv6m-none-eabi] +runner = "probe-rs run --chip STM32F042C4T6" +rustflags = [ + "-C", "link-arg=-Tlink.x", + "-C", "link-arg=--nmagic", +] + +[env] +DEFMT_LOG = "info" # Set logging level \ No newline at end of file diff --git a/firmware/.gitignore b/firmware/.gitignore new file mode 100644 index 0000000..9f97022 --- /dev/null +++ b/firmware/.gitignore @@ -0,0 +1 @@ +target/ \ No newline at end of file diff --git a/firmware/Cargo.lock b/firmware/Cargo.lock new file mode 100644 index 0000000..f835f10 --- /dev/null +++ b/firmware/Cargo.lock @@ -0,0 +1,350 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "bare-metal" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" +dependencies = [ + "rustc_version 0.2.3", +] + +[[package]] +name = "bare-metal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fe8f5a8a398345e52358e18ff07cc17a568fbca5c6f73873d3a62056309603" + +[[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 = "bxcan" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b13b4b2ea9ab2ba924063ebb86ad895cb79f4a79bf90f27949eb20c335b30f9" +dependencies = [ + "bitflags", + "nb 1.1.0", + "vcell", +] + +[[package]] +name = "cast" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c24dab4283a142afa2fdca129b80ad2c6284e073930f964c3a1293c225ee39a" +dependencies = [ + "rustc_version 0.4.1", +] + +[[package]] +name = "cortex-m" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" +dependencies = [ + "bare-metal 0.2.5", + "bitfield", + "critical-section", + "embedded-hal", + "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", +] + +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "defmt" +version = "0.3.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0963443817029b2024136fc4dd07a5107eb8f977eaf18fcd1fdeb11306b64ad" +dependencies = [ + "defmt 1.0.1", +] + +[[package]] +name = "defmt" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "548d977b6da32fa1d1fda2876453da1e7df63ad0304c8b3dae4dbe7b96f39b78" +dependencies = [ + "bitflags", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d4fc12a85bcf441cfe44344c4b72d58493178ce635338a3f3b78943aceb258e" +dependencies = [ + "defmt-parser", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn", +] + +[[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 = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6eca0aae8aa2cf8333200ecbd236274697bc0a394765c858b3d9372eb1abcfa" +dependencies = [ + "critical-section", + "defmt 0.3.100", +] + +[[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 = "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 = "panic-halt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de96540e0ebde571dc55c73d60ef407c653844e6f9a1e2fdbd40c07b9252d812" + +[[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", +] + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver 0.9.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver 1.0.26", +] + +[[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" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "stm32f0" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad6efffc472f66098c4ec84d5907b4d001c550db86a7dfa607adf1ba94adbf82" +dependencies = [ + "bare-metal 1.0.0", + "cortex-m", + "cortex-m-rt", + "vcell", +] + +[[package]] +name = "stm32f042c4-blinky" +version = "0.1.0" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "critical-section", + "defmt 0.3.100", + "defmt-rtt", + "embedded-hal", + "panic-halt", + "stm32f0xx-hal", +] + +[[package]] +name = "stm32f0xx-hal" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79544d457fe9a119c6fd02f0a16b8c20f39472b03199aac0a307d871a7015ad8" +dependencies = [ + "bare-metal 1.0.0", + "bxcan", + "cast", + "cortex-m", + "embedded-hal", + "nb 1.1.0", + "stm32f0", + "void", +] + +[[package]] +name = "syn" +version = "2.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6397daf94fa90f058bd0fd88429dd9e5738999cca8d701813c80723add80462" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[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", +] diff --git a/firmware/Cargo.toml b/firmware/Cargo.toml new file mode 100644 index 0000000..3c10051 --- /dev/null +++ b/firmware/Cargo.toml @@ -0,0 +1,24 @@ +[package] +edition = "2021" +name = "stm32f042c4-blinky" +version = "0.1.0" + +[dependencies] +cortex-m = { version = "0.7", features = ["inline-asm", "critical-section-single-core"] } +cortex-m-rt = "0.7" +critical-section = "1" +stm32f0xx-hal = { version = "0.18", features = ["stm32f042", "rt"] } +embedded-hal = "0.2" +panic-halt = "0.2" + +# For debugging and logging +defmt = "0.3" +defmt-rtt = "0.4" + +[profile.release] +debug = true # Keep debug info for better debugging +opt-level = "s" # Optimize for size +lto = true # Link-time optimization +codegen-units = 1 # Better optimization +panic = 'abort' # Reduce binary size +strip = false # Keep symbols for debugging diff --git a/firmware/build.rs b/firmware/build.rs new file mode 100644 index 0000000..d0c1913 --- /dev/null +++ b/firmware/build.rs @@ -0,0 +1,16 @@ +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Put memory.x in our output directory and ensure it's on linker search path + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + println!("cargo:rerun-if-changed=memory.x"); + println!("cargo:rustc-link-arg=--nmagic"); +} \ No newline at end of file diff --git a/firmware/guide.md b/firmware/guide.md new file mode 100644 index 0000000..27f7d1b --- /dev/null +++ b/firmware/guide.md @@ -0,0 +1,489 @@ +# STM32F042C4 Rust Development Guide + +Setting up Rust for STM32F042C4 microcontroller development has never been more streamlined, with modern tooling like **probe-rs** and mature HAL crates providing production-ready embedded development capabilities. This guide covers the complete workflow from environment setup through debugging with cheap ST-Link programmers, focusing on 2024-2025 best practices. + +The STM32F042C4 is a Cortex-M0-based microcontroller with 16KB Flash and 6KB RAM, requiring careful memory management but offering excellent USB and CAN capabilities. With probe-rs becoming the standard debugging tool and stm32f0xx-hal providing robust hardware abstraction, Rust embedded development now rivals traditional C/C++ toolchains while offering memory safety guarantees. + +## Rust development environment setup + +### Core toolchain installation + +The foundation requires Rust with ARM compilation targets and modern embedded tooling: + +```bash +# Install Rust via rustup +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh +source ~/.cargo/env + +# Add ARM Cortex-M0 target for STM32F042C4 +rustup target add thumbv6m-none-eabi + +# Install essential binary utilities +rustup component add llvm-tools-preview +cargo install cargo-binutils + +# Install modern debugging and flashing tools +cargo install probe-rs --features cli +cargo install cargo-generate # For project templates +``` + +**probe-rs has emerged as the recommended tool** replacing OpenOCD for most STM32 Rust development. It provides native Rust integration, superior VS Code support, and built-in RTT logging without the complexity of GDB configuration. + +### Platform-specific dependencies + +**Linux systems** need additional development libraries: +```bash +# Ubuntu/Debian +sudo apt install libudev-dev pkg-config + +# Fedora +sudo dnf install libudev-devel pkgconf-pkg-config + +# Install udev rules for non-root probe access +sudo curl -L https://probe.rs/files/99-probe-rs.rules -o /etc/udev/rules.d/99-probe-rs.rules +sudo udevadm control --reload +``` + +**Windows systems** require Visual Studio Build Tools and will need WinUSB drivers for ST-Link clones using the Zadig tool. **macOS** typically works out of the box with Homebrew-installed dependencies. + +## STM32F042C4 specifications and HAL integration + +### Device characteristics + +The STM32F042C4T6 features an **ARM Cortex-M0 core running up to 48 MHz** with constrained but sufficient resources for many embedded applications: + +- **Flash Memory**: 16KB starting at 0x08000000 +- **SRAM**: 6KB starting at 0x20000000 +- **Key Peripherals**: USB 2.0 Full-speed, CAN bus, 2x USART, 2x SPI, I2C, 12-bit ADC +- **Architecture Target**: `thumbv6m-none-eabi` + +### Using stm32f0xx-hal crate + +The **stm32f0xx-hal crate** provides comprehensive hardware abstraction for the STM32F0 family, including specific support for the F042 variant: + +```toml +[dependencies] +cortex-m = "0.7" +cortex-m-rt = "0.7" +stm32f0xx-hal = { version = "0.18", features = ["stm32f042", "rt"] } +embedded-hal = "0.2" +panic-halt = "0.2" + +# Optional: Enable USB or CAN support +stm32-usbd = { version = "0.6", optional = true } +bxcan = { version = "0.8", optional = true } +``` + +The **"stm32f042" feature flag** ensures chip-specific peripheral configurations are available. The HAL implements standard embedded-hal traits for portability across different HAL implementations. + +## Project structure and configuration + +### Recommended project layout + +Modern STM32 Rust projects follow this structure: + +``` +stm32f042c4-project/ +├── Cargo.toml +├── build.rs +├── memory.x +├── .cargo/ +│ └── config.toml +├── src/ +│ └── main.rs +├── examples/ +│ └── blinky.rs +└── openocd.cfg (if using OpenOCD) +``` + +### Complete Cargo.toml configuration + +```toml +[package] +edition = "2021" +name = "stm32f042c4-blinky" +version = "0.1.0" + +[dependencies] +cortex-m = { version = "0.7", features = ["inline-asm"] } +cortex-m-rt = "0.7" +stm32f0xx-hal = { version = "0.18", features = ["stm32f042", "rt"] } +embedded-hal = "0.2" +panic-halt = "0.2" + +# For debugging and logging +defmt = "0.3" +defmt-rtt = "0.4" + +[profile.release] +debug = true # Keep debug info for better debugging +opt-level = "s" # Optimize for size (critical with 16KB Flash) +lto = true # Link-time optimization +codegen-units = 1 # Better optimization +panic = 'abort' # Reduce binary size +strip = false # Keep symbols for debugging +``` + +### Cargo configuration (.cargo/config.toml) + +```toml +[build] +target = "thumbv6m-none-eabi" + +[target.thumbv6m-none-eabi] +runner = "probe-rs run --chip STM32F042C4T6" +rustflags = [ + "-C", "link-arg=-Tlink.x", + "-C", "link-arg=--nmagic", +] + +[env] +DEFMT_LOG = "info" # Set logging level +``` + +### Build script (build.rs) + +```rust +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Put memory.x in our output directory and ensure it's on linker search path + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + println!("cargo:rerun-if-changed=memory.x"); + println!("cargo:rustc-link-arg=--nmagic"); +} +``` + +## Memory.x configuration for STM32F042C4 + +The memory.x file defines the exact memory layout critical for proper linking: + +```linker-script +MEMORY +{ + /* STM32F042C4T6 specific memory layout */ + FLASH : ORIGIN = 0x08000000, LENGTH = 16K + RAM : ORIGIN = 0x20000000, LENGTH = 6K +} + +/* Stack grows downward from end of RAM */ +_stack_start = ORIGIN(RAM) + LENGTH(RAM); + +/* Custom sections for USB descriptors if needed */ +SECTIONS +{ + .usb_descriptors : + { + KEEP(*(.usb_descriptors.*)); + } > FLASH +} +``` + +**Critical memory constraints:** With only 16KB Flash and 6KB RAM, every byte matters. Always use release builds with size optimization (`opt-level = "s"`) and avoid dynamic allocation. + +## Basic blinking LED example + +Here's a complete blinking LED implementation optimized for STM32F042C4: + +```rust +#![no_std] +#![no_main] + +use panic_halt as _; +use cortex_m_rt::entry; +use stm32f0xx_hal::{ + prelude::*, + stm32, + delay::Delay, + gpio::*, +}; + +#[entry] +fn main() -> ! { + // Get device peripherals + let mut dp = stm32::Peripherals::take().unwrap(); + let cp = cortex_m::Peripherals::take().unwrap(); + + // Configure the clock to 48 MHz + let mut rcc = dp.RCC.configure() + .hsi48() + .enable_crs(dp.CRS) + .sysclk(48.mhz()) + .pclk(24.mhz()) + .freeze(&mut dp.FLASH); + + // Set up delay provider + let mut delay = Delay::new(cp.SYST, &rcc); + + // Configure GPIO + let gpioa = dp.GPIOA.split(&mut rcc); + + // Configure PA5 as push-pull output (common LED pin) + let mut led = gpioa.pa5.into_push_pull_output(&mut gpioa.moder, &mut gpioa.otyper); + + // Blink loop + loop { + led.set_high().ok(); + delay.delay_ms(500u16); + + led.set_low().ok(); + delay.delay_ms(500u16); + } +} +``` + +### Advanced LED example with RTT logging + +For debugging, add RTT logging capability: + +```rust +#![no_std] +#![no_main] + +use defmt::info; +use defmt_rtt as _; +use panic_halt as _; +use cortex_m_rt::entry; +use stm32f0xx_hal::{prelude::*, stm32, delay::Delay}; + +#[entry] +fn main() -> ! { + info!("Starting STM32F042C4 blinky with RTT logging"); + + let mut dp = stm32::Peripherals::take().unwrap(); + let cp = cortex_m::Peripherals::take().unwrap(); + + let mut rcc = dp.RCC.configure() + .hsi48() + .enable_crs(dp.CRS) + .sysclk(48.mhz()) + .freeze(&mut dp.FLASH); + + let mut delay = Delay::new(cp.SYST, &rcc); + let gpioa = dp.GPIOA.split(&mut rcc); + let mut led = gpioa.pa5.into_push_pull_output(&mut gpioa.moder, &mut gpioa.otyper); + + let mut counter = 0u32; + loop { + led.toggle().ok(); + info!("LED toggle #{}", counter); + counter += 1; + delay.delay_ms(1000u16); + } +} +``` + +## ST-Link clone setup and usage + +### Understanding ST-Link clones + +**ST-Link clones** are widely available Chinese copies of ST's official programming adapters, typically costing $2-5 versus $25+ for genuine hardware. However, they require careful setup and have reliability considerations. + +**Common clone issues include:** +- Inconsistent pinouts that don't match labeling +- Poor build quality causing intermittent connections +- Power delivery problems affecting target stability +- Firmware limitations blocking certain features + +### Essential wiring verification + +**Always verify pinout with a multimeter** before connecting. Standard connections should be: + +``` +ST-Link Clone STM32F042C4 +GND → GND +SWDIO → SWDIO (PA13) +SWCLK → SWCLK (PA14) +VAPP/VTref → 3.3V (CRITICAL - sets programming voltage) +VDD → 3.3V (if powering target from ST-Link) +``` + +**The VAPP connection is critical** - ST-Link determines programming voltage from this pin even when the target has external power. + +### Driver installation + +**Linux**: probe-rs works with standard udev rules: +```bash +sudo curl -L https://probe.rs/files/99-probe-rs.rules -o /etc/udev/rules.d/99-probe-rs.rules +sudo udevadm control --reload +``` + +**Windows**: Use Zadig to install WinUSB drivers for the ST-Link device. Download Zadig from https://zadig.akeo.ie/, select the ST-Link device, and install WinUSB driver. + +### Programming workflow with probe-rs + +**Basic commands:** +```bash +# List connected probes +probe-rs list + +# Get target information +probe-rs info --chip STM32F042C4T6 + +# Flash and run with RTT output +probe-rs run --chip STM32F042C4T6 target/thumbv6m-none-eabi/debug/blinky + +# Flash only without running +probe-rs download target/thumbv6m-none-eabi/release/blinky.elf --chip STM32F042C4T6 +``` + +**Cargo integration** enables `cargo run` to automatically flash and run: +```bash +# Build and flash in one command +cargo run --release + +# Build only +cargo build --release +``` + +## VS Code debugging and development workflow + +### Essential VS Code extensions + +1. **rust-analyzer** - Core Rust language support +2. **probe-rs** - Native debugging integration with DAP +3. **Cortex-Debug** - Alternative debugging option + +### VS Code launch configuration + +Create `.vscode/launch.json`: + +```json +{ + "version": "0.2.0", + "configurations": [ + { + "type": "probe-rs-debug", + "request": "launch", + "name": "Debug STM32F042C4", + "chip": "STM32F042C4T6", + "flashingConfig": { + "flashingEnabled": true, + "resetAfterFlashing": true, + "haltAfterReset": true + }, + "coreConfigs": [ + { + "coreIndex": 0, + "programBinary": "target/thumbv6m-none-eabi/debug/stm32f042c4-blinky", + "rttEnabled": true + } + ] + } + ] +} +``` + +This configuration enables **full debugging with breakpoints, variable inspection, and RTT logging** directly in VS Code. + +## Troubleshooting common issues + +### Memory and linking problems + +**"RAM overflowed" error** indicates stack or static variable overflow in the 6KB RAM constraint: +- Reduce stack-allocated arrays +- Use `static` variables instead of stack allocation +- Monitor memory usage with `cargo size` + +**"Load failed" during flashing** typically indicates incorrect memory.x values: +- Verify Flash size (16KB for STM32F042C4, not 32KB) +- Check SRAM size (6KB total) +- Ensure addresses match datasheet exactly + +### ST-Link connection issues + +**"No ST-Link detected" errors:** +1. Check USB cable quality and try different ports +2. Verify VAPP pin connection to target 3.3V +3. Ensure target has stable power supply +4. Try reducing programming speed: `--speed 1000` + +**Intermittent connection losses:** +- ST-Link clones often have poor power regulation +- Use external 3.3V supply for target instead of ST-Link power +- Add decoupling capacitors near the microcontroller + +### BOOT0 pin configuration + +**Program flashes but doesn't run** often indicates BOOT0 pin issues: +- BOOT0 must be LOW (connected to GND) for normal flash execution +- BOOT0 HIGH boots into system bootloader instead of user program +- Some development boards have BOOT0 jumpers requiring proper positioning + +### Debugging workflow optimization + +**RTT logging setup** for efficient debugging: +```rust +use defmt_rtt as _; +use defmt::{info, debug, error}; + +// Use throughout your code +info!("System initialized"); +debug!("Variable value: {}", variable); +error!("Critical error occurred"); +``` + +**Avoid WFI instruction** when using RTT, as it can interfere with real-time transfer communication. + +## Advanced considerations and best practices + +### Memory optimization strategies + +With only 16KB Flash, **aggressive optimization is essential:** + +```toml +[profile.release] +opt-level = "s" # Size optimization +lto = true # Link-time optimization +codegen-units = 1 # Better optimization +panic = 'abort' # Smaller panic handler +``` + +**Use `heapless` collections** instead of `std` alternatives: +```rust +use heapless::Vec; +use heapless::String; + +let mut buffer: Vec = Vec::new(); // Stack-allocated vector +let mut text: String<32> = String::new(); // Stack-allocated string +``` + +### Power management integration + +STM32F042C4 supports multiple low-power modes. **Basic sleep implementation:** + +```rust +use cortex_m::asm; +use stm32f0xx_hal::power::PowerMode; + +// Enter sleep mode +cortex_m::interrupt::free(|_| { + asm::wfi(); // Wait for interrupt +}); +``` + +### USB device development + +The STM32F042C4's **crystal-less USB capability** makes it ideal for USB projects: + +```rust +use stm32_usbd::UsbBus; +use usb_device::prelude::*; + +// USB setup requires specific clock configuration +let mut rcc = dp.RCC.configure() + .hsi48() + .enable_crs(dp.CRS) // Clock recovery system for crystal-less USB + .sysclk(48.mhz()) // Required for USB + .freeze(&mut dp.FLASH); +``` + +This comprehensive guide establishes a complete STM32F042C4 Rust development environment using modern 2024-2025 tooling. The combination of probe-rs for debugging, stm32f0xx-hal for hardware abstraction, and careful memory management provides a robust foundation for embedded development that rivals traditional C/C++ workflows while offering Rust's memory safety guarantees. \ No newline at end of file diff --git a/firmware/memory.x b/firmware/memory.x new file mode 100644 index 0000000..fbe12fd --- /dev/null +++ b/firmware/memory.x @@ -0,0 +1,18 @@ +MEMORY +{ + /* STM32F042C4T6 specific memory layout */ + FLASH : ORIGIN = 0x08000000, LENGTH = 16K + RAM : ORIGIN = 0x20000000, LENGTH = 6K +} + +/* Stack grows downward from end of RAM */ +_stack_start = ORIGIN(RAM) + LENGTH(RAM); + +/* Custom sections for USB descriptors if needed */ +SECTIONS +{ + .usb_descriptors : + { + KEEP(*(.usb_descriptors.*)); + } > FLASH +} \ No newline at end of file diff --git a/firmware/src/main.rs b/firmware/src/main.rs new file mode 100644 index 0000000..31ebbf9 --- /dev/null +++ b/firmware/src/main.rs @@ -0,0 +1,45 @@ +#![no_std] +#![no_main] + +use panic_halt as _; +use cortex_m_rt::entry; +use stm32f0xx_hal::{ + prelude::*, + stm32, + delay::Delay, +}; + +#[entry] +fn main() -> ! { + // Get device peripherals + let mut dp = stm32::Peripherals::take().unwrap(); + let cp = cortex_m::Peripherals::take().unwrap(); + + // Configure the clock to 48 MHz + let mut rcc = dp.RCC.configure() + .hsi48() + .enable_crs(dp.CRS) + .sysclk(48.mhz()) + .pclk(24.mhz()) + .freeze(&mut dp.FLASH); + + // Set up delay provider + let mut delay = Delay::new(cp.SYST, &rcc); + + // Configure GPIO + let gpioa = dp.GPIOA.split(&mut rcc); + + // Configure PA5 as push-pull output (common LED pin) + let mut led = cortex_m::interrupt::free(|cs| { + gpioa.pa5.into_push_pull_output(cs) + }); + + // Blink loop + loop { + led.set_high().ok(); + delay.delay_ms(500u16); + + led.set_low().ok(); + delay.delay_ms(500u16); + } +} \ No newline at end of file