🐡

stm32-rsのクレートを用いてSTM32系マイコンボードのお手軽Rustプログラミング

2020/09/23に公開

Rustが組込み開発で注目されていて、すでによくできたドキュメント類が用意されています。
また、ペリフェラルドライバのクレートがいくつか用意されています。

STM32系であれば、stm32-rsコミュニティが管理するクレートを用いれば、USARTやLEDなどのモジュールをお手軽に利用できます。
今回は自分の手元にあるNUCLEO-F429ZI用にstm32f4xx-halクレートでシリアル通信を例に解説します。

実際にシリアル通信のループバックを組んだレポジトリを以下に用意しました。
garasubo/stm32f4xx-hal

依存するクレート

このレポジトリで使用されているクレートから説明していきます。レポジトリ内のCargo.tomlを参照してください。

  • panic-haltno_stdのプログラミングではパニックした際の関数をこちらから与える必要があります。panic-haltは無限ループで止まるパニック関数を提供します
  • cortex-m-rt:Cortex-Mマイコン向けにno_stdのプログラミングのためのマクロなどを提供してブートストラップを助けてくれます。例外ハンドラの登録もできますが、今回は利用していません
  • embedded-hal:Rust Embeddedグループにより組込みでよく使うペリフェラル向けのトレートが定義されています。これに沿ってペリフェラルドライバを組めば他の場所での再利用が見込めます
  • stm32f4xx-hal:stm32f4xx向けのペリフェラルドライバの実装が提供されています。featuresによってボードを切り替えることができます。rtcortex-m-rtとの連携のため必要です。ベースはsvd2rustで作られたコードになっています。

コードの解説

src/main.rsについて解説します。1、2行目はベアメタルプログラミングではお馴染みの標準ライブラリを使わないための宣言とmain関数が存在しないことを宣言するためのものです。
extern crate panic_haltによってパニック関数を取り込んでいます。
cortex_m_rt::entry属性を付与されたmain関数はクレート側でbssセクションの初期化等の最低限のブートストラップ処理をした後実行されることになります。
Periphrals::take()でシングルトン化されたペリフェラルインターフェースが手に入れられます。今回は他で使う箇所がないのでunwrapしても大丈夫です。

今回シリアル通信に使うのはUSBケーブルから利用できるUSART3で、PD8をTX、PD9をRX用のピンとして利用します。
into_alternate_af7とすることで、そのピンに対してalternateモードを有効化させることができます。af7がUSART用のモードです。
この辺の機能はstm32f4xx_hal::gpio::GpioExtによりsvd2rustで定義された型を拡張させて使っています。
更に、この結果には型がついていて、これにより間違った設定のピンをシリアル通信に使おうとすることを型レベルで強制することができています。
config変数はシリアル通信の通信速度などの設定です。デフォルトのボーレートだといつも自分がシリアル通信用に使うminicomの設定と合わなかったので、ボーレートのみ上書きしています。
クロックの設定はデフォルトのものを使っています。

これらをSerail::usart3に渡します。第2引数のpinsはTX用のピンとRX用のピンが渡されることが期待されます。
しかし、渡されるピンには型がついていて、使えるピンにのみこの関数は定義されているので、間違ったピンを渡してもコンパイルエラーで落ちることでしょう。

最後のループはシリアルから1バイトだけ文字を読み込みそれをそのまま返すだけの無限ループになっています。

そのほか

memory.xcortex-m-rtのために必要です。フラッシュのメモリ領域とRAM領域のアドレスを教えてあげないとちゃんとリンクできないということです。
また、.cargo/configでリンカースクリプトを指定して、デフォルトのターゲットも変更しておくと便利でしょう。link.xcortex-m-rtから提供されます。

まとめ

今まで自分のブログでは他のクレートをあまり使わない形での組込みプログラミングを紹介していましたが、今回はがっつりとクレートをつかうものを紹介しました。

今回はzenn.devというサービスのテストを兼ねて簡単めな記事を書いてみました。

Discussion