プログラミング言語Rustは、低レベルのシステム開発向けに作られたぬるぽが発生しないメモリーセーフなプログラミング言語です。その利用範囲はシステム開発に留まらず、バックエンド開発やフロントエンド開発などにも広く使われはじめています。

人気急上昇ですね。

最近「実践Rustプログラミング入門」を入手して勉強していまして、Chapter8「組込みシステム」でLチカのお題(Cortex-M4)が出てくるのですが、ArduinoでもRustできないかなと思い調べてみました。

MAC環境(Docker未使用)で、Rust+ArduinoでLチカする方法について纏めています。
初心者向けにサクっと実行できる様に書いたつもりです。
「そういえばArduino押入れで眠ってるわ」という方は是非お試し下さい。

ArduinoでLチカ

まずはRust無しで、Arduinoを使ってふつーにLチカしてみましょう。
(MACとArduinoが接続されているポート名を調べる為なので、不要な場合は飛ばして下さい)

Arduino IDE

スクリーンショット 2020-09-06 17.11.18.png

ダウンロードしたzipを解凍し、Arduino.appを起動しましょう。
この時、Arduino本体はUSBに接続しておいて下さい。

スクリーンショット 2020-09-06 17.14.34.png
スクリーンショット 2020-09-06 17.22.22.png
Lです.jpg
スクリーンショット 2020-09-06 17.31.17.png

Rust+ArduinoでLチカ

ここまででお腹いっぱいにならなかった方は、続いてRustを使ったLチカにトライしてみましょう。
Arduino-IDEはRustに対応しておらず、cargoを使ってビルドしてやる必要があります。

環境構築

Rust

まずはRust環境をMACにセットアップします(普段からRustを使っているなら不要だと思います)。

スクリーンショット 2020-09-06 17.44.14.png
cargo
rustup
rustc

avr-gcc

Arduinoには、AVRファミリのマイクロコントローラーATmegaシリーズが搭載されています。
avr-gcc は、ATmega用のコンパイラです。後述のblinkでビルドする際に必要です。
(※このサイトを参考にしました)

以下のコマンドを実行すれば、avr-gccコマンドが使える様になります。

brew tap osx-cross/avr
brew install avr-gcc

クロスコンパイラ(Rust with AVR support)

AVRをRustでビルドできる様にする為、Rust with AVR supportをセットアップします。
MAC用の手順はコチラに記載されている通りです。

MACではビルド構成都合上、事前に「/usr/local/avr-rust」フォルダを手動で作成しパーミッション設定する必要があります。
以下のコマンドでそれらを実行します。

sudo mkdir /usr/local/avr-rust && sudo chown ${USER}:admin /usr/local/avr-rust

また、以下のコマンドで coreutils がインストールされている必要がある様です(私は不要でした)。

brew install coreutils

では、avr-toolchainをビルドしていきましょう。
avr-rust/rust.gitをcloneします。オプション(–recursive)が付いている点に注意。

# Grab the avr-rust sources
git clone https://github.com/avr-rust/rust.git --recursive

ビルド用フォルダを作成し、カレントディレクトリをbuildに変更します。

# Create a directory to place built files in
mkdir build && cd build

自作したフォルダbuildは、git cloneで生成されたフォルダ(rust)と同階層である点に注意して下さい。
参考:
avr-rust
├── build
└── rust

confiugreでMakefileを生成します。

# Generate Makefile using settings suitable for an experimental compiler
../rust/configure \
  --enable-debug \
  --disable-docs \
  --enable-llvm-assertions \
  --enable-debug-assertions \
  --enable-optimize \
  --enable-llvm-release-debuginfo \
  --experimental-targets=AVR \
  --prefix=/usr/local/avr-rust

makeします。ちなみに私の環境では小一時間かかりました。

# Build the compiler, install it to /usr/local/avr-rust
make
make install

これで、makeされたavr-toolchainが「/usr/local/avr-rust」に配置されました。

最後に、avr-toolchainを登録します。

# Register the toolchain with rustup
rustup toolchain link avr-toolchain /usr/local/avr-rust

# Optionally enable the avr toolchain globally
rustup default avr-toolchain

これで、avr用のRustプログラムをビルドできる様になりました。

avrdude

MACでビルドしたRust実行ファイル(.elf)をArduinoに書き込む為のツールです。

以下のコマンドで使える様になります。

brew install avrdude

ビルド(rust)

準備が整ったので、公式サンプル「blink」でLチカしてみましょう。

blinkサンプル(ruduino)

blink(点滅)は、ArduinoLでチカ用のRustサンプルプログラムです。
ATmega用モジュール(.elf)を生成する為の環境が整っていて便利です。

クローンします。

git clone https://github.com/avr-rust/blink.git

フォルダ「blink」が生成されます。

参考:私の環境では、以下の様なフォルダ構成にしました。
avr-rust
├── blink
├── build
└── rust

カレントディレクトリを「blink」に変更します。

cd ../blink

では、ビルドしましょう。
ビルドはnightlyで行う必要がある為、以下のコマンドを使います。

rustup override set nightly

# Compile the crate to an ELF executable.
cargo build -Z build-std=core --target avr-atmega328p.json --release

ビルドに失敗する場合は、以下のコマンドを実行した後、再びビルドしてみて下さい。

rustup component add rust-src

ビルドに成功すると、「target/avr-atmega328p/release/blink.elf」が生成されます。
これをArduinoに書き込みましょう。

Arduinoへ書き込む

MACからArduinoへ書き込むには、「avrdude」コマンドを使用します。
(参考サイト)

まず、MACとArduinoが繋がっているポート名を思い出してください。
ポート名の調べ方は、本記事の上記「ArduinoでLチカ」で説明しています。
ここでは、「/dev/cu.usbmodem141401」であるとして話を進めます。

Arduinoへ書き込む

ArduinoがMACと繋がっている状態で、コマンドを実行します。
「-P/dev/cu.usbmodem141401」の部分は、自分の環境用に適時修正して使って下さい。

avrdude -patmega328p -carduino -P/dev/cu.usbmodem141401 -b115200 -D -Uflash:w:target/avr-atmega328p/release/blink.elf:e
tenor.gif

blinkを改造しよう

しかし、先程の「ArduinoでLチカ(非Rust)」と結果が同じで分かりにくいですよね。
少し改造してみましょう。

blink/src/main.rsを、以下の内容に上書きして下さい。

#![feature(llvm_asm)]

#![no_std]
#![no_main]

use ruduino::cores::atmega328 as avr_core;
use ruduino::Register;

use avr_core::{DDRB, PORTB};

#[no_mangle]
pub extern fn main() {
    let mut param = 0;

    // Set all PORTB pins up as outputs
    DDRB::set_mask_raw(0xFFu8);

    loop {
        // Set all pins on PORTB to high.
        PORTB::set_mask_raw(0xFF);

        small_delay(param);
        // Set all pins on PORTB to low.
        PORTB::unset_mask_raw(0xFF);

        small_delay(param / 2);

        param += 50000;
        if param >= 800000 {
            param = 0;
        }
    }
}

/// A small busy loop.
fn small_delay(atai: u32) {
    //for _ in 0..400000 {
    for _ in 0..atai {
        unsafe { llvm_asm!("" :::: "volatile")}
    }
}

ezgif.com-resize.gif

方法その2(avr-hal)

今度はこの例を試してみましょう。同じ様なLチカですが、実装方法の異なる例です。
こちらの方が、どちらかというと「実践Rustプログラミング入門」での紹介例(但しこちらはArduinoでは無くCortex-M4)に近いと思います。

この例の使い方はこのブログに纏められていますが、ビルド環境はMACではなく Arch Linux で書かれています。

ここでは、MACでビルドしてLチカできる様に解説します。

rust-arduino-blink

早速クローンしていきましょう。

git clone https://github.com/creativcoder/rust-arduino-blink.git

フォルダ「rust-arduino-blink」が生成されます。

※参考:この時点での私の環境は、以下の様なフォルダ構成です。
avr-rust
├── blink
├── build
├── rust
└── rust-arduino-blink

カレントディレクトリを「rust-arduino-blink」に変更します。

cd ../rust-arduino-blink

この構成の特徴は、フォルダ「.cargo」の中に「config.toml」が格納されている点です。
ビルド時の各種設定が書かれており、 cargo build 時に余計なオプションを付けずにビルド出来ます。

このブログに書かれている、ビルドに必要な「pacman -S avr-gcc」などはArchLinuxでの方法なのでここでは飛ばしていきます(MACでのインストール方法(brew)は本記事の上の方で説明しています)。

さっそくビルドしてみましょう。

rustup override set nightly

cargo build

これで、target配下(今度はdebug)に.elfファイルが生成されました。

※追記:
ビルド時、下記エラーが出る場合がある様です。

error: language item required, but not found: `eh_personality`

これは、rustup toolchain 等の設定により起こる事がある様なのですが、具体的な発生理由は分かりませんでした。
ただ、発生した際は、Cargo.tomlに以下を追記する事で解消します。

[profile.dev]
panic = "abort"

[profile.release]
panic = "abort"

※こちらの記事を参考にしました。

Arduinoに書き込む為、avrdudeコマンドを使いましょう。
※ポート名を自分の環境に合わせる事と、.elfファイルのファイル名・パスが違う点に注意して下さい。

avrdude -patmega328p -carduino -P/dev/cu.usbmodem141401 -b115200 -D -Uflash:w:target/avr-atmega328p/debug/rust-arduino-blink.elf:e
コレ

※こっちのLチカも、実装は違いますが点滅速度が徐々に遅くなる感じのやつです。点滅速度や動きで違いを感じて下さい。Lチカでは出来る事は限られますよね〜?

環境を戻すには

avrでクロスコンパイルする為にrustupコマンドで色々変更を加えた為、もしかしたらArduino以外の普通のビルドが通らなくなっているかもしれません。以下のコマンドで元に戻しておきましょう(必要に応じて実行して下さい)。

rustup default stable

まとめ

Rustを使ってArduinoでLチカする方法を2つご紹介しました。

・1つめ(https://github.com/avr-rust/blink) → ruduino
・2つめ(https://github.com/creativcoder/rust-arduino-blink) → avr-hal

「実践Rustプログラミング入門」(github)では、2つめの手法に近いサンプルが掲載されています。
おそらく2つめの手法(avr-hal, .cargo/config.tomlを使用する例)が一般的(?)になるのかな、と思います。

「実践Rustプログラミング入門」のSection8-5「組込み向けクレート」では、組込み環境で使うクレート(alloc, heapless, panic等)の解説が纏められていて、Lチカから一歩先に進む為の情報が得られ、Arduino解説ではないですがとても参考になります。この本は入門書としての読みやすさもバツグンですので、興味ある方は入手してみて下さい。

Lチカ女子の参考になれば幸いです?

bannerAds