Rust on ARM

前言 ☕

之前在学习 ARM 芯片的开发的时候,教学是采用了 Keil 在 Win 下的开发环境。由于系统,以及 IDE 等都有很大的限制,故对此非常反感。之后深入学习了解后,发现使用 ARM dev 的官网提供的编译工具可以解决编译器的部分,代码就参考 ST 的 Manual, 下载则使用 stflash 工具。至此,所有工具流程完备,便开始了吭哧吭哧的寄存器写代码环节。。。

一直到前一段时间,个人非常喜欢 Rust 的设计理念,虽然没网没开发的特点不是很喜欢,但是相比于优点来说可以忽略。在学习 Rust 过程中,了解到了可以用来开发 ARM 。 最近疫情刚好有时间,就捣鼓了一下,发现 crates 包代码也还算简洁,同时生成的二进制文件又可以足够小,再者就是不用自己使用寄存器了,也算一大优势。所以果断在此记录下。

环境准备 🍩

这里对于环境准备等的情况就不过多介绍了。自行安装。

  1. 软件准备:

    OS Compiler flash tool
    any rust st-flash
  2. 硬件准备:

    1. stm32f103c8t6 开发板子
    2. stlink 下载器

代码编写 📚

在代码编写之前,首先需要添加 stm32f103c8t6 的编译平台:

rustup target add thumbv7m-none-eabi

首先,这里先总括下涉及到什么文件:

-rw-r--r--  1 staff  staff    78 May  9 16:00 .cargo/config
-rw-r--r--  1 staff  staff   659 May  9 16:23 Cargo.toml
-rw-r--r--  1 staff  staff   139 May  9 16:24 memory.x
-rw-r--r--  1 staff  staff  1811 May  9 16:22 src/main.rs

以上文件分别涉及编译选项配置、依赖配置、芯片空间指定、主要代码编写。

先看下编译选项的配置:

[build]
target = "thumbv7m-none-eabi"
rustflags = ["-C", "link-arg=-Tlink.x"]

其次是芯片参数配置:

/* Linker script for the STM32F103C8T6 */

MEMORY {
  FLASH : ORIGIN = 0x08000000, LENGTH = 64K
  RAM : ORIGIN = 0x20000000, LENGTH = 20K
}

以上的芯片参数可以从 Mannul 或则 st-flash 探测查看。当然通过已有的 HAL 库等的代码文件查看也可以得到。

重点在依赖的一些配置选项:

[package]
name = "stm32f103-blink"
version = "0.1.0"
edition = "2018"

  

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html


  

[profile.release]
opt-level = 'z'     # turn on maximum optimizations
lto = true          # link-time-optimizations for size reduction

  

  

[dependencies]
nb = "1.0.0"				# Minimal and reusable non-blocking I/O layer
cortex-m = "0.7.4"          # access to the generic ARM peripherals
cortex-m-rt = "0.7.1"       # startup code for ARM core
embedded-hal = "0.2.7"      # access to generic embedded functions
panic-halt = "0.2.0"        # panic handler

  

  

[dependencies.stm32f1xx-hal]
features = ["stm32f103", "rt", "medium"]
version = "0.9.0"

在上述代码中,package 块是当前项目的基本信息,profile 块则是关于编译优化等选项。

在 dependencies 块中,nb 是 IO 封装,cortex-m 则是关于 Crotex-M 的一些底层封装。类似于 C 语言开发中,一些汇编的初始化工作:涉及中断,内存初始化等。cortex-m-rt 则是关于 Cortex-m 的内核级别的代码,设计 BusFault、UsageFault 等等。这个的话初学者是接触不到的。embedded-hal 则是 HAL 层的一些标准封装。panic-halt 则是一些错误处理的封装。

最下面的代码块则是一些基本的信息选项。

最后则是我们的主要代码模块了:

//! Blinks an LED


//!


//! This assumes that a LED is connected to pc13 as is the case on the blue pill board.


//!


//! Note: Without additional hardware, PC13 should not be used to drive an LED, see page 5.1.2 of


//! the reference manual for an explanation. This is not an issue on the blue pill.


  

#![deny(unsafe_code)]
#![no_std]
#![no_main]

  

use panic_halt as _;

  

use nb::block;
use cortex_m_rt::entry;
use stm32f1xx_hal::{pac, prelude::*, timer::Timer};

  

#[entry]

fn main() -> ! {

    // Get access to the core peripherals from the cortex-m crate


    let cp = cortex_m::Peripherals::take().unwrap();

    // Get access to the device specific peripherals from the peripheral access crate


    let dp = pac::Peripherals::take().unwrap();

  

    // Take ownership over the raw flash and rcc devices and convert them into the corresponding


    // HAL structs


    let mut flash = dp.FLASH.constrain();

    let rcc = dp.RCC.constrain();

  

    // Freeze the configuration of all the clocks in the system and store the frozen frequencies in


    // `clocks`


    let clocks = rcc.cfgr.freeze(&mut flash.acr);

  

    // Acquire the GPIOC peripheral


    let mut gpioc = dp.GPIOC.split();

  

    // Configure gpio C pin 13 as a push-pull output. The `crh` register is passed to the function


    // in order to configure the port. For pins 0-7, crl should be passed instead.


    let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh);

    // Configure the syst timer to trigger an update every second


    let mut timer = Timer::syst(cp.SYST, &clocks).counter_hz();

    timer.start(1.Hz()).unwrap();

  

    // Wait for the timer to trigger an update and change the state of the LED


    loop {

        block!(timer.wait()).unwrap();
        led.set_high();

        block!(timer.wait()).unwrap();
        led.set_low();

    }

}

整体代码这里就不做过多介绍了。有兴趣的话可以去 stm32f1xx-hal 自行学习。

通过以上代码编译完成后,还需要转换成 bin 文件,目前我才用的 ARM dev 网站的工具集中的 arm-none-eabi-objcopy

arm-none-eabi-objcopy -O binary target/thumbv7m-none-eabi/release/stm32f103-blink  stm32f103-blink.bin

除此之外还没找到一个更好的办法。转换完成后,直接使用 stflash 工具进行下载就可以了。