当前位置:   article > 正文

Rust嵌入式:只使用寄存器为STM32点灯;从查手册开始_stm32 rust

stm32 rust

为什么是“只使用寄存器”

        网上很多教程都是直接调用对应芯片的HAL库,让初学者认为操作都被Rust嵌入式开源组封装好了,直接调就好。这在目前Rust嵌入式生态还不成熟的情况下可能是个误解。

        实际上Rust嵌入式有自己独特的层级关系,这一方面可以参考b站up主“爆米花胡了”的视频。其中负责访问寄存器的是PAC,与C语言直接访问内存地址不同,PAC层的代码依赖每个新品提供的svd文件自动生成,相当参考svd层的寄存器访问规范,为开发者提供了一系列寄存器的Rust访问方式。依赖PAC层的Rust嵌入式寄存器编程就是调用这些访问寄存器的api。

如何用依赖PAC层编程?

先别急,先搭建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内编辑 

  1. [build]
  2. target = "thumbv7em-none-eabihf"
  3. rustflags = [
  4. "-C", "link-arg=-Tlink.x",
  5. ]

这一步是指定target和编辑、链接参数

3.在项目根目录下新建build.rs

  1. //! This build script copies the `memory.x` file from the crate root into
  2. //! a directory where the linker can always find it at build time.
  3. //! For many projects this is optional, as the linker always searches the
  4. //! project root directory -- wherever `Cargo.toml` is. However, if you
  5. //! are using a workspace or have a more complicated build setup, this
  6. //! build script becomes required. Additionally, by requesting that
  7. //! Cargo re-run the build script whenever `memory.x` is changed,
  8. //! updating `memory.x` ensures a rebuild of the application with the
  9. //! new memory settings.
  10. use std::env;
  11. use std::fs::File;
  12. use std::io::Write;
  13. use std::path::PathBuf;
  14. fn main() {
  15. // Put `memory.x` in our output directory and ensure it's
  16. // on the linker search path.
  17. let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
  18. File::create(out.join("memory.x"))
  19. .unwrap()
  20. .write_all(include_bytes!("memory.x"))
  21. .unwrap();
  22. println!("cargo:rustc-link-search={}", out.display());
  23. // By default, Cargo will re-run a build script whenever
  24. // any file in the project changes. By specifying `memory.x`
  25. // here, we ensure the build script is only re-run when
  26. // `memory.x` is changed.
  27. println!("cargo:rerun-if-changed=memory.x");
  28. }

4.我们再建立上面的编译脚本指定的 memory.x

  1. MEMORY
  2. {
  3. FLASH : ORIGIN = 0x08000000, LENGTH = 256K
  4. RAM : ORIGIN = 0x20000000, LENGTH = 64K
  5. }

5.随后修改项目根目录Cargo.toml,加入PAC包

  1. [dependencies]
  2. cortex-m = "0.7.4"
  3. cortex-m-rt = "0.7.1"
  4. stm32f4 = { version = "0.14.0", features = ["stm32f412", "rt"] }

这里的具体新品型号根据自己芯片选择,其中cortex-m的两个是cortex-m内核通用的内核编程接口,stm32f4即是厂商特定的PAC编程接口,用于访问各种寄存器和芯片功能。

6.终于可以开始编辑main.rs

  1. #![no_std]
  2. #![no_main]
  3. use core::panic::PanicInfo;
  4. use cortex_m_rt::entry;
  5. use cortex_m::{asm, Peripherals};
  6. use stm32f4::stm32f412 as device;
  7. #[panic_handler]
  8. fn my_panic_handler(_panic: &PanicInfo) -> ! {
  9. loop {}
  10. }
  11. fn my_delay() {//简陋的延迟函数
  12. let mut count = 2;
  13. while count > 0 {
  14. count = count - 1;
  15. let mut count2 = 120000;
  16. while count2 > 0 {
  17. count2 = count2 - 1;
  18. }
  19. }
  20. }

开头是一段普通的裸机代码,同时引用了上文注册到的包。

7.PAC包怎么调?

PAC是由svd2rust自动生成的,我们需要打开stm32f4的文档:stm32f4 - Rust

进入子模块如stm32f413;

选择你要配置的寄存器,如要开启gpioB的时钟,你需要配置ahb1enr;

接着选择操作的闭包如W,然后你就会知道怎么做

最后得到类似以下的代码:

  1. #[entry]
  2. fn main() -> !{
  3. let mut p = device::Peripherals::take().unwrap();
  4. let rcc = p.RCC;
  5. rcc.ahb1enr.modify(|_, w| w.gpioben().set_bit());
  6. p.GPIOB.moder.modify(|_, w| unsafe{w.moder0().bits(1)});
  7. loop {
  8. p.GPIOB.odr.modify(|_, w| w.odr0().bit(false)); //灯亮
  9. my_delay();
  10. p.GPIOB.odr.modify(|_, w| w.odr0().bit(true)); //灯灭
  11. my_delay();
  12. }
  13. }

8.烧录:

cargo flash --chip stm32f412zgtx

enjoy it 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/533459
推荐阅读
相关标签
  

闽ICP备14008679号