組み込みRust連載の振り返り(連載26)
10月から始めたこの連載も、26回目を迎えました。
その期間、半年です!
こんなに続くとは思っていませんでした。
最初は、
・C/C++にはない概念の「所有権」とか「借用」とかってよくわからないよね。
・よくわからないけど、なんか「安全」らしいね。
・パッケージマネージャーとかクレートとかあるらしいよ。
・勉強がてら、Rust初心者向けに連載した記事を書いてみよう!
で、数か月くらいかかるかなぁ、の、ノリだったのですが。。。
実際に書いていると、次から次へと疑問が湧いてくるんですね。
その観点は一貫していて、
「C/C++で普通に書いているアレ、Rustでも書けるの?」
心配せずとも、書けましたね。
その結果、最後の25回目などはunsafeだらけになってしまいましたが。
でも良く考えると、Rustでunsafeにならざるを得ないコードって、C/C++を使って書いたとしても低レベルレイヤーにまとめておくべきコードです。
結局は同じレイヤー構造になるのだし、違和感は全くないことと、その上位のレイヤーからはほぼunsafeブロックは登場せず(何でも同じかともいますが少しの例外はあります)、「安全性・メンテナンス性」というRustの恩恵を受けることが “組み込み” でもできる、という事がわかった半年間でした。
とはいえ、まだまだRustですらすらとは書けない。
連載記事執筆中にでも、何度過去記事に戻って思い出し作業をしたことか。
さて、前置きが長くなりましたが、そのような理由で、今までの内容について振り返ってみたいと思います。
1.連載1-4回:導入部
Rustのプログラムを試してみるための実機環境について記載しました。
Raspberry Pi 4上でSOLID-OSを走らせ、RustでビルドすることができるSOLID-IDEを用いてプログラム作成するための準備期間です。
特に第4回。
筆者としては、初めてRustのプログラムを「見る」作業をした回です。(「読む」にはほど遠く。。。)
最初に、「RAWなプログラム」という事で、GPIOレジスタを直接操作するプログラムがありました。unsafeだらけで、あまりRustの恩恵のないプログラムです。
次に、GPIOレジスタを直接操作する部分がパッキングされたPAC(peripheral access crate)というクレートを使用して、自身のコードにはunsafeを極力使用しないコードを見ました。
そしてIDE経由でデバッグができることを確認しました。
導入回だったので、用いたプログラムの内容はほぼわからず、「何かのおまじないかな?」という感じでしたが、今見てみるとわかるようになっているのが嬉しいです。
2.連載5-10:浅く知識を集める
Rustの特徴である事項について、有識者の方々に教えて頂きつつ書きました。
実験もしたので、具体的にわかるように書いたつもりです。
筆者自身ちょくちょくここを見て思い出しています。(覚えきれていない)
・所有権のムーブ
・所有権の借用
・ライフタイム
・命名規則
・文字列は常にUTF-8
・構造体のデータレイアウト
・初期状態について
・Cargoとは
・依存関係
・クレートを作る
・使用したサンプルのコードで使っている文法
・2022年末時点での組み込みRust
3.連載11-21:実際にコードを書く
ここでは、SPI加速度センサを制御するプログラムをRustで書きました。
やはり実際にコードを書くと学びが多いです。
PAC(peripheral access crate)を使用してGPIOを操作するところから始まります。
SPIレジスタ操作では、FIFOアクセスやビット操作等あり、GPIOレジスタとは違っていろんな操作方法がありました。
・新規ワークスペース作成(SOLID-IDEの使い方)
・PACを使用するためCargo.tomlに依存関係を記述
・GPIOレジスタを書き込み操作
・SPIレジスタを書き込み操作
・ビットポーリング
・内蔵I/O操作時のデバッグ(SOLID-IDEの使い方)
・同じ処理の連続をループ処理にする
・Field構造体、FieldValue構造体
・フォーマッタ
・ビットポーリング用while文は一文で書ける
・ビットのセット&クリア
・関数の引数
・レジスタの読み込み操作
・データのシフトと結合
・関数の戻り値
・データをi32からf32にキャスト
・u8からi32に変換
・データを下位側から詰める
・関数の最後のreturnは不要
・関数の戻り値が複数個の場合
・使用するSOLID-OSインタフェースの定義
・32ビットのfloatからバイト配列への型変換
・スレッドの作成
・スレッド間共有変数Arc<Mutex<_>>と排他制御
・スレッド間共有変数を実際に使う
・スレッド間共有変数の構造体化
・共有変数:lock()後にunwrap()することが多い理由
・Arc<Mutex<_>>以外の共有変数
・バッファオーバーフローの実験
・バッファオーバーフローした共有変数への他スレッドからのアクセス実験
・割り込み登録用SOLID-OSカーネルAPIを使う
・割り込み許可用SOLID-OSカーネルAPIを使う
・SOLID-OSカーネル 割り込み登録用構造体
・SOLID-OSのAPIコールのためにsolidクレートを使えるようにする
・SOLID-OSのAPIコールによる割り込み登録(実践)
・SOLID-OSのAPIコールによる割り込み許可(実践)
・SOLID-IDEを使用して割り込み発生の確認
・コールバック関数との共有変数をすべて構造体にまとめる
・他タスク処理待ち間、自タスクをスリープする
・SOLID-OSのAPIコールによる割り込み優先度の最大値取得
・pin_singleton!とは、CpuCx<'a>とは
Rustとは関係ありませんが番外編で、加速度センサADXL345の制御について。
・SPI送信フロー(Raspberry Pi 4⇒ADXL345)
・SPI受信フロー(ADXL345⇒Raspberry Pi 4)
・加速度センサデータから加速度値取得
・SPI信号波形
・取得した加速度データの結果
・SPI割り込みを使う場合のハードウェア初期化
・BCM2711の割り込み仕様
・SPI割り込みハンドラですべきこと
・SPI転送完了割り込みを使って通信した波形
・コールバック関数との共有変数
こちらは興味深い比較でした。
・SOLID-OS向けのTCP/IP通信コードをRustとC++で比較
4.連載22-24:C/C++ Rust
この部分はC/C++関数とRust関数間の呼び出し、データ渡しについての記載です。
既に存在するC/C++で書いたソースコードを流用し、機能追加部分をRustで書く、といったケースは現実的に多くなるように思います。
[C/C++で書かれた関数をRustからコール]
・autocxxクレート
・autocxxクレート:関数コール
・autocxxクレート:構造体
・もっと簡単な方法
・どの方法を選択するか
[Rustで書かれた関数をC/C++からコール]
・SOLID-IDEで新規ワークスペース作成
・no_mangle
・関数コール時の引数(定義数が合わない場合なども実験)
・関数リターン時の戻り値
・引数に配列等がある場合
・戻り値に配列等がある場合
・構造体として確保された領域を共有する場合
5.連載25:組み込みでよく使うアレはどうなの?のシリーズ
今まであまり出てこなかったけれども気になる、以下の項目について書きました。
・構造体のデータ配置について
・構造体を共用体の中に入れる
・メモリのアライメントを意識した配置
・Volatile
・ビットフィールド
・セクション定義
・インラインアセンブラ
6.ソースコード ダウンロード
今回の連載で作成したソースコードのうち、SPI加速度センサADXL345 を制御する記事のあたりで
SOLID-IDE用ワークスペースごとZIPファイルで圧縮し、ダウンロードできるようにしてあります。
こちらにもご紹介します。興味のある方、ぜひダウンロードしてみてください。
連載18に掲載しているソースコード:(SPI割り込み未使用)
PC側C#プログラム(Visual Studio 2019系)
(bin\Releaseフォルダ内にexecutableファイルがあります)
連載21に掲載しているソースコード:(SPI割り込み使用)
PC側C#プログラム(Visual Studio 2019系)
(bin\Releaseフォルダ内にexecutableファイルがあります)
Raspberry pi4があれば試してみることが可能です。
#PC側プログラムは何のエラーチェックもしていないので、データが返信されてこない場合等例外が発生します。
7.振り返ってみる
今回の連載で、結局は、ソースコードにどれだけ美意識を持てるか、だな、と思いました。なんでもそうですよね。美意識をもって物事を遂行すると、うまくいくことが多いような気がします。
・机の上も、カバンの中も、美しく整えると効率が良い。
・美しい数式は感動を与える。
・美しい言葉は気分が良い。
・美しいコードは持続性があり、かつ、不具合要因を減らす。
ちょっと気取ってみましたが、別にだからといってRustを使わないといけない、とは思っておらず、C/C++でもPythonでもなんでも、美しいコードを書くという事をもうちょっと心がけようと思った次第です。
そして、Rustは美しいコードを書きやすい、という事だと思いました。
この半年間、いかにRustが安全でありメンテナンス性に優れているか、について毎週感動し続けてきました。
最初は「???」という感じだったのですが、実際にコードを書き始めたあたりから、急にいろいろわかるようになりました。
なんでもそうですね。まずやってみるのが一番!
“組み込み” という観点からすると、まぁ大体のことは網羅できたのかなぁ。。。という気がします。
何も見ずにすらすらとRustのコードが書けるまでには程遠いですが、調べながらであれば結構大丈夫。
Rust初心者の筆者に粘り強くRustの考え方について教えてくださった、有識者の方に感謝します。
これでRust×組み込み with SOLID-OSの連載は一旦終了しますが、またどこかで再開するかもしれません。
ここまで読んでくださった方々、ありがとうございました!