📟

Rustでmicro:bit

2022/12/10に公開

この記事はEEIC Advent Calendar 2022の10日目の記事です。

こんにちは。EEIC2022のゆうてんです。EEICアドカレ、今年こそはと思い参加させていただきました。さて、今の時期はBDMが旬ということで、micro:bitをRustで動かしてみたという話をしようと思います。

micro:bitとは

ご存知の方も多いと思いますが、micro:bitについて軽く。

micro:bitとは、イギリスのBBCが主体となって作った教育向けマイコンボードです。日本では2020年に発売したもので、現在はmicro:bit-v2がメインのバージョンとなっています。
micro:bitは教育向けとされていますが、そのコアにはARM Cortex-M4が搭載されていて結構やれることは多いです。また、GUIを用いたノーコード開発やPythonを用いた開発もサポートされており、どちらもブラウザで完結するので環境構築の楽な点も魅力の一つです。今回はそんなmicro:bitをrustで動かして見たいと思います。
micro:bit

Rustとは

Rustとは、モダンなマルチパラダイム言語であり、C++の代わりを目指している言語です。所有権というシステムやゼロコスト抽象化によって、メモリ安全性を確保しながらC++とほぼ同等の速度を出すことができます。Rustの詳しい説明は省きますが、設計思想を見るだけでも大変面白い言語ですのでみなさんもぜひRustについて調べて見てください。

Rustでmicro:bit

それでは、本題に入って行きたいと思います。今回の実行環境は

  • OS:Ubuntu 22.04(wsl2)
  • CPU:11th Gen Intel Core i7
  • GPU:Geforce RTX 3060 laptop

です。wsl2で実行するにあたっては、wsl2にUSBを認識させる必要がありますが、それについては公式ドキュメントが参考になると思います(Ubuntu 22.04を使っている人はlinux-tools-genericのバージョンに注意)。また、micro:bitを接続するにあたってこちらの設定も必要です。
Rustでmicro:bitに関しては、公式チュートリアルがあるので、こちらを参考にやっていきます。

Rust開発環境

さて、まずはRustの開発環境を構築していこうかと思います。一番簡単な方法はrustupというツールを用いる方法です。rustupのインストール方法についてはこちらのサイトにあります。wsl2上なら

$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

です。
rustupによって、rustコンパイラのrustcやビルドシステム兼パッケージマネージャーのcargoなどがインストールされます。rustupダウンロード後、指示のとおりにpathを通してインストール完了です。コンソールで

$ rustc --version

を実行し、バージョンが出力されればインストール完了です。

Hello World

micro:bitに入る前に、まずは普通にRustでHello,Worldしてみたいと思います。Rustでプロジェクトを作成するには

$ cargo new hello_world

のようにします。
これでプロジェクトが作成されるわけですが、このうち、編集するのは主にCargo.tomlとmain.rsです。Cargo.tomlはrustのバージョンや依存パッケージなどを記載するファイル、main.rsはrustのソースファイルでmain関数を含みます。

コードを実行するには、Cargo.tomlがあるディレクトリで

$ cargo run

とすれば、プログラムがコンパイルされ、main内のmain関数が実行されます。

以上がRustの大まかな説明です。それでは、micro:bitで実行するための環境構築に入っていこうかと思います。

クロスコンパイラの設定

まずはcargo-binutilsとcargo-embedをインストールします。

$ rustup component add llvm-tools-preview

$ cargo install cargo-binutils

$ cargo install cargo-embed

cargo-binutilsは、rustupのllvmツールを呼び出すためのcargoのサブコマンドです(cargoは独自のコマンドで機能を拡張できます)
cargo-embedは、組み込み機器に対して、rust実行に必要な操作(build, flash, uploadなど)を行えるサブコマンドです。
以上のツールを用いることで、簡単にRustを組み込み機器上で扱えるのです。

Lチカ

それでは、Lチカしたと思います。今回は、micro:bitに搭載されている5 \times 5LEDを用いて、"EEIC"と光らせてみましょう。作成したプログラムについてはこちらのリポジトリにあります。実行は、Cargo.tomlがあるディレクトリで

cargo embed

でできます。実行の様子はこんな感じです

以下、プログラムを説明する前に、実行に必要なファイルを説明しようと思います。

Embed.toml

これはcargo-embedを使う際に必要なもので、細かい説明はここにありますが、簡単に説明すると、ターゲットのチップや、書き込む前にリセットを行うか、書き込み後にRTT(Real Time Transfer)、gdbを使用するか等の設定を行うファイルです。

memory.x build.rs

memory.xは書き込み対象のメモリの開始アドレスと大きさが記載されており、これを用いてビルド中の中間ファイルをどこに作成するのがbuild.rsです。

comfig

.cargo/configは、buildのtargetやflagを設定するファイルです。

これらの設定ファイルによって、クロスコンパイルが実行可能となります。ここまできたら、あとはmainプログラムを作成するだけです。

main

mainプログラムは見ればなんとなく解ると思いますが、BSPによって提供されているLEDのAPIを用いてLEDを点灯させています。通常のプログラムと異なるのは、stdを用いないことと、プログラムのエントリーポイントがmain関数ではないことです。
cortex-m-rでは、main関数の代わりに#[entry]属性を持つ関数をエントリーポイントとすることになっています。これは、main関数というのが引数を受け取るコマンドラインアプリケーションに合わせたものだからです。
また、エントリーポイントの関数は絶対に終了しないので、関数の返り値を!とします。あとは、BSPによって提供されるAPIを用いてシリアル通信やスピーカー等々色々できます。

最後に

以上がrustでmicrobitを動かしてみた話になります。興味を持っていただけたなら幸いです。Lチカではrustの利点はあまりありませんが、複雑な処理を行う際はそのメモリ安全性が必ず武器になると思います。僕自身、組み込みのこともrustのことも全然詳しくないので、より学びを深めていきたいものです。それでは。

参考文献

wslでUSBデバイスを用いる
組み込みRust Discovery

Discussion