Posted at

RustでSTM32マイコンをLチカしてみる(Embedded HAL)

More than 1 year has passed since last update.

こちらの記事をみて興味を持っていろいろ試していたところ、本家ブログにてHAL traitsの記事が出ていたのでこれを使ってLチカしてみました。1


使用するボード Nucleo-F303RE

1/21現在で実装されているHALはSTM32F30xだけのようです。ちょうど適合するマイコンが載っているボードが手元にあったのでこれを使いました。


環境構築

Linux(Ubuntu 16.04 LTS x86_64)で環境を作成します。WindowsやmacOSでは試していませんが、こちらが参考になると思います。


インストール

$ rustup default nightly

$ rustc -V
rustc 1.25.0-nightly (15a1e2844 2018-01-20)

$ sudo apt install binutils-arm-none-eabi
$ arm-none-eabi-ld -V | head -n1
GNU ld (2.26-4ubuntu1+8) 2.26

$ sudo apt-get install gdb-arm-none-eabi
$ arm-none-eabi-gdb --version | head -n1
GNU gdb (7.10-1ubuntu3+9) 7.10

$ sudo apt install openocd
$ openocd -v 2>&1 | head -n1
Open On-Chip Debugger 0.9.0 (2015-09-02-10:42)

$ sudo apt install libssl-dev libssh-dev pkg-config cmake
$ cargo install cargo-clone
$ cargo install cargo
$ cargo -V
xargo 0.3.10
cargo 0.26.0-nightly (6a8eb71f6 2018-01-13)

$ rustup component add rust-src
$ cargo install cargo-edit


gdb-dashboardレイアウト

gdb-dashboardのGitHubリポジトリ (https://github.com/cyrus-and/gdb-dashboard) を取得して、.gdbinitスクリプトをホームディレクトリ直下に保存します。保存後、safe-path設定を追加します。

$ git clone https://github.com/cyrus-and/gdb-dashboard.git

$ cp gdb-dashboard/.gdbinit ~/
$ echo 'set auto-load safe-path /' >> ~/.gdbinit


Cargoプロジェクト設定

依存モジュールとして


  • stm32f30x-hal

を設定します。


Cargo.toml

[package]

name = "stm32f30x_hal_blinky"
version = "0.1.0"
authors = ["..."]
description = "LED blinky for STM32F303RE using stm32f30x_hal"
keywords = ["arm", "cortex-m", "blinky"]
categories = ["embedded", "no-std"]
license = "MIT OR Apache-2.0"
repository = "https://"

[profile.dev]
codegen-units = 1
incremental = false

[profile.release]
lto = true
debug = true

[dependencies.stm32f30x-hal]
version = "0.1.1"
features = ["rt"]

[dependencies.cortex-m]
version = "0.4.1"

[dependencies.cortex-m-rt]
version = "0.3.12"
features = ["abort-on-panic"]

[dependencies.cortex-m-semihosting]
version = "0.2.0"


Cortex-M4(FPUあり)をターゲットに設定


.cargo/config

[target.thumbv7em-none-eabihf]

runner = 'arm-none-eabi-gdb'
rustflags = [
"-C", "link-arg=-Tlink.x",
"-C", "linker=arm-none-eabi-ld",
"-Z", "linker-flavor=ld",
]

[build]
target = "thumbv7em-none-eabihf"


STM32F303REのメモリ容量を設定


memory.x

MEMORY

{
/* NOTE K = KiBi = 1024 bytes */
/* TODO Adjust these memory regions to match your device memory layout */
FLASH : ORIGIN = 0x08000000, LENGTH = 512K
RAM : ORIGIN = 0x20000000, LENGTH = 64K
}


ソースコード


src/main.rs

#![no_std]

extern crate cortex_m;

// "as hal"をつける習わしらしい?
extern crate stm32f30x_hal as hal;

// "extern crate stm32f30x"を *書かない*
// 代わりに"use hal::stm32f30x"を書く
use hal::stm32f30x;

// おまじない
use hal::prelude::*;

// GPIOでOutputするための指定
// NucleoボードではPA5がLEDに接続されている
use hal::gpio::{Output, PushPull};
use hal::gpio::gpioa::{PA5};

// Systickを用いたディレイ
use hal::delay::Delay;

fn main() {
let cp = cortex_m::Peripherals::take().unwrap();
let p = stm32f30x::Peripherals::take().unwrap();

let mut flash = p.FLASH.constrain();
let mut rcc = p.RCC.constrain();

// 現在はHSIをクロック源として設定のみ
// 何も指定しなければデフォルトの8MHz
let clocks = rcc.cfgr.freeze(&mut flash.acr);

// GPIOAのPA5をOutput-PushPullで使用するオブジェクト
let mut gpioa = p.GPIOA.split(&mut rcc.ahb);
let mut pa5: PA5<Output<PushPull>> =
gpioa.pa5.into_push_pull_output(&mut gpioa.moder, &mut gpioa.otyper);

// Systickベースでディレイするオブジェクト
let mut delay = Delay::new(cp.SYST, clocks);

loop {
pa5.set_high();
delay.delay_ms(1_000_u16);
pa5.set_low();
delay.delay_ms(1_000_u16);
}
}







  1. というか、ちょうど手をつけ始めたタイミングでレジスタアクセスの方法が切り替わってしまっていろいろ混乱してみたりして。