2008年11月27日木曜日

my Arduino OS計画 #2

今、手に入れているAVRマイコンはArduinoと同じATmega168ではなく、ROM容量が半分の8kByteになったATmega88というマイコンです。メモリ容量以外はほぼコンパチですので、これに入れられればATmega168にもスムーズに入ることになります。
なぜ、ATmega88なのかというと、秋月電子で購入できたのがこれだけだったから、というそれだけの理由です。ちなみにクロックは20MHzにしてしまっていますが、Arduinoは16MHzでした。これはチェックし忘れたからです。CPUクロックの違いは主にタイマやUARTなどに影響が出ますが、これは#defineでクリアしようと思っています。

さて、今回はArduinoに入れるOSの基本設計思想(アーキテクチャ)を記したいと思います。このAVRマイコンのメモリリソースはとても十分とは言えないので、ある程度機能を割り切った設計が必要だと考えました。
Overviewは以下の感じです。
・タスク優先度のない疑似マルチタスク(ノンプリエンプティブ)
・多重割込はしない
・リアルタイム性は若干損なわれるが、事象発生順は保たれる
・タスク間のやりとりはメッセージによって通知する(メッセージドリブン)

擬似マルチタスク(ノンプリエンプティブ)とは、複数のタスクを定義することは出来るが、実行中のタスクからOSがタスク優先度的に(あるいは定期的に)CPUリソースを剥奪することはせずに、実行中のタスクが自発的にCPUを解放する、という方式です。
また、タスク優先度という概念も省いて、シンプルな設計にします。

多重割込とは、ある割込ハンドラの実行中に他の優先度の高い割込ハンドラの動作を許可する機能ですが、これも省いて、ある割込ハンドラは最後まで実行させてしまいます。基本的に割込ハンドラの処理はなるべく早く終わらせ、タスク側に複雑な処理を実行させるようにすれば、意外に狙い通りに動作するものです。また、多重割込にしなければ、割込ハンドラが使用するスタック容量も少なくなり、見積もりもし易くなるメリットがあります。さらに、事象発生順も保証することが出来ます。

リアルタイム性とは、ある処理イベントが発生してから、十分許容出来る時間内に必要な処理を実行できる、というものです。例えば、車のアンチロックブレーキシステムの場合は、タイヤがロックしてから数十msecでポンピングブレーキングを実行できなければ、重大な事故に繋がることになります。この許容時間内に処理を実行できる保証がリアルタイム性です。今回は擬似マルチタスクであることからも、タスクがCPUを解放するまで次のタスクには回ってきませんので、実装次第では、全然リアルタイム性が損なわれる可能性がありますが、そこはそれを意識して実装すれば、そこそこのリアルタイム性は保持できます。また、事象(イベント)発生順を保持する仕組みとしては、イベント(タイマ、AD変換、端子状態変化などの外部イベントや、あるタスクが他タスクに通知する内部イベント)をタスクに通知する際、共用のFIFOにその通知を入れていく仕組みにすることで、発生順番が保証されるようにします。

メッセージドリブンとは、タスク間の通知の方式としてメッセージという一意に決まった形をとることにより、タスク処理を起動する方式です。マルチタスクではタスク間通知の方式は、イベントフラグやセマフォ、メッセージプールなどを使うことが通例です。今回のOSではメッセージプールをFIFOで制御することにします。このようなアーキテクチャによって、タスクの構造は次のようになるはずです。

 1.メッセージを待つ。
 2.メッセージを処理する。必要なら他タスクにメッセージを発行する。
 3.上記1.に戻る。

このデザインパターンにより、タスク設計が見た目にもわかりやすく、バグが発生する可能性を下げるメリットがあります。
タスク優先度のない擬似マルチタスクを採用するので、タスク切り替えはタスクが次のメッセージを待つ時に発生します。

μitronなどのプリエンプティブなOSを利用する場合は、シンプルとは言え、それなりのメモリリソースが必要となりますが、今回のOSのようなアーキテクチャにすることで、メモリリソースはそんなに心配しなくて済みます。実際、基本的なメッセージFIFOによるタスク切替の実装は、ROMが8kByteの内5%程度、RAMが1kByteの内10数%で済む(FIFOの段数に依存)ことになりそうです。また、タスクスイッチの時間も、シンプルな設計なので、μitronに比べてかなり高速になります。

次回は、このアーキテクチャの実装を具体的に記したいと思います。

0 件のコメント: