【Rust】搭建Rust嵌入式环境并点亮一颗LED
1. 安装运行环境
本文章默认已经安装好rust语言的基础环境
Rust在嵌入式中都是基于rust-embedded/embedded-hal: A Hardware Abstraction Layer (HAL) for embedded systems这个库的接口来开发的HAL库,因此在不同MCU中移植代码会变得比较方便。
目前,常见的MCU基本都有现成的HAL库可用,本文会以stm32f407vgt6为例,进行介绍。
1.1 交叉编译工具链
以stm32f407为例,该MCU采用ARM-Cortex-M4架构,并且带FPU,使用以下命令
rustup target add thumbv7em-none-eabihf
1.2 cargo-generate
可以使用cargo-generate从模板生成项目。
cargo install cargo-generate
1.3 OpenOCD
OpenOCD是一款开源的嵌入式调试软件,我们用它来烧录程序和调试程序。
打开OpenOCD的开源链接xpack-dev-tools/openocd-xpack: A binary distribution of OpenOCD,下载对应系统的release版本并解压,将bin目录配置到环境变量中即可。
同时可以安装上st-link的驱动,确保OpenOCD可以正常工作。
2. 创建项目
使用上面安装的cargo-generate可以方便的创建嵌入式项目
cargo generate --git https://github.com/burrbull/stm32-template/
此时需要输入项目名称和项目的一些基础信息,输入完成我们的项目就创建好了,使用vscode打开项目目录。
2.1 修改项目配置
2.1.1 Cargo.toml
从模板创建的项目里面使用的crates版本可能比较老了,我们可以修改这个文件来选择新版本的crate,打开Cargo.toml
可以在crates.io: Rust Package Registry上查找dependencies的版本,修改后面的版本号即可
[dependencies]
embedded-hal = "1.0.0"
nb = "1"
cortex-m = "0.7"
cortex-m-rt = "0.7"
# Panic behaviour, see https://crates.io/keywords/panic-impl for alternatives
panic-halt = "0.2"
[dependencies.stm32f4xx-hal]
version = "0.22.1"
features = ["stm32f407"]
其中的cortex-m和cortex-m-rt为我们提供了Cortex-M内核MCU运行时的一个外设的接口,而panic-halt是当程序出现panic的时候,MCU会停止工作,下面的stm32f4xx-hal就是我们MCU对应的hal库了。
2.1.2 config.toml
打开.cargo目录下的config.toml文件,找到[build],把target修改为我们在上面添加的target,例如我这里就是
[build]
target = "thumbv7em-none-eabihf"
3. 编写代码
终于来到了最令人激动的写bug写代码环节,作为第一个项目当然不能缺少了嵌入式的hello world--点灯。
打开main.rs,引入眼帘的是模板为我们提供的默认代码:
#![no_std]
#![no_main]
// pick a panicking behavior
use panic_halt as _; // you can put a breakpoint on `rust_begin_unwind` to catch panics
// use panic_abort as _; // requires nightly
// use panic_itm as _; // logs messages over ITM; requires ITM support
// use panic_semihosting as _; // logs messages to the host stderr; requires a debugger
use cortex_m::asm;
use cortex_m_rt::entry;
#[entry]
fn main() -> ! {
asm::nop(); // To not have main optimize to abort in release mode, remove when you add code
loop {
// your code goes here
}
}
最上面的两行表明了该项目是没有主函数的,并且是一个非标准库的项目。没有主函数那么程序的入口在哪里呢?
往下我们可以看到use cortex_m_rt::entry;
这一行,它引入了Cortex-M内核的entry标识,而entry标识下方的函数就是我们的入口函数,也就是fn main() -> !
这个函数了。
3.1 修改main.rs
#![deny(unsafe_code)]
#![no_main]
#![no_std]
// Halt on panic
use panic_halt as _;
use cortex_m_rt::entry;
use stm32f4xx_hal::{gpio::Speed, pac, prelude::*};
#[allow(clippy::empty_loop)]
#[entry]
fn main() -> ! {
if let (Some(dp), Some(cp)) = (
pac::Peripherals::take(),
cortex_m::peripheral::Peripherals::take(),
) {
let gpiob = dp.GPIOB.split();
let mut led = gpiob.pb2.into_push_pull_output().speed(Speed::High);
let rcc = dp.RCC.constrain();
let clocks = rcc.cfgr.sysclk(48.MHz()).freeze();
let mut delay = cp.SYST.delay(&clocks);
loop {
led.toggle();
delay.delay_ms(500);
}
}
loop {}
}
上述代码里我们引入了stm32f407的hal库,hal库中的pac是rust开发嵌入式的一个重点,它的全称为Peripheral Access Crates外设访问层,通过pac我们可以访问到MCU下的所有外设。如果使用的MCU偏冷门,没有现成的pac可用,我们也可以使用芯片的SVD文件,通过svd2rust生成对应的pac库。
进入到main函数中,我们首先使用了pac::Peripherals::take();
来获取cortex-m的核心,使用cortex_m::peripheral::Peripherals::take();
获取mcu上的所有外设。
然后通过dp获取到gpiob的接口,将pb2配置为推挽输出,把系统时钟频率设置为48MHz,使用cortex-m crate提供的一个SYST接口实现一个简单的延时。
最后在loop主循环里,翻转led电平并延时500ms,实现了led的闪烁。
3.2 烧录
首先创建一个OpenOCD的配置文件openocd.cfg
source [find interface/stlink.cfg]
transport select hla_swd
source [find target/stm32f4x.cfg]
adapter speed 1800
打开vscode的tasks.json为烧录配置一个任务
{
"label": "Flash",
"type": "shell",
"command": "openocd",
"args": [
"-f",
"openocd.cfg",
"-c",
"tcl_port disabled",
"-c",
"gdb_port disabled",
"-c",
"tcl_port disabled",
"-c",
"program target/thumbv7em-none-eabihf/debug/stm32f407_rs_demo",
"-c",
"reset",
"-c",
"shutdown"
],
"dependsOn": [
"cargo_build(debug)"
],
"group": {
"kind": "build",
},
"problemMatcher": []
}
其中的openocd.cfg和program根据实际情况选择编译好的文件的位置,然后连接好st-link和开发板,ctrl+shift+p,运行这个build task即可。
Comments NOTHING