chakokuのブログ(rev4)

テック・コミック・DTM・・・ごくまれにチャリ

組み込みRustのむつかしさ

STM32用のRust開発環境を設定して、I2CとかUARTとかボチボチ動いている。が、、あくまでもサンプルコードをベースに修正した程度である。
素の状態から最低限のコードだけで動かそうとすると、いろいろエラーが出てくる。一つはSTM32用ライブラリのエラーで、もう一つはコンパイル時のundefined simbleのエラー。
ブログ等に掲載されているSTM32用サンプルコードがいろいろあるのだけど、STM32LシリーズやSTM32Fシリーズ等、マイコンのシリーズが違ってくるとstm32-HALのライブラリが異なるのか、メソッドが無いといって怒られる。確かにハードウエアが異なるからライブラリも違ってくるので、そこはソースをよく読んで、シリーズごとの違いを手修正で直さないといけないのかも。
で、、ライブラリの不整合が無くなってもリンカの最終段階で、undefinedシンボルで怒られる場合がある。こちらはかなり厄介だ。スタートアップとかが正しく指定できていないのかもしれないが。
Rustという言語のむつかしさもあるけど、それ以上に、ライブラリ不整合、リンカでのundefinedシンボルの問題と、なかなかに道は険しいのであった。
だからどうすべきか??? 自分でスタートアップ書いたり、リンカ定義ファイルを作るぐらいの根性がないと、このレベルの不具合解消は難しい。素でくみ上げるぐらいの気合で取り組むか、、はたまた、基本的にサンプルコードを極力踏襲して、サンプルコードから差分だけ変えて作るか。。

リンカでのエラー、StartUpルーチンが何かおかしいようだ

  = note: /usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o: in function `_start':
          (.text+0x16): undefined reference to `__libc_csu_fini'
          /usr/bin/ld: (.text+0x1d): undefined reference to `__libc_csu_init'
          /usr/bin/ld: (.text+0x2a): undefined reference to `__libc_start_main'
          collect2: error: ld returned 1 exit status

上記と同じような症状の記事、解決策がいまいちわからんが・・
"Hello World" no_std linker error - help - The Rust Programming Language Forum

プロジェクトのディレクトリに.cargoディレクトリを掘って、config.tomlを以下の内容で設定したら上記エラーは解消した。

$ cat .cargo/config.toml
#
#
[build]
rustflags = ["-C", "link-args=-lc"]

というわけで、、先人のブログを参考にしつつ、なんとか素のSTM32L4X6のひな型はできたようだ。
素のひな型ができたところで、STM32のGPIOを加えると、途端にリンク時のエラーが出た。浅い理解で組み込みRustを使っているせいだろう。リンクする対象が間違ってるのか、ビルドの指定が間違っているのか。。素の状態から自分の望むライブラリを加えるアプローチだと、エラーが頻発して、その都度やり直しになる。勉強にはなるかもだけどいくら時間があっても足りない。だから、、サンプルのモリモリのコードを削って必要な分だけ残すアプローチに変更する。

= note: <path_user>/lang/rust/stm32/src/paisen/target/debug/deps/paisen-f8a7cd7c539f1067.25lazqxwii3x4twt.rcgu.o: in function `cortex_m::interrupt::enable':
/home/sumi/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-0.7.3/src/interrupt.rs:48: undefined reference to `__cpsie'
<path_user>/lang/rust/stm32/src/paisen/target/debug/deps/paisen-f8a7cd7c539f1067.25lazqxwii3x4twt.rcgu.o: in function `cortex_m::interrupt::disable':
/home/sumi/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-0.7.3/src/interrupt.rs:38: undefined reference to `__cpsid'
<path_user>/lang/rust/stm32/src/paisen/target/debug/deps/paisen-f8a7cd7c539f1067.anqm6z1ob0uppwu.rcgu.o: in function `cortex_m::register::primask::read':
/home/sumi/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-0.7.3/src/register/primask.rs:29: undefined reference to `__primask_r'
collect2: error: ld returned 1 exit status

所有権関連で出たエラー

error[E0507]: cannot move out of `self.serial_port` which is behind a shared reference

おおよその意味は、「借用している値なので、変更してはいけません」(所有権は移動できません、かも)。構造体等の値はあちこちに移さず、ライブラリ内で生成、利用、消費すべきか。。

SerialやらSPIやらペリフェラルの操作をモジュール化して分割したいのだが、、あまり理解せずにモジュール化しても所有権の問題が出て以下のように怒られたりする。

error[E0507]: cannot move out of `self.serial_port` which is behind a shared reference
61 |      let (mut tx,_) = self.serial_port.split();
   |                       ^^^^^^^^^^^^^^^^ move occurs because `self.serial_port` has type `Serial<hal::pac::USART2, (PA2<Alternate<hal::gpio::AF7, Input<Floating>>>, PA3<Alternate<hal::gpio::AF7, Input<Floating>>>)>`, which does not implement the `Copy` trait

ポート等のレジスタはメモリマップドIOなので、Rustからはメモリ(構造体か?)とみなして動くのだが、、Rustでは構造体は所有権で守られていて、気軽にサブルーチンに渡してレジスタ操作しようとしても、所有権がないと怒られるのであった。

組み込みRustをまずはきっちり勉強すべきかも。
導入 - The Embedded Rust Book
所有権とは? - The Rust Programming Language 日本語版
自分がRustの処理系になったつもりで、どんなタイミングでメモリを回収するのか?をよく考えると、所有権が多少は理解できて、上記のような権利ある、なしに悩むことがなくなるのかも。

ここ数日のRustによるプログラミングを振り返ってみて、、ハマりポイントは、(1)Rustによる所有権の扱い(自分の理解不足)、(2)STM-HALと呼ばれるハード抽象化レイヤーに対応したライブラリ(stm32l4xx_hal)の使い方の2点であった。サンプルはmainでLチカとかシリアルとかを動かしているのだけど、これを外部モジュールに出そうとすると、途端にレジスタ(構造体)の所有権が問題になってくる。少し自分のやりたいように変えようと思っても所有権に正しく対応したコードが書けないので、文法的には(所有権も文法か?)正しくても権限の点でコンパイル段階でエラーとして拒否される。というわけで、、勉強もかねて、HALの部分は自力でSTM32用のドライバを作るつもりです。最初のうちは、Singletonモデルにならず、複数のライブラリでレジスタを触れてしまうかもしれないけど、、自分の腕が上がってきたら、レジスタはSingletonモデルを導入して、正しく排他できるようにすればよいかと。まずはどうにかして動かすのが先決。

リンカの定義やstartupまで公開している記事があるので(情報開示ありがたい)、この記事等を参考に、一度素から組んでみたい。。
rust で組み込み(Cortex-M3) – GitHub 出張所 – プログラム関係のブログはここに


■追記(2022/2/1)
Rustを学んでマスターしたいと思っていたが、組み込みRustのむつかしさ(所有権をクリアして周辺IOをどう使っていいのか分からない、マイコンシリーズに適用できるライブラリはどれを使ったらいいのか分からないetc)の壁が厚く、Droneを飛ばす件は音が大きくてヨメサンに怒られることもあって、一旦中断、今は Dart/Flutterでマルチプラットフォームのスマフォアプリを作ろうとしているという。。