赞
踩
网上很多教程都是直接调用对应芯片的HAL库,让初学者认为操作都被Rust嵌入式开源组封装好了,直接调就好。这在目前Rust嵌入式生态还不成熟的情况下可能是个误解。
实际上Rust嵌入式有自己独特的层级关系,这一方面可以参考b站up主“爆米花胡了”的视频。其中负责访问寄存器的是PAC,与C语言直接访问内存地址不同,PAC层的代码依赖每个新品提供的svd文件自动生成,相当参考svd层的寄存器访问规范,为开发者提供了一系列寄存器的Rust访问方式。依赖PAC层的Rust嵌入式寄存器编程就是调用这些访问寄存器的api。
先别急,先搭建Rust嵌入式开发环境
1.对于编译,我们需要为rustc添加交叉编译的target
rustup target add armv7em-none-eabi
2.为了简单的烧录,我们选择使用cargo-flash这样的玩具工具
cargo install cargo-flash
3.接着,为你的烧录器安装驱动
1.新建一个cargo项目
2.在项目根目录下新建 .cago 隐藏文件夹,在 .cargo 内新建config.toml
在config.toml内编辑
- [build]
- target = "thumbv7em-none-eabihf"
- rustflags = [
- "-C", "link-arg=-Tlink.x",
- ]
这一步是指定target和编辑、链接参数
3.在项目根目录下新建build.rs
- //! This build script copies the `memory.x` file from the crate root into
- //! a directory where the linker can always find it at build time.
- //! For many projects this is optional, as the linker always searches the
- //! project root directory -- wherever `Cargo.toml` is. However, if you
- //! are using a workspace or have a more complicated build setup, this
- //! build script becomes required. Additionally, by requesting that
- //! Cargo re-run the build script whenever `memory.x` is changed,
- //! updating `memory.x` ensures a rebuild of the application with the
- //! new memory settings.
-
- 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 the 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());
-
- // By default, Cargo will re-run a build script whenever
- // any file in the project changes. By specifying `memory.x`
- // here, we ensure the build script is only re-run when
- // `memory.x` is changed.
- println!("cargo:rerun-if-changed=memory.x");
- }
4.我们再建立上面的编译脚本指定的 memory.x
- MEMORY
- {
- FLASH : ORIGIN = 0x08000000, LENGTH = 256K
- RAM : ORIGIN = 0x20000000, LENGTH = 64K
- }
5.随后修改项目根目录Cargo.toml,加入PAC包
- [dependencies]
- cortex-m = "0.7.4"
- cortex-m-rt = "0.7.1"
- stm32f4 = { version = "0.14.0", features = ["stm32f412", "rt"] }
这里的具体新品型号根据自己芯片选择,其中cortex-m的两个是cortex-m内核通用的内核编程接口,stm32f4即是厂商特定的PAC编程接口,用于访问各种寄存器和芯片功能。
6.终于可以开始编辑main.rs
- #![no_std]
- #![no_main]
-
- use core::panic::PanicInfo;
- use cortex_m_rt::entry;
- use cortex_m::{asm, Peripherals};
- use stm32f4::stm32f412 as device;
-
- #[panic_handler]
- fn my_panic_handler(_panic: &PanicInfo) -> ! {
- loop {}
- }
-
- fn my_delay() {//简陋的延迟函数
- let mut count = 2;
- while count > 0 {
- count = count - 1;
- let mut count2 = 120000;
- while count2 > 0 {
- count2 = count2 - 1;
- }
- }
- }
开头是一段普通的裸机代码,同时引用了上文注册到的包。
7.PAC包怎么调?
PAC是由svd2rust自动生成的,我们需要打开stm32f4的文档:stm32f4 - Rust
进入子模块如stm32f413;
选择你要配置的寄存器,如要开启gpioB的时钟,你需要配置ahb1enr;
接着选择操作的闭包如W,然后你就会知道怎么做
最后得到类似以下的代码:
- #[entry]
- fn main() -> !{
- let mut p = device::Peripherals::take().unwrap();
- let rcc = p.RCC;
- rcc.ahb1enr.modify(|_, w| w.gpioben().set_bit());
- p.GPIOB.moder.modify(|_, w| unsafe{w.moder0().bits(1)});
-
- loop {
- p.GPIOB.odr.modify(|_, w| w.odr0().bit(false)); //灯亮
- my_delay();
- p.GPIOB.odr.modify(|_, w| w.odr0().bit(true)); //灯灭
- my_delay();
- }
- }
8.烧录:
cargo flash --chip stm32f412zgtx
enjoy it
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。