まだ探求すべきこと
私たちはまだほんの表面をなぞったにすぎません! まだ探求すべきことがたくさん あります。
注記: これを読んでいて、以下の項目のいずれか、あるいはその他の関連する 組み込みトピックについて、Discovery book に例や練習問題を追加するのを 手伝いたいと思ってくださるなら、ぜひ力を貸してください!
手伝いたいけれど、これを本にどう貢献すればよいかについて支援やメンタリングが 必要な場合は、open an issue してください。あるいは、その情報を追加する Pull Request を開いてください!
MB2 のさらなるトピック
本書の中で、私たちは MB2 上のハードウェアの大部分に触れてきました。とはいえ、まだ 探求すべき MB2 のトピックがいくつか残っています。
ダイレクトメモリアクセス (DMA).
一部のペリフェラルには DMA があり、これは一種の 非同期な memcpy で、CPU が関与しなくても
ペリフェラルがメモリとの間でデータを移動できるようにします。
micro:bit v2 を使っているなら、実はすでに DMA を使っています。HAL が UARTE と TWIM ペリフェラルでこれを行ってくれるからです。DMA ペリフェラルはデータの一括転送に使えます。 たとえば RAM から RAM、UARTE のようなペリフェラルから RAM、あるいは RAM から ペリフェラルへの転送です。DMA 転送をスケジュールして — たとえば「このバッファに UARTE から 256 バイト読み込む」— バックグラウンドで実行したままにできます。あとで何らかの レジスタを確認して転送が完了したかを見ることもできますし、転送完了時に割り込みを 受け取るようにすることもできます。つまり、DMA 転送をスケジュールし、その転送が進行して いる間に別の作業を行えます。
低レベルの DMA の詳細は少し厄介になることがあります。このトピックを扱う章を近いうちに 追加したいと考えています。
embedded-hal の pwm module には PWM を扱うための抽象化がいくつかあり、nrf52833-hal
にはこれらのトレイトの実装があります。
デジタル入力と出力
私たちはマイクロコントローラのピンをデジタル出力として使い、LED を駆動してきました。 スネークゲームを作るときには、これらのピンをデジタル入力として設定する方法も少し 垣間見ました。デジタル入力としては、これらのピンでスイッチの二値状態(オン/オフ)や ボタンの状態(押されている/押されていない)を読み取れます。
デジタル入力と出力は embedded-hal の digital module で抽象化されており、
[nrf52833-hal] にはその実装があります。
(ネタバレ スイッチ / ボタンの二値状態を読み取るのは、聞こえるほど単純ではありません ;-) )
アナログ-デジタルコンバータ (ADC)
世の中にはデジタルセンサーがたくさんあります。I2C や SPI のようなプロトコルを使って それらを読み取れます。しかし、アナログセンサーも存在します! これらのセンサーは、 ADC 入力ピンで検知している電圧の読み取り値をそのまま CPU に出力します。
したがって ADC ペリフェラルを使えば、“アナログ” な電圧レベル — たとえば 1.25 ボルト —
を、プロセッサが計算に使える “デジタル” な数値 — たとえば 24824 — として測定できます。
embedded-hal には汎用的な ADC トレイトがありましたが、embedded-hal 1.0 では削除されました:
issue #377 を参照してください。nrf52833-hal クレートは、nRF52833 に内蔵された固有の ADC
に対する使いやすいインターフェースを提供します。
デジタル-アナログコンバータ (DAC)
想像どおり、DAC は ADC とちょうど逆のものです。レジスタにデジタル値を書き込むことで、 あるアナログ出力ピンに特定の電圧を出せます。このアナログ出力ピンを適切な電子回路に接続し、 正しい値を高速にレジスタへ書き込めば、音や音楽を生成するといったことができます。
nRF52833 にも MB2 ボードにも専用の DAC はありません。一般には、PWM を出力し、その出力側に 少し電子回路(RC フィルタ)を追加して PWM 波形を “平滑化” することで、DAC のような効果を 得ます。
リアルタイムクロック
リアルタイムクロックのペリフェラルは、通常は “人間向けの形式”、つまり秒、分、時、日、月、年 で、独自の電源により時刻を保持します。リアルタイムクロックの中には、うるう年や 夏時間を自動で扱えるものもあります。
nRF52833 にも MB2 ボードにもリアルタイムクロックは搭載されていません。nRF52833 には
“Real-Time Counter” (RTC) があり、これは nrf52833-hal でサポートされている低周波で刻む
クロックです。このカウンタを専用に使って、疑似的なリアルタイムクロックとして機能させる
ことができます。もちろん、そのための重要な要件は、MB2 を使っていないときでも RTC
ペリフェラルに給電し続けることです。MB2 にはオンボードバッテリーはありませんが、MB2 の
バッテリーポートにバッテリーを接続しておけば、RTC は長期間(場合によっては数年)動作
できるはずです(たとえば、micro::bit Go kit に付属するバッテリーパックなど)。
その他の通信プロトコル
- SPI: 「Serial Peripheral Interface」は、いくつかの点で I2C に似た高速通信
インターフェースです。SPI は
embedded-halspimodule で抽象化されており、 [nrf52-hal] によって実装されています。 - I2S: 「Inter-IC Sound」プロトコルは、音声伝送向けにカスタマイズされた I2C の一種です。
I2S は現在
embedded-halでは抽象化されていませんが、[nrf52-hal] によって 実装されています。 - Ethernet:
smoltcpという小さな TCP/IP スタックが存在し、一部のチップ向けに 実装されています。MB2 には Ethernet ペリフェラルはありません - USB: これについてはいくつか実験的な取り組みがあり、たとえば
usb-deviceクレートが あります。MB2 では、USB ポートはホスト MCU ではなくインターフェース MCU によって 管理されているため、独自の USB 機能を扱うのは難しくなります。 - Bluetooth: Embassy の MB2 ランタイムが提供する
nrf-softdeviceラッパーは、おそらく MB2 の Bluetooth への最も簡単な入り口です。Embassy には Rust ネイティブのTrouBLEBLE ホストクレートもあります。 - CAN、SMBUS、IrDA など: 世界にはあらゆる種類の特殊用途インターフェースが存在し、Rust が それらをサポートしていることもあります。必要なインターフェースの現状は、ぜひ調べてみて ください
アプリケーションによって使う通信プロトコルは異なります。ユーザー向けアプリケーションには通常 USB コネクタがあります。これは、USB が PC やスマートフォンで広く使われているプロトコル だからです。一方、自動車の内部には多くの CAN バスがあります。デジタルセンサーの中には、 SPI、I2C、SMBUS を使うものもあります。
embedded-hal における抽象化や、一般にペリフェラルの実装を開発することに興味があるなら、
気後れせずに HAL リポジトリで issue を開いてください。あるいは
Rust Embedded matrix channel に参加して、上で挙げたものを作った人たちの多くと
連絡を取ることもできます。
一般的な組み込み関連トピック
これらのトピックでは、私たちのデバイスやその上のハードウェアに固有ではない項目を扱います。 その代わりに、組み込みシステムで使える有用な技法について説明します。 ここで取り上げるハードウェアの多くは MB2 では利用できませんが、その多くは安価なハードウェアを MB2 のエッジカードコネクタに接続することで簡単に追加でき、それを直接駆動することも、SPI や I2C のようなものを使って制御することもできます。
マルチタスキング
これまでのプログラムのほとんどは、単一のタスクを実行していました。では、OS がなく、したがってスレッドもないシステムで、どうすればマルチタスキングを実現できるでしょうか。マルチタスキングには主に 2 つの方式があります。プリエンプティブ・マルチタスキングと協調的マルチタスキングです。
プリエンプティブ・マルチタスキングでは、現在実行中のタスクは、どの時点でも別のタスクによって プリエンプト(中断)される可能性があります。プリエンプトが発生すると、最初のタスクは一時停止され、代わりにプロセッサが 2 つ目のタスクを実行します。やがて最初のタスクは再開されます。マイクロコントローラは、割り込み という形でプリエンプションをハードウェア的にサポートしています。割り込みについては、第16章 でスネークゲームを作ったときに学びました。
協調的マルチタスキングでは、実行中のタスクは サスペンドポイント に到達するまで実行されます。プロセッサがそのサスペンドポイントに到達すると、現在のタスクの実行を停止し、代わりに別のタスクを実行します。やがて最初のタスクは再開されます。この 2 つのマルチタスク方式の主な違いは、協調的マルチタスキングでは、実行のどの時点でも強制的にプリエンプトされるのではなく、既知の サスペンドポイントで実行制御を 譲る ことです。
ジャイロスコープ
Punch-o-meter の演習の一環として、3 次元の加速度の変化を測定するために加速度計を使いました。しかし、ジャイロスコープのような別のモーションセンサーもあり、これを使うと 3 次元での「回転」の変化を測定できます。
これは、転倒を避けたいロボットのような特定のシステムを構築しようとするときに非常に役立ちます。さらに、ジャイロスコープのようなセンサーから得られるデータは、センサーフュージョンと呼ばれる技法を使って加速度計のデータと組み合わせることもできます(詳細は以下を参照してください)。
サーボモーターとステッピングモーター
一部のモーターは、たとえばラジコンカーを前進または後退させるように、主に一方向または逆方向に回転させるためだけに使われますが、モーターがどのように回転するかをより正確に測定できると便利なこともあります。
マイクロコントローラを使ってサーボモーターやステッピングモーターを駆動できます。これにより、モーターが何回転するかをより正確に制御でき、さらにはモーターを特定の位置に位置決めすることもできます。たとえば、時計の針を特定の方向に動かしたい場合などです。
センサーフュージョン
micro:bit には 2 つのモーションセンサー、加速度計と磁力計が搭載されています。 それぞれ単体では、(固有)加速度と(地球の)磁場を測定します。 しかし、これらの量は「融合」して、より有用なものにできます。つまり、どの単一のセンサーよりも測定誤差が少ない、ボードの姿勢の「ロバストな」測定値です。
異なるソースからより信頼性の高いデータを導き出すこの考え方は、センサーフュージョンと呼ばれます。
では、次はどこへ進めばよいのでしょうか?
まず何よりも、Rust Embedded matrix channel に参加してください。そこには、組み込みソフトウェアに貢献している人や関わっている人がたくさん集まっています。たとえば、microbit BSP、nrf52-hal クレート、embedded-hal クレート群などを書いた人たちもいます。Rust での組み込みプログラミングを始めるときにも、さらに先へ進みたいときにも、私たちは喜んでお手伝いします!
ほかにも多くの選択肢があります:
microbit-v2ボードサポートクレートのサンプルを見てみるのもよいでしょう。そこにあるサンプルはすべて、手元の micro:bit ボードで動作します。
- 現在 Rust Embedded で何が利用できるかを概観したいなら、Awesome Rust Embedded のリストを見てみてください。
- Embassy を見てみるのもよいでしょう。これは、Rust の
async/awaitを使った並行実行をサポートする、モダンで効率的な協調的マルチタスキング・フレームワークです。
- Real-Time Interrupt-driven Concurrency RTIC を見てみるのもよいでしょう。RTIC は、タスクの優先順位付けとデッドロックのない実行をサポートする、非常に効率的なプリエンプティブ・マルチタスキング・フレームワークです。
embedded-halプロジェクトのさらに多くの抽象化を調べてみたり、それをベースに独自のプラットフォーム非依存ドライバを書いてみたりするのもよいでしょう。
- 別の開発ボードで Rust を動かしてみるのもよいでしょう。ESP-32、Raspberry Pi、Arduino のような人気のボードには、それぞれ活発な Rust 開発者コミュニティがあります。