推荐例子:stm32f4xx-hal
要和版本对应,main 分支下的例子不一定符合发布版本的库
- Cortex-M3 架构
- OpenOCD: 调试翻译器,连接在 MCU 与 GDB 之间
- gdb-multiarch: MCU 的调试器
- QEMU: 模拟器
sudo apt install gdb-multiarch openocd qemu-system-arm可以先检查权限,不用安装 udev 规则
lsusb添加 MCU 工具链
rustup target add thumbv7em-none-eabihf #Cortex-M3cargo init . --bin --name=config-
安装 cortex-m, cortex-m-rt
cargo add cortex-m --features critical-section-single-core,inline-asm
- critical-section-single-core: 只支持单核 MCU 的临界区实现
- inline-asm: 支持内联汇编
cargo add cortex-m-rt
-
不用教程里面传统的同步框架, 采用现代化的异步框架 embassy,必须指定 features
cargo add embassy-stm32 --features stm32f407zg,time-driver-any,exti,defmt,memory-x
- stm32f407zg: 指定芯片型号
- time-driver-any: 使用 embassy-time 作为异步定时器驱动
- exti: 使能外部中断支持
- defmt: 支持 defmt 日志格式
- 如果开启了embassy-stm32的memory-x feature,那么就需要移除memory.x相关的配置,使用embassy内置的。
embassy-executor 需要你在 Cargo.toml 里开启至少一个 feature(比如 arch-cortex-m,再选一种执行器实现如 executor-thread 或 executor-interrupt)。否则它不知道该如何在你的 MCU 上跑 async 任务。
cargo add embassy-executor --features arch-cortex-m,executor-thread,defmt
-
panic 处理,否则不知道如何处理异常,这里采用特征: 通过 RTT + defmt 输出错误信息与堆栈
cargo add panic-probe --features print-defmt
-
日志库
cargo add defmt defmt-rtt
- defmt-rtt 是 嵌入式设备的超轻量日志输出系统,使用 RTT(Real-Time Transfer) 通道,把 MCU 内部的日志通过调试器(如 ST-Link / J-Link)实时传到主机显示。
-
时间处理
embassy-time 是 Embassy 的异步定时器与时间抽象库
cargo add embassy-time --features defmt,defmt-timestamp-uptime,tick-hz-32_768
- defmt: 支持 defmt 日志格式
- defmt-timestamp-uptime: defmt 日志的时间戳自动来自系统运行时间(Uptime)
- tick-hz-32_768: 设置 tick 频率为 32768Hz(RTC 常用低功耗时钟)提升定时精度
-
heapless 用于嵌入式系统的无堆内存数据结构
编译可以命令行执行
cargo build --target thumbv7em-none-eabihf或者写入到 .cargo/config.toml, 然后执行 cargo build 与上面等价
[build]
target = "thumbv7em-none-eabihf"会生成 target/thumbv7em-none-eabihf/debug/<projectName> 二进制文件
安装烧录工具 probe-rs
cargo install probe-rs-tools --locked查看烧录器
probe-rs list配置 .cargo/config.toml
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
runner = "probe-rs run --chip stm32f407zg"配置连接,写在 build.rs 里面
fn main() {
println!("cargo:rustc-link-arg-bins=--nmagic");
println!("cargo:rustc-link-arg-bins=-Tlink.x");
println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
}如果开启了embassy-stm32的memory-x feature,那么就需要移除memory.x相关的配置,使用embassy内置的。
针对 keil 生成的 hex 文件
probe-rs download --binary-format hex test.hex --chip STM32F407ZG-
烧录的时候记得硬件复位
-
ide 提示
#![no_std]can't find crate for test-
vscode 配置
{ "rust-analyzer.check.allTargets": false, "rust-analyzer.check.targets": "x86_64-unknown-linux-gnu" } -
或者在
Cargo.toml里面排除 test[[bin]] name = "config" test = false bench = false
-
运行文件都放到 src/bin 目录下, 采用 t_num_name.rs 命名方式
如果配置了
[[bin]]
name = "blink"
path = "src/bin/t_00_blink.rs"
test = false则可以直接运行
cargo run --bin blink如果是用了 lib.rs 这样的入口文件,则一定要声明 #![no_std]
// lib.rs
#![no_std]推挽输出在 Output 空间下面
let mut led0 = Output::new(p.PF9, Level::High, Speed::High);
led0.set_low();
led0.set_high();引入 embassy_hal_internal 这个库用来作封装
推挽输出
输入
let key = Input::new(p.PA0, Pull::Up);
key.is_high();
key.is_low();| EXTI线 | 中断函数 |
|---|---|
| EXTI0 | EXTI0_IRQHandler |
| EXTI1 | EXTI1_IRQHandler |
| EXTI2 | EXTI2_IRQHandler |
| EXTI3 | EXTI3_IRQHandler |
| EXTI4 | EXTI4_IRQHandler |
| EXTI5–9 | EXTI9_5_IRQHandler |
| EXTI10–15 | EXTI15_10_IRQHandler |
需要自己查芯片
可以多个通道,然后它是循环扫描。内存数据就是这样
[CH5, CH6, CH7, CH5, CH6, CH7, CH5, CH6, CH7, ...]