【Arduino工作〜発展編】RustでATmega328pのプログラムをビルドしてみる
※ 当ページには【広告/PR】を含む場合があります。
2021/03/22

以前FreeROSをArduinoにインストールしてLチカさせる方法を紹介しました。
また別のアプローチとして、Rustによる組込プログラミングというのも可能のようです。
今回はRustからどのようにAVRマイコン用のプログラムを使っていくのか考えていきます。
AVR-Rustでより簡単に組込プログラミング
このことでcargoコマンド一発でAVRのビルド環境が構築できるようになり、かなり簡単に扱えるようになっています。
toolchainの環境構築
RustでAVR用のプログラムをビルドする前に、Rustの環境を整えます。
パソコンのOS自体はRustが動作すればなんでもOKですが、今回は
Debian/Ubuntu
apt-get
さて、まずrustupがビルド時に必須ですので、現在のバージョンを確認します。
$ rustup --version
rustup 1.23.1 (3df2264a9 2020-11-30)
info: This is the version for the rustup toolchain manager, not the rustc compiler.
info: The currently active `rustc` version is `rustc 1.51.0-nightly (c2de47a9a 2021-01-06)`
AVRのプログラムに必要なプログラムを以下のように追加でパッケージインストールします。
$ sudo apt-get install binutils gcc-avr avr-libc avrdude
他のOSへのインストールは
AVR向けのツールチェーンはnightlyにしか組み込まれていませんので、以下のようにrustupでnightlyビルドができるように仕向けます。
$ rustup update
$ rustup toolchain install nightly
$ rustup component add rust-src --toolchain nightly
$ rustup override set nightly
$ rustc -Vv
rustc 1.51.0-nightly (c2de47a9a 2021-01-06)
binary: rustc
commit-hash: c2de47a9aa4c9812884f341f1852e9c9610f5f7a
commit-date: 2021-01-06
host: x86_64-unknown-linux-gnu
release: 1.51.0-nightly
次にビルドターゲットをAVR用に設定しますが、Rustのnightlyに記述されているAVR用ターゲットは
avr-unknown-gnu-atmega328
もしATmega328以外のマイコンをターゲットにするには、カスタムターゲット用のJSONを別途作成する必要があります。
カスタムターゲットの例としてATmega328p用のjsonファイルを作ってみましょう。
$ rustc --print target-spec-json -Z unstable-options \
--target avr-unknown-gnu-atmega328 > avr-atmega328p.json
すると、
avr-atmega328p.json
{
"arch": "avr",
"atomic-cas": false,
"cpu": "atmega328",
"data-layout": "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8",
"eh-frame-header": false,
"exe-suffix": ".elf",
"executables": true,
"is-builtin": true,
"late-link-args": {
"gcc": [
"-lgcc"
]
},
"linker": "avr-gcc",
"linker-is-gnu": true,
"llvm-target": "avr-unknown-unknown",
"max-atomic-width": 0,
"pre-link-args": {
"gcc": [
"-mmcu=atmega328",
"-Wl,--as-needed"
]
},
"target-c-int-width": "16",
"target-pointer-width": "16"
}
基本的には
cpu
-mmcu
{
//...
"cpu": "atmega328p",
//...
"pre-link-args": {
"gcc": [
"-mmcu=atmega328p",
//...
]
},
//...
}
これでひとまずツールチェーンの構築は完了です。
Rustプログラミング手順
では
このプロジェクトの最低限のフォルダ構造は以下です。
$ tree
.
├── Cargo.toml
├── src
│ └── main.rs
└── avr-atmega328p.json
ビルドターゲット用のjsonは先ほど説明していたファイルですので説明は省略しまして、まずCargo.tomlですが、
[package]
name = "blink"
version = "0.1.0"
authors = ["Dylan McKay <me@dylanmckay.io>"]
edition = '2018'
[dependencies]
ruduino = "0.3"
となっています。
ここで唯一依存性の指定が入っている
ruduino
他のAVRマイコンへの実装例もこの
次にいよいよ
src/main.rs
#![feature(llvm_asm)]
#![no_std]
#![no_main]
use ruduino::Pin;
use ruduino::cores::current::{port};
#[no_mangle]
pub extern fn main() {
port::B5::set_output();
loop {
port::B5::set_high();
ruduino::delay::delay_ms(1000);
port::B5::set_low();
ruduino::delay::delay_ms(1000);
}
}
となって、いかにもArduino風にプログラミングされいます。
こうスッキリと完結したコードになっているのも、ruduinoからインポートしたメソッドを利用できている恩恵で、一般に自分で一からコードを実装すると、もっと長くなると思います。
如何せんこれで材料が揃いましたので以下のコマンドでビルドします。
$ export AVR_CPU_FREQUENCY_HZ=16000000
$ cargo build -Z build-std=core --target avr-atmega328p.json --release
これで
target/[デバイスのタイトル]/release
blink.elf
ちなみにArduinoにはビルドインLEDとマイコン側のPB5ピンは接続されているので、Arduino上で試すとこのLEDがチカチカすることが分かります。
あとはavrdudeでマイコンに書き込む手順は別記事で説明した内容と一緒です。
以下のコマンドはAtmel-ICEからマイコンへ書き込むときのコマンド例です。
$ sudo avrdude -p m328p -c atmelice_isp -P usb -U flash:w:target/avr-atmega328p/release/blink.elf:e
書き込み装置の種類でavrdudeのオプションが違いますので、avrdudeのマニュアルなどを参照にプログラムを書き込んでください。
LLVM ERRORで止まる(2021年1月頃の報告)
2021年3月現在で、nightlyのバージョンによっては他のライブラリとの整合性が内部で取れていないのか、llvmでビルド中のバグが報告されています。
以下のように
compiler_builtins
$ cargo build -Z build-std=core --target avr-unknown-gnu-atmega328 --release
Compiling compiler_builtins v0.1.39
Compiling nb v1.0.0
#...
Compiling embedded-hal v0.2.4
LLVM ERROR: Not supported instr: <MCInst 258 <MCOperand Reg:1> <MCOperand Imm:15> <MCOperand Reg:40>>
error: could not compile `compiler_builtins`
To learn more, run the command again with --verbose.
warning: build failed, waiting for other jobs to finish...
error: build failed
現行で最新のnightlyではまだこのバグが残ったままでしたので、バグの出ない
nightly-2021-01-07
$ rustup toolchain install nightly-2021-01-07
$ rustup component add rust-src --toolchain nightly-2021-01-07
$ rustup override set nightly-2021-01-07
として再度cargoビルドしてあげると上手くコンパイルできるはずです。
まとめ
今回はRustでAVRマイコンを実装する場合の手順を紹介していきました。
感触としてはすでにC言語でプログラミングするのと殆ど同じように感じました。
個人的に、Rustで組込プログラミングというのは水面下でかなり流行ってきてる手法ですので、これを気に何かサーボモータを制御して可動する装置を作ってみたくなりました。
参考サイト
Arduinoへ直接書き込みする
Raspberry Pi Pico関連
最近話題のRaspberry Pi Picoも同様の手法でRustによるプログラミングが可能ですが、書き込み方法は別の環境を構築する必要があります。