1: はじめに
基本的には、公式ガイドブックの通りに進めることで、環境を構築することができますが、一部つまづきポイントがありました。
調べたところ Windows の人は WSL2 上に構築することが多いようですが、今回は Windows 11 にも構築して動作確認しています。
- Ubuntu on WSL2
- Windows 11
1-1: 本資料を活用できる対象者
- AVR マイコンを C/C++ でプログラミングしたことがある方
- シェルやコマンドプロンプトでのコマンド操作にある程度慣れている方
1-2: 構築した環境
外部ライブラリとして ruduino を使用しています。他にも avr-hal の作例も調べると出てきます。
- ruduino
- avr-hal (今回は使用していません)
その他の環境
- Rust Nightly 2024-04-23 付近
- 後述しますが バージョンを最新 (2024-08-04, 1.81) にすると動きませんでした ので、動かなかった場合は、こちらのバージョンで試すことをおすすめします
- AVR ATmega328P-PU (動作確認したマイコン)
- https://akizukidenshi.com/catalog/g/g103142/
- ATmega328P 以外にも ATtiny2313 で動かないか試行錯誤しましたが、うまく動かせませんでした
2: 作業手順
Ubuntu on WSL2 と Windows で異なる手順は分けて説明します。
2-1: WSL2 インストール (省略可能)
Ubuntu on WSL2 で環境を構築したい方は、WSL2 を有効化し、Ubuntu をインストールしてください。作業手順に関しては省略します。
本資料を記述するにあたって、まっさらな環境で動作確認するため、Ubuntu を追加インストールしています。
追加インストール方法に関しては、次のブログが大変参考になりました。ありがとうございました。
goodbyegangsterのブログ - WSL にまっさらな新規の Ubuntu 環境をつくる
2-2: Rustup のインストール
Rustup とは、Rust 公式が提供する管理ツールです。次のような機能を持ちます。
- Rust 自体のバージョン管理(インストール・アップデート)
- パッケージマネージャ Cargo のインストール
- ツールチェインの管理
参考サイト: Zenn - インストール後にrustupを使ってすること
OS ごとにインストール方法が異なります。次のサイトにアクセスし、指示に従ってインストールしてください。
https://www.rust-lang.org/ja/tools/install
Rustup インストール (Ubuntu on WSL2 の場合)
Windows Subsystem for Linux でのインストール方法に従って、コマンドでインストールします。
スクリーン上の説明に従って Rust をインストールしてください。
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
(省略)
Current installation options:
default host triple: x86_64-unknown-linux-gnu
default toolchain: stable (default)
profile: default
modify PATH variable: yes
1) Proceed with standard installation (default - just press enter)
2) Customize installation
3) Cancel installation
> (そのまま Enter)
Rust での Hello World!
Rust を使用するのが初めてであれば、$ cargo new hello
でプロジェクトを作成し、"Hello World!" を実行してみると良いと思います。
cargo によるプロジェクトの作成・ビルド・実行の感覚が学べます。
(私は C, Java, Python ぐらいしか経験がなかったため、新鮮な感覚でした)
参考 Qiita RUSTの環境構築とHello,world!について by @Veritas666777(tomato 3世)
2-3: AVR-Rust のインストール
Rust で書かれたプログラムを AVR マイコンで動くようコンパイルするには、AVR-Rust をインストールする必要があります。
- AVR-Rust プロジェクト https://github.com/avr-rust
- AVR-Rust ガイドブック https://book.avr-rust.org/
AVR-Rust ガイドブックを参考に、インストールを進めます。
nightly コンパイラのインストール
AVR-Rust ガイドブック 2. Installing the compiler には、以下の記載があります。
AVRサポート付きのRustを使用するには、いくつかのソフトウェアをインストールする必要があります
* AVRサポートが有効になっているRustコンパイラ
* コンパイラのソースコード
これは、AVR が一般に互いに ABI 互換性がないため、libcore を遅延コンパイルする必要があるため必須であり、そのため、コンパイル時に対象となる AVR デバイス用にコア ライブラリを明示的にコンパイルする必要があります。
注 必要なサードパーティ製ツールも必ずインストールしてください。これにはリンカーが含まれます。
"AVRサポートが有効になっているRustコンパイラ" とは、Nightly コンパイラのことです。
Rust は3つのチャネルでリリースされています。 (参考: Rust公式 - Channels)
- stable: 安定版、通常はこちらをそのまま利用する
- beta: ベータ版
- nightly: 毎晩のように更新されているもの。AVR サポートが有効。
AVR-Rust ガイドブック Installing via Rustup (recommended) を読みながら、nightly のインストールを進めます。
動作確認が取れている nightly のバージョンを指定し、インストールします。(1分程度)
こちらの環境ではとりあえず、nightly-2024-04-23 で動作が確認できました。
$ rustup toolchain install nightly-2024-04-23
$ rustup component add rust-src --toolchain nightly-2024-04-23
AVR-Rust ガイドブックでは、次のように最新版の nightly コンパイラをインストールしていますが、バージョンによっては動作しませんでした。
$ rustup toolchain install nightly
$ rustup component add rust-src --toolchain nightly
2-4: avr-gcc 関連のインストール
AVR-Rust ガイドブック 2.1. Installing required third party tools には以下の記載があります。
AVR Rustを使用するには、多数のサードパーティ製ツールが必要です。
avr-gcc (リンカー フロントエンドとしてのみ使用)
avr-binutils (リンカーサポート用)
avr-libc (デバイス固有のランタイム ライブラリ用)
avrdude (実際の AVR チップをフラッシュするため)
これらは、オペレーティング システムのパッケージ マネージャーによってインストールされる必要があります。
avr-gcc は、AVR マイコンを C/C++ でプログラミングする際に必要なコンパイラです。
Linux で AVR マイコンをプログラミングする際には、おなじみのツールかと思われますが、Windows の方は Atmel Studio をインストールすると勝手にインストールされるので、意識したことはないかもしれません。
avr-gcc インストール (Ubuntu)
公式ガイドブックに記載の通り、いくつかのツールをパッケージマネージャでインストールします。WSL2 経由でマイコンに書き込まない場合、avrdude は必要ありません。
$ sudo apt update
$ sudo apt install binutils gcc-avr avr-libc # avrdude は除外
avr-gcc インストール (Windows)
winget でインストールすることができます。
$ winget install --id=ZakKemble.avr-gcc -e
$ winget install --id=AVRDudes.AVRDUDE -e
次のソフトウェアをインストールしている場合は、avr-gcc.exe が含まれるディレクトリのパスを通すだけでも利用できるようになります。
私の環境では、次のディレクトリに avr-gcc.exe が存在しました。
- Arduino IDE (avr-gcc 7.3.0)
C:\Users\user\AppData\Local\Arduino15\packages\arduino\tools\avr-gcc\7.3.0-atmel3.6.1-arduino7\
- 入手先 https://www.arduino.cc/en/software
- Microchip Studio (avr-gcc 5.4.0, 旧 Atmel Studio)
C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\bin
- 入手先 https://www.microchip.com/en-us/tools-resources/develop/microchip-studio
3: プロジェクトのビルド
Rust nightly コンパイラと avr-gcc をインストールしたら、環境構築は完了しているはずです。
ここでは、AVR-Rust が提供しているサンプルをビルドするなどをして、動作を確認します。
3-1: Blink サンプルのビルド
AVR-Rust が提供しているサンプルをビルドしてみます。
GitHub - avr-rust/blink
リポジトリクローン
まずはサンプルを GitHub からクローンします。
クローン後は blink ディレクトりが生成されるため、カレントディレクトリを移動します。
$ git clone https://github.com/avr-rust/blink.git
$ cd blink
ソースコードは src/main.rs にあるため、開いてみます。
#![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 UNO であれば、ボード上の LED (PB5) がチカチカするサンプルとなっています。
ビルド前準備
動作確認につかったマイコンボード(ブレッドボード)は次のような状態です。
- マイコン: ATmega328P
- ヒューズビット: 0x62, 0xD9, 0xFF (出荷時状態 参考: https://www.engbedded.com/fusecalc/)
- クロック: 1 MHz (内蔵クロック 8 MHz を8分周)
それでは、ビルドしてみましょう。
公式サンプルの ReadMe.md や AVR-Rust ガイドブック に記載の方法だと、いくつか不具合があったので、少し調整して動かします。
まず、インストールされている toolchain のバージョンを調べます。
$ rustup toolchain list
stable-x86_64-pc-windows-msvc (default)
nightly-2024-04-23-x86_64-pc-windows-msvc # 今回使いたい nightly コンパイラ
nightly-x86_64-pc-windows-msvc
blink ディレクトリ内にある rust-toolchian.toml に、nightly コンパイラのバージョンを記述します。
[toolchain]
channel = "nightly-2024-04-23-x86_64-pc-windows-msvc" # 変更後
components = ["rust-src"] # 追加
マイコンの動作周波数を設定するため、.cargo/config.toml を変更します。
変更しないと、delay_ms() の時間に設定が反映されませんでした。
[build]
target = "avr-atmega328p.json"
[unstable]
build-std = ["core"]
# Cargo versions before 2021-02-23 won't recognize this: https://github.com/rust-lang/cargo/pull/9175
[env]
AVR_CPU_FREQUENCY_HZ = "1_000_000" # 16 -> 1 MHz に変更
次のコマンドでビルドします。
# config.toml を設定しているので、export コマンドは不要
$ export AVR_CPU_FREQUENCY_HZ=1000000
# AVR-Rust ガイドブック通り
$ cargo build -Z build-std=core --target avr-atmega328p.json --release
# config.toml を設定しているので、こちらで問題ないはず
$ cargo build --release
target/avr-atmega328p/release/
ディレクトリにある blink.elf
をマイコンに書き込むことで、正常にLチカを行うことができました。
3-2: cargo 新規プロジェクトのビルド
先ほど Blink サンプルの動作を確認しましたが、ビルドに最小限必要なファイルは限られます。
そこで、$ cargo new [プロジェクト名]
で作成できるプロジェクトでプログラミングする方法を試しました。
必要なファイル
最低限必要なファイルは次のとおりです。
- simple-blink ディレクトリ (プロジェクト)
- src ディレクトリ
- main.rs (ソースコード)
- .cargo ディレクトリ
- config.toml (ビルド時の設定ファイル)
- Cargo.toml
- Cargo.lock (blink から流用)
- avr-atmega328p.json (ターゲット仕様 JSON ファイル, blink から流用)
- rust-toolchain.toml (コンパイラ設定ファイル)
- src ディレクトリ
新規プロジェクトの作成
それでは、simple-blink プロジェクトを作成します。
# 新規プロジェクトの作成
$ cargo new simple-blink
# ディレクトリへ移動
$ cd simple-blink
Cargo.toml の編集
ruduino への依存関係を追加する必要があるため、dependencies に次の行を追加します。
[package]
name = "simple-blink"
version = "0.1.0"
edition = "2021"
# 以下の記述を追加(blink サンプルよりコピー)
[dependencies]
ruduino = { git = "https://github.com/avr-rust/ruduino", branch = "master" }
[profile.release]
opt-level = 'z'
lto = true
strip = true
src/main.rs の編集
もともとは Hello World のためのコードが記述されていますが、Blink サンプルをそのまま上書きしました。
#![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(500);
}
}
rust-toolchain.toml の作成
プロジェクトで Nightly コンパイラのバージョンを指定するため、rust-toolchain.toml を次のように作成します。
参考: Rustのrust-toolchain.tomlについて
[toolchain]
channel = "nightly-2024-04-23"
components = ["rust-src"]
正しく rust-toolchain.toml ファイルで指定できていれば、次のコマンドで確認できます。
$ rustup show
Default host: x86_64-pc-windows-msvc
rustup home: C:\Users\user\.rustup
installed toolchains
--------------------
stable-x86_64-pc-windows-msvc (default)
nightly-2024-04-23-x86_64-pc-windows-msvc
nightly-2024-04-24-x86_64-pc-windows-msvc
nightly-2024-04-29-x86_64-pc-windows-msvc
nightly-2024-04-30-x86_64-pc-windows-msvc
nightly-x86_64-pc-windows-msvc
active toolchain
----------------
(↓ ここに記載)
nightly-2024-04-23-x86_64-pc-windows-msvc (overridden by 'D:\user\Documents\Rust\simple-blink\rust-toolchain.toml')
rustc 1.79.0-nightly (7f2fc33da 2024-04-22)
ターゲット仕様 JSON ファイルの作成 (ファイル流用)
Blink サンプルにも入っている avr-atmega328p.json ファイルは、たくさんある AVR マイコンの型番を指定するために必要なターゲットファイルです。
AVR-Rust ガイドブック 3. Building a crate for AVR を読みながら作成してみましたが、コンパイル時のエラーを解消できず、結局作れませんでした。
そのため、Blink サンプルからそのままコピーして流用しています。
ターゲット仕様 JSON ファイルの作成 (ガイドブック)
今のところ成功していませんが、AVR-Rust ガイドブック 3. Building a crate for AVR を読みながら作成します。
Google翻訳によると、以下のようなことが記載されています。
- Rust Nightly コンパイラには、
avr-unknown-gnu-atmega328
という ATmega328 用の組み込みターゲットが含まれている - ATmega328 以外の MCU をターゲットにする場合、組み込みの
avr-unknown-gnu-atmega328
ターゲットをカスタム ターゲット仕様 JSON ファイルにエクスポートし、ニーズに合わせて変更する必要がある-
このファイルを別のマイクロコントローラをターゲットにするように調整するには:
- トップレベルの「cpu」:「atmega328」を「cpu」:「YOUR-AVR-VARIANT-NAME」に置き換えます
- 「-mmcu=atmega328」を「-mmcu=YOUR-AVR-VARIANT-NAME」に置き換えます
-
rustc --target <JSON FILE PATH>
を介してファイルを Rust に渡すことができます。これにより、生成されたコードが目的のマイクロコントローラに合わせて調整されます
-
今回使用するのは ATmega328P であり ATmega328 ではないので、ターゲット仕様 JSON ファイルをカスタマイズする必要があります。
まずは、Nightly コンパイラに組み込まれているターゲット仕様 JSON ファイルをエクスポートします。
$ rustc --print target-spec-json -Z unstable-options --target avr-unknown-gnu-atmega328 > avr-atmega328p.json
avr-atmega328p.json ファイルが作成されます。
ファイル中に記載されているマイコン名を atmega328 から atmega328p へ変更します。(3個ありました)
{
"arch": "avr",
"atomic-cas": false,
"cpu": "atmega328p",
"crt-objects-fallback": "false",
"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",
"is-builtin": true,
"late-link-args": {
"gnu-cc": [
"-lgcc"
],
"gnu-lld-cc": [
"-lgcc"
]
},
"linker": "avr-gcc",
"linker-flavor": "gnu-cc",
"llvm-target": "avr-unknown-unknown",
"max-atomic-width": 16,
"metadata": {
"description": null,
"host_tools": null,
"std": null,
"tier": null
},
"pre-link-args": {
"gnu-cc": [
"-mmcu=atmega328p"
],
"gnu-lld-cc": [
"-mmcu=atmega328p"
]
},
"relocation-model": "static",
"target-c-int-width": "16",
"target-pointer-width": "16"
}
ただ、AVR-Rust ガイドブックに沿って作成した avr-atmega328p.json を使用すると、次のようなエラーが出てきたため、使用できていません。
$ cargo build -Z build-std=core --target avr-atmega328p.json --release
error: failed to run `rustc` to learn about target-specific information
Caused by:
process didn't exit successfully: `C:\Users\user\.rustup\toolchains\nightly-2024-04-23-x86_64-pc-windows-msvc\bin\rustc.exe - --crate-name ___ --print=file-names --target \\?\D:\user\Documents\Rust\simple-blink\_avr-atmega328p.json --crate-type bin --crate-type rlib --crate-type dylib --crate-type cdylib --crate-type staticlib --crate-type proc-macro --print=sysroot --print=split-debuginfo --print=crate-name --print=cfg` (exit code: 1)
--- stderr
error: target file "\\\\?\\D:\\user\\Documents\\Rust\\simple-blink\\_avr-atmega328p.json" does not exis
トラブルシューティング
このままビルドすれば動くと思っていましたが、LEDが薄ら光るだけでうまく動きませんでした。
色々試してみたところ、Cargo.lock ファイルに記載されている avr_delay などのクレートのバージョンが異なることがわかりました。
- 動くバージョン avr_delay v0.4.0
- 動かない最新バージョン avr_delay v0.4.2
blink サンプルの Cargo.lock ファイルを simple-blink プロジェクトに上書きしてください。
Cargo.toml に正しくクレートのバージョンを指定することができれば、このトラブルを解決できそうですが、今のところはできていません。
基本的なビルド手順
AVR-Rust ガイドブック 3.2. A note about the required Rust -Z build-std= flag を読みながら、ビルドしていきます。
--target
オプションには、ターゲット仕様 JSON ファイルを指定します。
$ cargo build -Z build-std=core --target avr-atmega328p.json --release
次のような .cargo/config.toml
ファイルを作成することで、楽にビルドできるようにします。
[build]
target = "avr-atmega328p.json"
[unstable]
build-std = ["core"]
# マイコン動作周波数を指定
[env]
AVR_CPU_FREQUENCY_HZ = "1_000_000" # _ で区切ると読みやすい
楽なオプション指定でビルドします。
$ cargo build --release
target/avr-atmega328p/release/
ディレクトリにある simple-blink.elf
をマイコンに書き込むことで、正常にLチカを行うことができます。
4: 最後に
この資料を書いているのは、実践Rustプログラミング入門 を読み始めた程度の Rust 言語歴2日目の初心者です。
未だにクレートって何?という状態ではありますが、AVR マイコンを Rust で開発するまでの環境構築をまとめてみました。
AVR マイコンで Rust を動かそうと試行錯誤している人の助けになれば幸いです。