(1)の続きです。
参考サイト
- RustでSTM32マイコンをLチカしてみる(Embedded HAL) - Qiita
- cortex_m - Rust
- Compiling fails due to
compiler_builtins
· Issue #15 · japaric/cortex-m-rt - stm32f30x_hal - Rust
自作プロジェクト
コピペで出来ます。やってみましょう(できるようになるまで丸3日かかった...)。今回ターゲットにしたチップはいつもの STM32F303K8T6 です。とはいってもチップが違うのならリンカの所を変えればいいだけですが。
まずはコマンドを打撃して構造を作ります。
$ xargo new blinky --bin # blinkyというプロジェクト作成
$ cd blinky
$ mkdir .cargo # なんか必要なディレクトリ
続いてファイルの構成です。
Cargo.toml
[package]
authors = ["Hoge Tarou <hogehoge@example.com>"]
name = "blinky"
version = "0.1.0"
[profile.dev]
codegen-units = 1
incremental = false
[profile.release]
lto = true
debug = true
[dependencies]
stm32f30x = "*"
[dependencies.cortex-m]
version = "0.4.1"
[dependencies.cortex-m-rt]
version = "0.3.12"
features = ["abort-on-panic"]
[dependencies.stm32f30x-hal]
version = "0.1.1"
features = ["rt"]
[dependencies.num-traits]
version = "0.2"
default-features = false
Xargo.toml
[dependencies.core]
stage = 0
[dependencies.compiler_builtins]
features = ["mem"]
stage = 1
build.rs
Makefile みたいなやつで、Rust のソースコードファイル以外に変更があったらビルドを再度してくれるように指示するためのファイルです。以下ファイル全体がおまじないですね。
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
fn main() {
// Put the memoryer script somewhere the memoryer can find it
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-memory-search={}", out.display());
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=memory.x");
}
memory.x
リンカスクリプトです。ROM
ではなく FLASH
としている点にご注意。
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 12K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 64K
}
.cargo/config
[target.thumbv7em-none-eabihf]
runner = 'arm-none-eabi-gdb'
rustflags = [
"-C", "link-arg=-Tlink.x",
"-C", "linker=arm-none-eabi-ld",
"-C", "linker-flavor=ld",
"-Z", "no-landing-pads",
"-C", "opt-level=0",
]
[build]
target = "thumbv7em-none-eabihf"
これで終わりです。お疲れ様でした。以下に完成後のディレクトリツリーを示します。
$ tree . -L 2 -a
[master]
.
├── .cargo
│ └── config
├── Cargo.toml
├── Xargo.toml
├── build.rs
├── memory.x
└── src
└── main.rs
ソースファイルの編集
というわけで src/main.rs
をひな形にします。既存のファイルを削除して置き換えてください。
#![no_std]
extern crate cortex_m;
extern crate stm32f30x_hal as hal;
use hal::prelude::*;
// Systickを用いたディレイ
use hal::delay::Delay;
fn main() {
let cp = cortex_m::Peripherals::take().unwrap();
let p = hal::stm32f30x::Peripherals::take().unwrap();
let mut flash = p.FLASH.constrain();
let mut rcc = p.RCC.constrain();
let clocks = rcc.cfgr.freeze(&mut flash.acr);
// Systick-based delay
let mut delay = Delay::new(cp.SYST, clocks);
loop {
// TODO: Insert codes here
}
}
なおビルド時には以下のコマンドを実行してください。
$ xargo build
ハマりどころ集
僕がハマってもがき苦しんでいたので是が非でも書きます。build 時のエラーになります。
can't find crate for core
と言われる
cargo
じゃなくて xargo
ですよ!
arm-none-eabi-ld
に「libc.a ねぇよ」って怒られる
面倒だからとリンカスクリプトを IDE が生成したものとしてそのまま memory.x にコピペすると怒られます。これは内部の /DISCARD/
セクションの中で libc.a
libgcc.a
libm.a
を呼び寄せていますので、Rust でやる場合はこのような記述はあってはなりません(多分)。
また、下に述べる現象も同時に発生するため、上のように MEMORY
の所のみを記載するようにしてください。
リンク時に「サイズが足りない」「Reset_Handlerないよ」って怒られる
IDE が生成したリンカスクリプトをそのまま memory.x にコピペすると起こる現象です。上と同じく MEMORY
の所のみを記載するようにしてください。
〆
今回はここまで。Lチカはもう出来ているのですが、このまま続けたら記事は長くなるし、僕自身眠くなってきたのでここでおしまいにします。
ビルドは stm32f30x
クレートが非常に時間掛かると思いますが、首を長くして待ってやってくださいな。初回だけですから。