Basis for firmware

This commit is contained in:
Geens 2025-06-10 21:12:18 +02:00
parent 9311470b1c
commit b70026d562
8 changed files with 955 additions and 0 deletions

View File

@ -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

1
firmware/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
target/

350
firmware/Cargo.lock generated Normal file
View File

@ -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",
]

24
firmware/Cargo.toml Normal file
View File

@ -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

16
firmware/build.rs Normal file
View File

@ -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");
}

489
firmware/guide.md Normal file
View File

@ -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<u8, 64> = 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.

18
firmware/memory.x Normal file
View File

@ -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
}

45
firmware/src/main.rs Normal file
View File

@ -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);
}
}