手中有一块STM开发板,其型号时STM32F103C6T6A。想玩玩Rust嵌入式开发,那么Hello world级别的程序应当是点亮板载的LED灯了。
那么如何建立起一个Rust的嵌入式开发环境呢?参考了不少资料,踩了几各坑,最终完成这一目标。这些资料大都需要你有一个仿真器,而且会涉及到使用openOCD,相对麻烦一点。这这是一个简单的hello world程序,我并不希望设置一系列的工具链来弄好一个并不会被使用到的调试功能。我只想简单的看到板载LED被点亮而已。因此本篇的目的是设置好开发环境,使用下载器来下载编译好的程序。
环境
首先的首先,你得有安装好rust,这个按下不表。
用cargo new led
初识化一个项目,编辑Cargo.toml 加入必要的依赖:
[dependencies]
embedded-hal = "0.2.7"
nb = "1"
cortex-m = "0.7.6"
cortex-m-rt = "0.7.1"
# cortex-m-semihosting = "0.5.0"
panic-halt = "0.2.0"
[dependencies.stm32f1xx-hal]
version = "0.10.0"
features = ["rt", "stm32f103"]
编辑src/main.rs:
#![allow(clippy::empty_loop)]
#![deny(unsafe_code)]
#![no_main]
#![no_std]
use panic_halt as _;
use cortex_m_rt::entry;
use stm32f1xx_hal::{pac, prelude::*};
#[entry]
fn main() -> ! {
let p = pac::Peripherals::take().unwrap();
let mut gpioc = p.GPIOC.split();
gpioc.pc13.into_push_pull_output(&mut gpioc.crh).set_low();
loop {}
}
如果这时候编译,会得到一大片错误:
其中最后以个是最主要的,因为我们声明了no_std, 但是没有制定变异的目标。因此编译器提示我们加上—target
参数或者添加.cargo/config 文件。
STM32F1XX 的CPU 是Cortex-M3,通过网络资料可知道,编译目标是: thumbv7m-none-eabi,但先要安装相应的依赖:
rustup target add thumbv7m-none-eabi
然后执行 cargo build --release --target thumbv7m-none-eabi
不知道为什么cargo没有自动下载依赖,导致了编译失败。于是我主动执行了一下cargo add panic-halt
然后再build,就可以了。
为了避免老是需要指定target为thumbv7m-none-eabi,让我们把它写入.cargo/config
[build]
target = "thumbv7m-none-eabi"
问题是编译生成的文件太大了,有900多K,要知道这个开发板子的Flash才32K。
cargo-binutils 提供了一系列工具,其中cargo-size 可以查看文件的大小信息,让我们先安装它:cargo install cargo-binutils
然后执行:cargo size --bin led -- -A
(如果没的.cargo/config, 这里也需要加上 —target),这个命令提示我们需要设置好llvm-tools,于是执行rustup component add llvm-tools-preview
可以看出绝大不部分都是debug信息,问题是release版本里为什么有这么多debug信息?还有一个更严重的问题:没有代码段(.text)!
以rust embeded no text section
为关键字搜索发现应该是链接器的配置不对,改.cargo/config 如下:
[target.thumbv7m-none-eabi]
rustflags = [
"-C", "link-arg=-Tlink.x",
]
[build]
target = "thumbv7m-none-eabi"
再编译,提示linker需要知道内存布局是怎么样的,这个布局由memory.x 指定,STM32F103C 系列的布局是这样的:
MEMORY
{
FLASH : ORIGIN = 0x08000000, LENGTH = 32K
RAM : ORIGIN = 0x20000000, LENGTH = 10K
}
意思是Flash从0x08000000处开始,长32K. RAW从0x20000000开始,长10K.
现在的目录结构是这样的:
这下编译后查看size就有代码段了。
通过执行cargo strip --bin led --release -- --strip-all
可以移除里面的调试信息,这里有个小坑:cargo strip —help 给出的例子是错的:
可是strip完还是有129K,远大于F103的Flash大小。
百思不得其解,互连网都翻烂了才发现这里生成的是ELF文件,而下载到单片机的是Binary文件。objcopy 可以将ELF 转为bin文件:
cargo objcopy --bin led --release -- -O binary out.bin
下载
ST-LINK 接线顺序
:TODO
用STM自家才STMCubeProgrammer来下载固件,必需要吐槽一下这个GUI,java做的启动巨慢,用的java1.8,在高分屏下字体贼小。
受不了这个GUI,可以直接使用STM_Programm_CLI 下载:
STM_Programmer_CLI --list #显示可用的连接方式
用下面的命令下载:
STM32_Programmer_CLI -c port=SWD <path-to-bin> 0x08000000
下载完成后再下板子上的Reset就可以看见板载的LED亮了(出厂设置为该灯闪烁)。
https://github.com/rust-embedded/discovery/issues/147
arm-none-eabi-objcopy -O binary t t1
总之体验糟糕极了。