- RTOSはどのように機能しますか?
- RTOSで頻繁に使用される用語
- ArduinoFreeRTOSライブラリのインストール
- 回路図
- ArduinoFreeRTOSの例-ArduinoIDEでFreeRTOSタスクを作成する
- ArduinoIDEでのFreeRTOSタスクの実装
組み込みデバイス内に存在するOSは、RTOS(リアルタイムオペレーティングシステム)と呼ばれます。組み込みデバイスでは、タイミングが非常に重要な役割を果たすリアルタイムタスクが重要です。リアルタイムタスクは時間決定論的です。つまり、イベントへの応答時間は常に一定であるため、特定のイベントが一定の時間に発生することが保証されます。RTOSは、非常に正確なタイミングと高度な信頼性でアプリケーションを実行するように設計されています。RTOSは、シングルコアでのマルチタスクにも役立ちます。
RTOS、汎用OSとRTOSの違い、さまざまなタイプのRTOSなどについて詳しく知ることができる組み込みシステムでRTOSを使用する方法についてのチュートリアルについてはすでに説明しました。
このチュートリアルでは、FreeRTOSから始めます。FreeRTOSは、組み込みデバイス用のRTOSのクラスであり、8/16ビットマイクロコントローラーで実行するのに十分小さいですが、その使用はこれらのマイクロコントローラーに限定されません。これは完全にオープンソースであり、そのコードはgithubで入手できます。RTOSのいくつかの基本的な概念を知っている場合、FreeRTOSは、コーディングのバックエンド部分を知らなくてもコードで直接使用できる十分に文書化されたAPIを備えているため、非常に簡単に使用できます。完全なFreeRTOSドキュメントはここにあります。
FreeRTOSは8ビットMCUで実行できるため、ArduinoUnoボードでも実行できます。FreeRTOSライブラリをダウンロードしてから、APIを使用してコードの実装を開始する必要があります。このチュートリアルは完全な初心者を対象としています。以下のトピックは、このArduinoFreeRTOSチュートリアルでカバーします。
- RTOSのしくみ
- RTOSで頻繁に使用される用語
- ArduinoIDEへのFreeRTOSのインストール
- 例を使用してFreeRTOSタスクを作成する方法
RTOSはどのように機能しますか?
RTOSの動作を開始する前に、タスクとは何かを見てみましょう。タスクは、CPU上で実行するようにスケジュール可能なコードの一部です。したがって、何らかのタスクを実行する場合は、カーネル遅延または割り込みを使用してスケジュールする必要があります。この作業は、カーネルに存在するスケジューラーによって実行されます。シングルコアプロセッサでは、スケジューラは特定のタイムスライスでタスクを実行するのに役立ちますが、異なるタスクが同時に実行されているように見えます。すべてのタスクは、与えられた優先順位に従って実行されます。
ここで、1秒間隔でLEDが点滅するタスクを作成し、このタスクを最高の優先度に設定したい場合、RTOSカーネルで何が起こるかを見てみましょう。
LEDタスクとは別に、カーネルによって作成されるタスクがもう1つあります。これは、アイドルタスクと呼ばれます。。アイドルタスクは、実行可能なタスクがない場合に作成されます。このタスクは常に最低の優先度、つまり0の優先度で実行されます。上記のタイミンググラフを分析すると、実行はLEDタスクで開始され、指定された時間実行され、残りの時間、ティック割り込みが発生するまでアイドルタスクが実行されることがわかります。次に、カーネルは、タスクの優先度とLEDタスクの合計経過時間に従って、実行する必要のあるタスクを決定します。 1秒が完了すると、カーネルは、アイドルタスクよりも優先度が高いため、実行するLEDタスクを再度選択します。これは、LEDタスクがアイドルタスクをプリエンプトすると言うこともできます。同じ優先度のタスクが3つ以上ある場合、それらは指定された時間、ラウンドロビン方式で実行されます。
非実行タスクの実行状態への切り替えを示す状態図の下。
新しく作成されたすべてのタスクは、準備完了状態(実行されていない状態の一部)になります。作成されたタスク(Task1)の優先度が他のタスクよりも高い場合、実行状態に移行します。この実行中のタスクが他のタスクに取って代わった場合、再び準備完了状態に戻ります。それ以外の場合、タスク1がブロッキングAPIを使用してブロックされている場合、CPUは、ユーザーが定義したタイムアウトまでこのタスクを実行しません。
Task1がSuspendAPIを使用して実行状態で一時停止されている場合、Task1は一時停止状態になり、スケジューラーは再び使用できなくなります。Task1を一時停止状態で再開すると、ブロック図に示されているように、準備完了状態に戻ります。
これは、タスクがどのように実行され、状態を変更するかについての基本的な考え方です。このチュートリアルでは、FreeRTOSAPIを使用してArduinoUnoで2つのタスクを実装します。
RTOSで頻繁に使用される用語
1.タスク:これは、CPU上で実行するようにスケジュール可能なコードの一部です。
2.スケジューラー:準備完了状態リストから実行状態までタスクを選択する役割を果たします。スケジューラーは、多くの場合、(負荷分散のように)すべてのコンピューターリソースをビジー状態に保つように実装されます。
3.プリエンプション:これは、すでに実行中のタスクを一時的に中断して、協力せずに実行状態から削除することを目的とした行為です。
4.コンテキスト切り替え:優先度ベースのプリエンプションでは、スケジューラーは、すべての systick 割り込みで、実行中のタスクの優先度を準備完了タスクリストの優先度と比較します。リスト内に実行中のタスクよりも優先度が高いタスクがある場合、コンテキストスイッチが発生します。基本的に、このプロセスでは、さまざまなタスクの内容がそれぞれのスタックメモリに保存されます。
5.スケジューリングポリシーの種類:
- プリエンプティブスケジューリング:このタイプのスケジューリングでは、タスクは優先順位を考慮せずに等しいタイムスライスで実行されます。
- 優先度ベースのプリエンプティブ:優先度の高いタスクが最初に実行されます。
- 協調スケジューリング:コンテキストの切り替えは、実行中のタスクの協調によってのみ発生します。タスクは、タスクのyieldが呼び出されるまで継続的に実行されます。
6.カーネルオブジェクト: タスクに何らかの作業を実行するように通知するために、同期プロセスが使用されます。このプロセスを実行するには、カーネルオブジェクトを使用します。一部のカーネルオブジェクトには、イベント、セマフォ、キュー、ミューテックス、メールボックスなどがあります。これらのオブジェクトの使用方法については、今後のチュートリアルで説明します。
上記の議論から、RTOSの概念に関するいくつかの基本的なアイデアが得られ、ArduinoでFreeRTOSプロジェクトを実装できるようになりました。それでは、ArduinoIDEにFreeRTOSライブラリをインストールすることから始めましょう。
ArduinoFreeRTOSライブラリのインストール
1. Arduino IDEを開き、[ スケッチ]-> [ライブラリを含める]-> [ライブラリの管理]に 移動し ます 。FreeRTOSを検索し、以下に示すようにライブラリをインストールします。
githubからライブラリをダウンロードし、 [スケッチ]-> [ライブラリを含める]-> [。zip ファイルを 追加]で.zip ファイルを 追加 できます。
ここで、ArduinoIDEを再起動します。このライブラリは、以下に示すように、 [ファイル]-> [例]-> [FreeRTOS]に あるサンプルコードを提供します。
ここでは、動作を理解するためにコードを最初から作成します。後でサンプルコードを確認して使用できます。
回路図
以下は、ArduinoでFreeRTOSを使用してLEDの点滅タスクを作成するための回路図です。
ArduinoFreeRTOSの例-ArduinoIDEでFreeRTOSタスクを作成する
FreeRTOSプロジェクトを作成するための基本的な構造を見てみましょう。
1.まず、ArduinoFreeRTOSヘッダーファイルを次のようにインクルードします
#include
2.実行のために作成しているすべての関数の関数プロトタイプを次のように記述します。
void Task1(void * pvParameters); void Task2(void * pvParameters); .. …。
3.ここで、 void setup() 関数で、タスクを作成し、タスクスケジューラを起動します。
タスクを作成するために、 xTaskCreate() APIは、特定のパラメーター/引数を使用して セットアップ 関数で呼び出され ます 。
xTaskCreate(TaskFunction_t pvTaskCode、const char * const pcName、uint16_t usStackDepth、void * pvParameters、UBaseType_t uxPriority、TaskHandle_t * pxCreatedTask);
タスクの作成中に渡す必要のある引数は6つあります。これらの議論が何であるかを見てみましょう
- pvTaskCode:これは、タスクを実装する関数への単なるポインターです(実際には、関数の名前だけです)。
- pcName:タスクの説明的な名前。これはFreeRTOSでは使用されません。これは、純粋にデバッグ目的で含まれています。
- usStackDepth:各タスクには、タスクの作成時にカーネルによってタスクに割り当てられる独自のスタックがあります。この値は、バイト数ではなく、スタックが保持できるワード数を指定します。たとえば、スタックの幅が32ビットで、 usStackDepth が100として渡される場合、RAMに400バイトのスタックスペース(100 * 4バイト)が割り当てられます。Arduino Unoには2KバイトのRAMしかないため、これを賢く使用してください。
- pvParameters:タスク入力パラメーター(NULLにすることができます)。
- uxPriority:タスクの優先度(0が最低の優先度)。
- pxCreatedTask:作成中のタスクへのハンドルを渡すために使用できます。このハンドルを使用して、API呼び出しでタスクを参照できます。たとえば、タスクの優先度を変更したり、タスクを削除したりできます(NULLにすることができます)。
タスク作成の例
xTaskCreate(task1、 "task1"、128、NULL、1、NULL); xTaskCreate(task2、 "task2"、128、NULL、2、NULL);
ここでは、Task2の優先度が高いため、最初に実行されます。
4.タスクを作成した後、vTaskStartScheduler()を使用してvoidセットアップでスケジューラーを開始します。API。
5. 手動で無限にタスクを実行したくないため、 Void loop() 関数は空のままになります。タスクの実行がスケジューラによって処理されるようになったためです。
6.次に、タスク関数を実装し、これらの関数内で実行するロジックを作成する必要があります。関数名は、 xTaskCreate() APIの最初の引数と同じである必要があります。
void task1(void * pvParameters) { while(1){ …. //ロジック } }
7.ほとんどのコードは実行中のタスクを停止するためにdelay関数を必要としますが、RTOSではCPUを停止し、RTOSも動作を停止するため、 Delay() 関数の使用は推奨されていません。そのため、FreeRTOSには特定の時間タスクをブロックするカーネルAPIがあります。
vTaskDelay(const TickType_t xTicksToDelay);
このAPIは、遅延の目的で使用できます。このAPIは、指定されたティック数だけタスクを遅延させます。タスクがブロックされたままになる実際の時間は、ティックレートによって異なります。定数 portTICK_PERIOD_MS を使用して、ティックレートからリアルタイムを計算できます。
つまり、200ミリ秒の遅延が必要な場合は、この行を書き込むだけです。
vTaskDelay(200 / portTICK_PERIOD_MS);
したがって、このチュートリアルでは、これらのFreeRTOSAPIを使用して3つのタスクを実装します。
使用するAPI:
- xTaskCreate();
- vTaskStartScheduler();
- vTaskDelay();
このチュートリアル用に作成するタスク:
- デジタルピン8でLEDが200msの周波数で点滅
- 300msの周波数でデジタルピン7でLEDが点滅
- 500msの周波数でシリアルモニターに番号を印刷します。
ArduinoIDEでのFreeRTOSタスクの実装
1.上記の基本構造の説明から、ArduinoFreeRTOSヘッダーファイルをインクルードします。次に、関数プロトタイプを作成します。3つのタスクがあるので、3つの関数とそのプロトタイプを作成します。
#include void TaskBlink1(void * pvParameters); void TaskBlink2(void * pvParameters); void Taskprint(void * pvParameters);
2. void setup() 関数で、シリアル通信を9600ビット/秒で初期化し、 xTaskCreate() APIを使用して3つのタスクすべてを作成します。最初に、すべてのタスクの優先順位を「1」にして、スケジューラーを開始します。
void setup(){ Serial.begin(9600); xTaskCreate(TaskBlink1、 "Task1"、128、NULL、1、NULL); xTaskCreate(TaskBlink2、 "Task2"、128、NULL、1、NULL); xTaskCreate(Taskprint、 "Task3"、128、NULL、1、NULL); vTaskStartScheduler(); }
3.次に、task1のLED点滅について、以下に示す3つの機能すべてを実装します。
void TaskBlink1(void * pvParameters) { pinMode(8、OUTPUT); while(1) { digitalWrite(8、HIGH); vTaskDelay(200 / portTICK_PERIOD_MS); digitalWrite(8、LOW); vTaskDelay(200 / portTICK_PERIOD_MS); } }
同様に、TaskBlink2関数を実装します。Task3関数は次のように記述されます
void Taskprint(void * pvParameters) { int counter = 0; while(1) { カウンター++; Serial.println(counter); vTaskDelay(500 / portTICK_PERIOD_MS); } }
それでおしまい。ArduinoUnoのFreeRTOSArduinoプロジェクトが正常に完了しました。このチュートリアルの最後に、完全なコードとビデオがあります。
最後に、デジタルピン7と8に2つのLEDを接続し、コードをArduinoボードにアップロードして、シリアルモニターを開きます。以下に示すように、タスク名で500msに1回カウンターが実行されていることがわかります。
また、LEDを観察してください。LEDは異なる時間間隔で点滅しています。 xTaskCreate 関数のpriority引数を試してみてください。番号を変更し、シリアルモニターとLEDの動作を観察します。
これで、アナログ読み取りタスクとデジタル読み取りタスクが作成される最初の2つのサンプルコードを理解できます。このようにして、ArduinoUnoとFreeRTOSAPIだけを使用してより高度なプロジェクトを作成できます。