使用rust开发stm32体验
以下的示例是基于STM32F411的完整demo,需要安装rust相关工具链以及probe-rs
# gnu工具链
rustup toolchain install stable-x86_64-pc-windows-gnu
rustup default stable-x86_64-pc-windows-gnu
# probe-rs
cargo install probe-rs cargo-flash cargo-embed cargo cargo-update
# cargo install-update -a 是用于更新rust install安装的工具
# 查看固件大小所要的包
cargo install cargo-bloat cargo-binutils
# 如果安装失败可以尝试 --lock 参数避免本地包与原工程不一致,例如cargo install office2pdf --lock
rustup component add llvm-tools-preview
# 查看固件大小,按需使用
cargo size
cargo size -- -A
cargo size --release -- -A
cargo bloat --release # 查看最大的函数
cargo bloat --release --crates# 只看你的 crate
file path >> ./src/main.rs:
#![no_std]
#![no_main]
use stm32f4xx_hal::{self as hal}; // memory layout + panic handler
use hal::prelude::*;
use cortex_m_rt::entry;
use hal::interrupt;
use core::cell::RefCell;
use cortex_m::interrupt::Mutex;
static SERIAL1: Mutex<RefCell<Option<hal::serial::Serial<hal::pac::USART1>>>> = Mutex::new(RefCell::new(None));
// use rtt_target::{rprintln, rtt_init_print};
use defmt_rtt as _; // 全局日志通道,只需引入
use panic_probe as _; // 可选:panic 时打印 defmt 日志
#[entry]
fn main() -> ! {
//rtt_init_print!();
let dp = hal::pac::Peripherals::take().unwrap();
let cp = hal::pac::CorePeripherals::take().unwrap();
let mut rcc = dp.RCC.freeze(hal::rcc::Config::hse(25.MHz()).sysclk(100.MHz()));
let mut delay = cp.SYST.delay(&rcc.clocks);
let gpioc = dp.GPIOC.split(&mut rcc);
let gpioa = dp.GPIOA.split(&mut rcc);
let mut led = gpioc.pc13.into_push_pull_output();
let usart1 = dp.USART1;
let tx_pin = gpioa.pa9;
let rx_pin = gpioa.pa10;
let mut serial: hal::serial::Serial<hal::pac::USART1> = hal::serial::Serial::new(
usart1,
(tx_pin, rx_pin),
hal::serial::config::Config::default().baudrate(115_200.bps()),
&mut rcc,
).unwrap();
unsafe {
// Enable USART1 interrupt
hal::pac::NVIC::unmask(hal::pac::Interrupt::USART1);
}
serial.listen(hal::serial::Event::RxNotEmpty);
cortex_m::interrupt::free(|cs| {
SERIAL1.borrow(cs).replace(Some(serial));
});
loop {
led.set_low();
delay.delay_ms(500);
led.set_high();
delay.delay_ms(500);
}
}
#[interrupt]
fn USART1() {
cortex_m::interrupt::free(|cs| {
if let Some(serial) = SERIAL1.borrow(cs).borrow_mut().as_mut() {
if let Ok(byte) = serial.read() {
//rprintln!("Received: {} ('{}')", byte, byte as char);
defmt::info!("Received: {} ('{}')", byte, byte as char); // 类似 info!
// Echo received byte
let _ = serial.write(byte);
}
}
});
}
file path >> memory.x
MEMORY
{
RAM : ORIGIN = 0x20000000, LENGTH = 128K
FLASH : ORIGIN = 0x8000000, LENGTH = 512K
}
_stack_start = ORIGIN(RAM) + LENGTH(RAM);
file path >> Cargo.toml
[package]
name = "blinky_f411"
version = "0.1.0"
edition = "2024"
[dependencies]
embedded-hal = "1.0"
nb = "1.1"
cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] }
cortex-m-rt = "0.7"
panic-halt = "1.0"
# rtt-target = "0.6"
defmt = "1.0"
defmt-rtt = "1.1" # RTT 传输后端
panic-probe = "1.0" # 可选:panic 时打印 defmt 日志
[dependencies.stm32f4xx-hal]
version = "0.23.0"
features = ["stm32f411"] # replace the model of your microcontroller here
# and add other required features
[[bin]]
name = "blinky_f411"
test = false
bench = false
[profile.dev]
panic="unwind"
lto = true
[profile.release]
panic="unwind"
lto = true
opt-level = "z"
[build-dependencies]
cc = "1.2"
bindgen = "0.72"
file path >> .cargo/config.toml
[target.thumbv7em-none-eabihf]
runner = "probe-rs download --chip STM32F411CE"
[build]
target = "thumbv7em-none-eabihf"
rustflags = [
"-C", "link-arg=-Tlink.x",
]
[alias]
# 示例 cargo bin
bin = "objcopy --release -- -O binary target/firmware.bin"
hex = "objcopy --release -- -O ihex target/firmware.hex"
size-rel = "size --release -- -A"
bloat-rel = "bloat --release"
build-rel = "build --release"
run-rel = "run --release"