リアルタイムオペレーティングシステム(RTOS)とそのアプリケーション
DigiKeyの北米担当編集者の提供
2021-02-25
RTOSとは
リアルタイムオペレーティングシステム(RTOS)は、組み込みシステムで一般的なリソースと時間に制約のある設計において、マルチタスキングやタスク統合を容易にするために使用される軽量OSです。その上、「リアルタイム」という用語は、生の速度ではなく、実行時間の予測可能性/決定論性を示しています。したがって、RTOSは通常、その決定論性によって厳しいリアルタイム要件を満たすことを実証できます。
RTOSの主な概念は、以下の通りです。
タスク
タスク(プロセス/スレッドと呼ばれることもある)は、無限ループで動作する独立した関数で、通常はそれぞれが1つの機能を担当します。タスクは、独自の時間(時間的分離)とメモリスタック(空間的分離)で個別に動作しています。ハードウェアのメモリ保護ユニット(MPU)を使用することで、タスク間の空間的分離を保証することができます。これにより、アクセス可能なメモリ領域を制限し、アクセス違反時にフォールト例外を発生させます。通常、内部ペリフェラルはメモリマップされているため、MPUを使用してペリフェラルへのアクセスを制限することもできます。
タスクには、以下のようなさまざまな状態があります。
- ブロック状態 – タスクがイベント(遅延タイムアウト、データ/リソースの可用性など)を待っています
- 実行可能状態 – タスクはCPU上で実行可能ですが、CPUが別のタスクによって使用されているため、実行されていません
- 実行状態 – タスクがCPU上で実行されるように割り当てられています
スケジューラ
RTOSのスケジューラはCPU上でどのタスクを実行するかを制御し、さまざまなスケジューリングアルゴリズムが利用可能です。通常は、以下のアルゴリズムが使用されます。
- プリエンプティブ – 優先度の高い別のタスクが準備できている場合、タスクの実行が中断される可能性があります
- 協調的 – タスクの切り替えは、現在実行中のタスクが自ら停止する場合にのみ行われます
プリエンプティブスケジューリングにより、優先度の高いタスクはリアルタイムの制約を満たすために下位のタスクに割り込むことができますが、コンテキスト切り替えのオーバーヘッドが多くなってしまいます。
タスク間通信(ITC)
通常、複数のタスクは相互に情報やイベントを共有する必要があります。最も単純な共有方法は、RAM内の共有グローバル変数を直接読み取り/書き込みすることですが、競合状態によるデータ破損のリスクがあるため望ましくありません。より良い方法は、セッター関数およびゲッター関数でアクセス可能なファイルスコープの静的変数を読み取り/書き込みすることであり、割り込みを無効にするか、セッター/ゲッター関数内で相互排除オブジェクト(ミューテックス)を使用することで、競合状態を防ぐことができます。よりクリーンな方法は、メッセージキューのようなスレッドセーフなRTOSオブジェクトを使用して、タスク間で情報を渡すことです。
情報の共有以外にも、RTOSオブジェクトの可用性を待つためにタスクをブロックできるため、RTOSオブジェクトはタスクの実行を同期させることもできます。ほとんどのRTOSには、以下のようなオブジェクトがあります。
- メッセージキュー
- データを渡すための先入れ先出し(FIFO)キュー
- データは、コピーまたは参照(ポインタ)で送信することができます
- タスク間、または割り込みとタスクの間でデータを送信するために使用します
- セマフォ
- 特定のリソースの可用性を記録するための参照カウンタとして扱うことができます
- バイナリセマフォまたはカウントセマフォになります
- リソースの使用を保護したり、タスクの実行を同期させたりするために使用します
- ミューテックス
- バイナリセマフォに似ていて、一般的に単一リソースの使用を保護するために使用されます(相互排他)
- FreeRTOSのミューテックスは、優先順位の逆転(優先度の高いタスクが優先度の低いタスクを待っている状態)を回避するために、優先度継承メカニズムを備えています。
- メールボックス
- 単一の変数を共有するためのシンプルな格納先
- 単一要素のキューとみなすことができます
- イベントグループ
- 条件のグループ(セマフォ、キュー、イベントフラグの可用性など)
- タスクをブロックすることができ、特定の組み合わせ条件が満たされるのを待つことができます
- ZephyrではポーリングAPIとして、FreeRTOSではQueueSetとして利用可能
システムティック
RTOSは通常、定期的なハードウェアタイマ割り込みでインクリメントされたシステムティックカウンタ変数の形で、時間を測定するためのタイムベースを必要とします。アプリケーションはシステムティックにより、単一のハードウェアタイマを使用して、時間ベースの複数のサービス(タスクの実行間隔、待機タイムアウト、タイムスライシング)を維持することができます。ただし、ティックレートを高くしてもRTOSのタイムベースの解像度が上がるだけで、ソフトウェアの動作が速くなるわけではありません。
RTOSを使用する理由
組織化
アプリケーションは常にベアメタルの方法で書くことができますが、コードの複雑さが増すにつれて、ある種の構造を持つことは、アプリケーションの異なる部分を管理し、それらを分離したままにしておくのに役立ちます。さらに、構造化された開発方法と慣れ親しんだデザイン言語により、新しいチームメンバーはコードを理解し、より早く貢献し始めることができます。RFCOM Technologiesは、Texas InstrumentsのHercules、RenesasのRL78とRX、およびSTMicroelectronicsのSTM32などのさまざまなマイクロコントローラを使用して、異なるRTOS上でアプリケーションを開発してきました。設計パターンが似ているため、異なるマイクロコントローラや異なるRTOS上でアプリケーションを開発することができます。
モジュール性
分割により克服します。新しい機能がCPUやペリフェラルなどの共有リソースをオーバーロードしない場合、機能を異なるタスクに分けることで、他の機能を壊すことなく、新しい機能を簡単に追加することができます。通常、RTOSなしの開発は、すべての機能がループの一部である大きな無限ループの中で行われます。ループ内の任意の機能を変更すると、他の機能に影響を与え、ソフトウェアの変更や維持が困難になります。
通信スタックとドライバ
TCP/IP、USB、BLEスタック、グラフィックスライブラリといった多くの追加ドライバやスタックは、既存RTOSのために開発されたり、既存RTOSへ移植されたりします。アプリケーション開発者は、ソフトウェアのアプリケーション層に集中することができ、市場投入までの時間を大幅に短縮することができます。
チップ
静的割り当て
RTOSオブジェクトにメモリの静的割り当てを使用することは、コンパイル時に各RTOSオブジェクトに対してRAMのメモリスタックを予約することを意味します。freeRTOSにおける静的割り当て関数の例としては、xTaskCreateStatic()が挙げられます。これにより、RTOSオブジェクトを正常に作成することができ、失敗した可能性のある割り当てを処理する手間を省いて、アプリケーションをより決定論的なものにすることができます。
タスクに必要なスタックサイズの決定に関しては、タスクをより大きな(十分以上の)スタックサイズで実行し、実行時にスタック使用量をチェックして最高水位標を決めることができます。また、静的スタック解析ツールも利用できます。
オペレーティングシステム抽象化レイヤ(OSAL)と意味のある抽象化
ハードウェア抽象化レイヤ(HAL)と同様に、RTOS抽象化レイヤを使用することで、アプリケーションソフトウェアを他のRTOSに簡単に移行させることができます。RTOSの機能はかなり似ているため、OSALの作成はそれほど複雑ではないはずです。以下にその例を挙げます。
freeRTOS APIを直接使用します。
if( xSemaphoreTake( spiMutex, ( TickType_t ) 10 ) == pdTRUE ) { //dosomething }
RTOS APIをOSALにラッピングします。
if( osalSemTake( spiMutex, 10 ) == true) { //dosomething }
タスク間通信の抽象化レイヤを使用して、コードをより読みやすくし、RTOSオブジェクトの範囲を最小化します。
if( isSpiReadyWithinMs( 10 ) ) { //doSomething }
さらに、利用可能なSPIモジュールが複数ある場合、プログラマは抽象化により、その下で使用されるRTOSオブジェクトを変更(例:ミューテックスからカウントセマフォへ)することもできます。OSALや他の抽象化レイヤは、ユニットテスト時のモック関数の挿入を簡素化することで、ソフトウェアテストにも役立ちます。
ティック間隔の選択
オーバーヘッドが少ないため、ティックレートが低いほうが理想的です。適切なティックレートを選択するために、開発者はアプリケーション内のモジュールのタイミング制約(リピート間隔、タイムアウト期間など)をリストダウンすることができます。小さな間隔を必要とする外れ値モジュールがある場合は、RTOSのティックレートを上げるよりも、外れ値モジュールに専用のタイマ割り込みを持たせることを検討することができます。高周波機能が非常に短い場合(例:LEDをオン/オフするためのレジスタへの書き込み)は、割り込みサービスルーチン(ISR)内で行うことができます。そうでない場合は、延期割り込み処理を使用することができます。延期割り込み処理は、割り込み計算をRTOSタスクに延期する技術です。ISRはRTOSオブジェクトを介してイベントを生成するだけで、RTOSタスクはイベントによってブロック解除されて計算を行います。
低電力アプリケーション向けのティック抑制
システムがより長い期間アイドル状態になっている場合、ティックレスアイドルはティック割り込みを無効にします。組込みファームウェアが消費電力を削減するための重要な方法の1つは、システムをできるだけ長く低電力モードにすることです。ティックレスアイドルは、定期的なティック割り込みを無効にしてから、ブロック状態のタスクが実行される時にカウントダウンタイマを設定して割り込みをかけることで実装されます。タイムアウト待ちのタスクがない場合は、別の割り込みが発生する(例:ボタンが押される)まで、ティック割り込みを無期限で無効にすることができます。たとえば、Bluetooth Low Energy(BLE)ビーコンの場合、広告間隔の間にMCUをディープスリープ状態にすることができます。図1に示すように、ビーコンはほとんどの時間ディープスリープモードに入り、消費電力は数十μAです。
結論
RTOSは、スケジューラ、タスク、タスク間通信RTOSオブジェクト、さらには通信スタックやドライバなどの機能を提供します。これにより、開発者は組み込みソフトウェアのアプリケーション層に集中し、簡単かつ迅速にマルチタスキングソフトウェアを設計することができます。しかし、その他のツールと同様に、より多くの価値を引き出すためには、適切な使い方をしなければなりません。安全、確実、効率的な組み込みソフトウェアを作成するために、開発者はRTOSの機能を使用するタイミングとRTOSの設定方法を知っておく必要があります。
免責条項:このウェブサイト上で、さまざまな著者および/またはフォーラム参加者によって表明された意見、信念や視点は、DigiKeyの意見、信念および視点またはDigiKeyの公式な方針を必ずしも反映するものではありません。


