あなたが探索するために残されているもの
私たちはまだ表面を少しかじったにすぎません! あなたが探索できることは、まだたくさん残っています。
NOTE: これを読んでいて、以下の項目や、その他の関連する組み込みトピックについて、Discovery book に例や演習を追加するのを手伝いたいと思っているなら、ぜひ力を貸してください!
手伝いたいけれど、この本への貢献方法について支援やメンタリングが必要な場合は、open an issue してください。あるいは、情報を追加する Pull Request を送ってください!
組み込みソフトウェアに関するトピック
これらのトピックでは、組み込みソフトウェアを書くための戦略について議論します。多くの問題は異なる方法で解決できますが、これらのセクションでは、いくつかの戦略と、それらを使うことに意味がある場合(または意味がない場合)について説明します。
マルチタスク
これまでのすべてのプログラムは単一のタスクを実行してきました。OS がなく、そのためスレッドもないシステムで、どうすればマルチタスクを実現できるでしょうか。マルチタスクには主に 2 つのアプローチがあります。プリエンプティブ・マルチタスクと協調的マルチタスクです。
プリエンプティブ・マルチタスクでは、現在実行中のタスクは、どの時点であっても別のタスクによって preempted(割り込み)される可能性があります。プリエンプションが起こると、最初のタスクは中断され、代わりにプロセッサが 2 つ目のタスクを実行します。やがて最初のタスクは再開されます。マイクロコントローラは、interrupts の形でプリエンプションのためのハードウェアサポートを提供します。
協調的マルチタスクでは、実行中のタスクは suspension point に到達するまで動作し続けます。プロセッサがそのサスペンションポイントに到達すると、現在のタスクの実行を停止し、代わりに別のタスクを実行します。やがて最初のタスクは再開されます。これら 2 つのマルチタスク方式の主な違いは、協調的マルチタスクでは、実行中のどの時点でも強制的にプリエンプトされるのではなく、known なサスペンションポイントで実行制御を yields することです。
スリープ
これまでのすべてのプログラムでは、何か実行すべきことがあるかどうかを確認するために、周辺機器を継続的にポーリングしてきました。しかし、ときには何もすることがない場合もあります! そのようなとき、マイクロコントローラは「スリープ」するべきです。
プロセッサがスリープすると、命令の実行を停止するため、電力を節約できます。
電力を節約するのはほとんど常に良い考えなので、マイクロコントローラは可能な限り多くの時間をスリープしているべきです。では、何らかの動作を実行するためにいつ起きる必要があるのかを、どのように知るのでしょうか? 「割り込み」はマイクロコントローラを起こすイベントの 1 つですが、ほかにもあり、wfi と wfe はプロセッサを「スリープ」させる命令です。
マイクロコントローラの機能に関連するトピック
マイクロコントローラ(私たちの STM32F3 のようなもの)には、多くの異なる機能があります。しかし、それらの多くは、さまざまな問題の解決に使える類似した機能を共有しています。
これらのトピックでは、そのような機能のいくつかと、それらを組み込み開発で効果的に使う方法について説明します。
Direct Memory Access (DMA).
この周辺機器は、ある種の asynchronous memcpy です。これまでのプログラムでは、UART や I2C のような周辺機器に、1 バイトずつデータを送り込んできました。この DMA 周辺機器は、データの一括転送を行うために使用できます。RAM から RAM、UART のような周辺機器から RAM、あるいは RAM から周辺機器へも可能です。たとえば、USART1 からこのバッファへ 256 バイト読み込む、といった DMA 転送をスケジュールし、それをバックグラウンドで実行させておき、進行中にほかの作業を行いながら、何らかのレジスタをポーリングして完了したかどうかを確認できます。
割り込み
現実世界と相互作用するためには、ある種のイベントが発生したときに、マイクロコントローラが immediately 応答する必要があることがよくあります。
マイクロコントローラには割り込みを受ける能力があります。つまり、ある特定のイベントが発生すると、その時点で行っていることを止めて、代わりにそのイベントに応答します。これは、ボタンが押されたときにモーターを停止したり、タイマーのカウントダウンが終了したときにセンサーを測定したりしたい場合に、非常に有用です。
これらの割り込みは非常に便利である一方で、適切に扱うのは少し難しいこともあります。私たちはイベントにすばやく応答したいですが、同時にほかの作業も継続できるようにしたいのです。
Rust では、割り込みをデスクトップ Rust プログラムにおけるスレッドの概念に似たものとしてモデル化します。つまり、メインアプリケーションと、割り込みイベントの処理の一部として実行されるコードとの間でデータを共有する際には、Rust の Send と Sync の概念についても考えなければなりません。
パルス幅変調 (PWM)
一言で言えば、PWM とは、何かを周期的にオンにしてからオフにすることを繰り返しつつ、「オンの時間」と「オフの時間」の間にある割合(「デューティサイクル」)を保つことです。十分に高い周波数で LED に対してこれを使うと、LED を暗くできます。低いデューティサイクル、たとえばオン時間が 10% でオフ時間が 90% なら LED は非常に暗くなり、高いデューティサイクル、たとえばオン時間が 90% でオフ時間が 10% なら、LED はずっと明るくなります(ほぼ完全に給電されているかのように見えます)。
一般に、PWM は、ある電気機器にどれだけの power を与えるかを制御するために使用できます。マイクロコントローラと電動モーターの間に適切な(電力)電子回路があれば、PWM を使ってモーターに与える電力の量を制御できるため、トルクや速度を制御するのに使えます。さらに角度位置センサーを追加すれば、異なる負荷条件でもモーターの位置を制御できる閉ループコントローラが手に入ります。
デジタル入力
これまで私たちは、LED を駆動するためにマイクロコントローラのピンをデジタル出力として使ってきました。しかし、これらのピンはデジタル入力として設定することもできます。デジタル入力として使うと、これらのピンはスイッチ(オン/オフ)やボタン(押されている/押されていない)の 2 値状態を読み取れます。
(spoilers スイッチ / ボタンの 2 値状態を読み取るのは、聞こえるほど単純ではありません ;-)
Analog-to-Digital Converters (ADC)
世の中にはたくさんのデジタルセンサーがあります。I2C や SPI のようなプロトコルを使ってそれらを読み取れます。しかし、アナログセンサーも存在します! これらのセンサーは、検出している物理量の大きさに比例した電圧レベルを出力するだけです。
ADC 周辺機器は、その「アナログ」電圧レベル、たとえば 1.25 ボルトを、プロセッサが計算に使用できる [0, 65535] の範囲の「デジタル」な数値へ変換するために使用できます。
Digital-to-Analog Converters (DAC)
予想どおり、DAC は ADC のちょうど逆です。レジスタに何らかのデジタル値を書き込むことで、ある「アナログ」ピンに [0, 3.3V] の範囲の電圧を生成できます(3.3V 電源を前提とする場合)。このアナログピンが適切な電子回路に接続され、そのレジスタに適切な値が一定の高速なレート(周波数)で書き込まれると、音や、さらには音楽まで生成できます!
Real Time Clock (RTC)
この周辺機器は、「人間向けの形式」で時間を追跡するために使用できます。秒、分、時間、日、月、年です。この周辺機器は、「ティック」をこうした人にわかりやすい時間単位へ変換する処理を担います。うるう年や夏時間まで処理してくれます!
その他の通信プロトコル
SPI, I2S, SMBUS, CAN, IrDA, Ethernet, USB, Bluetooth, etc. さまざまなアプリケーションは、さまざまな通信プロトコルを使用します。ユーザー向けの アプリケーションには通常 USB コネクタがあります。USB は PC やスマートフォンで広く普及した プロトコルだからです。一方、車内では多数の CAN 「バス」が使われています。デジタルセンサーの中には SPI を使うものもあれば、I2C を使うもの、 さらに SMBUS を使うものもあります。
一般的な組み込み関連トピック
これらのトピックでは、私たちのデバイスや、その搭載ハードウェアに固有ではない項目を扱います。 その代わりに、組み込みシステムで利用できる有用な技術について説明します。
ジャイロスコープ
Punch-o-meter 演習の一環として、私たちは加速度計を使って 3 次元の加速度変化を測定しました。 このボードにはジャイロスコープと呼ばれるセンサーも搭載されており、これによって 3 次元の 「回転」の変化を測定できます。
これは、たとえば転倒を避けたいロボットのような特定のシステムを構築しようとする際に非常に 役立ちます。さらに、ジャイロスコープのようなセンサーから得られるデータは、Sensor Fusion と呼ばれる技術を使って加速度計のデータと組み合わせることもできます(詳細は以下を参照)。
サーボモーターとステッピングモーター
一部のモーターは、たとえばラジコンカーを前進または後退させるように、主に一方向または 反対方向に回転させるためだけに使われますが、モーターがどのように回転するかを、より正確に 測定することが役立つ場合もあります。
私たちのマイクロコントローラーはサーボモーターやステッピングモーターを駆動でき、これにより モーターが何回転したかをより正確に制御したり、さらにはモーターを特定の位置に配置したりする こともできます。たとえば、時計の針を特定の方向へ動かしたい場合などです。
センサーフュージョン
STM32F3DISCOVERY には 3 つのモーションセンサーが搭載されています。加速度計、 ジャイロスコープ、磁力計です。これらは単体では、それぞれ(固有)加速度、角速度、 (地球の)磁場を測定します。しかし、これらの物理量を「融合」することで、より有用なもの、 つまりボードの向きの「ロバスト」な測定値を得ることができます。ここでロバストとは、単一の センサーだけで可能な場合よりも測定誤差が少ないことを意味します。
このように、異なる情報源からより信頼性の高いデータを導き出す考え方は、 センサーフュージョンとして知られています。
では、次は何をすればよいでしょうか? いくつかの選択肢があります。
f3ボードサポート crate のサンプルを見てみることができます。これらのサンプルはすべて、 手元の STM32F3DISCOVERY ボードで動作します。
- このモーションセンサーのデモを試してみることができます。実装の詳細と ソースコードは、このブログ記事で公開されています。
- Real Time for The Masses を見てみることもできます。これは、タスクの優先順位付けと デッドロックのない実行をサポートする、非常に効率的なプリエンプティブ マルチタスクフレームワークです。
- Rust を別の開発ボードで動かしてみることもできます。始める最も簡単な方法は、
cortex-m-quickstartCargo プロジェクトテンプレートを使うことです。
- Rust の型システムが I/O 設定のバグをどのように防げるかを説明した このブログ記事を見てみることもできます。
- Rust による組み込み開発に関する雑多なトピックについて、私の blog を見てみることもできます。
- すべてのマイクロコントローラーで一般的に見られる組み込み I/O 機能のための抽象化(トレイト)を
構築することを目指す
embedded-halプロジェクトを見てみることもできます。
- Weekly driver initiative に参加して、
embedded-halトレイトの上に構築され、 あらゆる種類のプラットフォーム(ARM Cortex-M、AVR、MSP430、RISCV など)で動作する 汎用ドライバーの作成を手伝うこともできます。