SOLID未分類 SOLID for Raspberry Pi 4 (連載26)

SOLID for Raspberry Pi 4 (連載26)

(2023/5/15)

26. 組み込みRust連載の振り返り

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割り込み未使用)

spi_adxl345クレート

SOLID-IDE Rustアプリケーション

PC側C#プログラム(Visual Studio 2019系)
(bin\Releaseフォルダ内にexecutableファイルがあります)

 

連載21に掲載しているソースコード:(SPI割り込み使用)

spi_adxl345クレート

SOLID-IDE Rustアプリケーション

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の連載は一旦終了しますが、またどこかで再開するかもしれません。
ここまで読んでくださった方々、ありがとうございました!