こんにちは。 短い一連の投稿で、マイクロコントローラ用の最も人気のある開発中のRTOSの1つであるFreeRTOSとの連携の可能性とアプローチについて説明します。 読者がマルチタスクの理論に精通していることを前提としています。これは、Habréまたは他の場所の近隣の投稿の1つで読むことができます。
他の部分へのリンク:
FreeRTOS:プロセス間通信。
FreeRTOS:ミューテックスとクリティカルセクション。
なんでこんなこと? または、FreeRTOSの作成者によるマルチタスクシステムの紹介。
従来、マルチタスクには2つのバージョンがあります。
- ソフトリアルタイム
- ハードリアルタイム
ソフトコンピューターには、コンピューターが含まれます。 ユーザーは、たとえば、記号の付いたボタンをクリックすると、入力された文字が表示されますが、ボタンを押してもしばらく反応が見られない場合、OSはタスクが「応答していない」と見なします(Windowsと同様に、「プログラムは「)と答えますが、OSは引き続き使用可能です。 したがって、ソフトタイムRTOSは単純に推定応答時間を決定し、期限切れになると、OSはタスクを応答なしとして分類します。
ハードタイプのRTOSには、組み込みデバイスにRTOSが含まれます。 いくつかの点で、それらはデストップのRTOS(1つのプロセッサでのマルチスレッド実行)に似ていますが、主な違いもあります -各タスクは割り当てられたタイムクォンタムで完了する必要があります。この条件を満たさないと、すべてのシステムが崩壊します。
しかし、なぜですか?
一連のセンサー間のデータ交換を同期するための非自明なロジックを備えたデバイスがあり、本当に応答時間を保証する必要がある場合、最後にシステムが成長する可能性があるが、その量がわからない場合は、RTOSを選択します。
RTOSの適用にRTOSを使用しないでください。 些細なタスクでRTOSを使用する必要はありません(1つのセンサーからデータを取得し、さらに送信し、1ボタンを押すなどの処理を行います)。 これは、結果のコードと問題自体の解決策の両方の不必要な冗長性につながります。
タスク(またはタスク、プロセス)を操作します。
最初に、さらなる考慮事項を明確にするためにいくつかの定義を示します。
「 リアルタイムオペレーティングシステム (RTOS)は、タイムクリティカルなリアルタイムシステムのリソースへのインターフェイスを提供するように設計されています。このようなシステムの主なタスクは、データ処理の適時性です。」
「 FreeRTOSは、組み込みシステム向けのマルチタスクリアルタイムオペレーティングシステム(RTOS)です。複数のマイクロプロセッサアーキテクチャに移植されています。
andrewsh habrayuzerから、ライセンスに関して:OSがそれにリンクしているという事実にもかかわらず、FreeRTOSを使用するアプリケーションのテキストを公開しないことが許可されています。 RTOS自体のソースコードは常に適用する必要があり、それに加えられた変更も適用する必要があります。
FreeRTOSは、少量のアセンブラコード(コンテキストスイッチングロジック)を使用してCで記述され、そのコアは3つのCファイルのみで表されます。 サポートされているプラットフォームの詳細については、 公式Webサイトをご覧ください 。
ビジネスに取り掛かろう。
すべてのタスクは、次のプロトタイプを持つC関数です。
void vTask( void *pvParametres );
各タスクは、本質的に独自のエントリポイントを持つミニサブプログラムであり、無限ループ内で実行され、通常は終了しないはずであり、独自のスタックも持っています。 1つのタスク定義を使用して、独立して実行され、独自のスタックを持つ複数のタスクを作成できます。
タスクの本文に明示的な戻り値を含めることはできません。 そして、タスクが不要になった場合は、関数APIを呼び出すことで削除できます。 次のリストは、典型的なタスクスケルトンを示しています。
void vTask( void *pvParametres) { /* , . someVar. , . */ int someVar; // - , . for( ;; ) { // } // , , . // vTaskDelete , . // NULL, vTaskDelete( NULL ); }
タスクを作成してスケジューラに追加するには、次のプロトタイプで特別なAPI関数を使用します。
portBASE_TYPE xTaskCreate( pdTASK_CODE pvTaskCode, const signed portCHAR * const pcName, unsigned portSHORT usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask );
pvTaskCode-タスクは単なるC関数であるため、その値は最初のパラメーターです。
pcNameはタスクの名前です。 実際、これはどこでも使用されておらず、IDEの適切なプラグインを使用してデバッグする場合にのみ役立ちます。
usStackDepth-各タスクは独自のスタックを持つミニルーチンであるため、このパラメーターはその深さを決定します。 RTOSをダウンロードし、プラットフォームにシステムを展開するとき、OS自体の動作を構成できる設定により、FreeRTOSConfig.hファイルを取得します。 このファイルは、定数値configMINIMAL_STACK_SIZEも宣言しました。これは、必要に応じて、対応する要素とともにusStackDepthとして渡す必要があります。
pvParameters-作成されると、各タスクは、いくつかのパラメーター、値、またはタスク自体の内部で必要になる可能性のある何かを取ることができます。 カプセル化の観点から見ると、このアプローチは最も安全であり、たとえば、何らかの構造を渡す価値があります。pvParametersとして何も渡す必要がない場合はNULLを渡す価値があります。
uxPriority-各タスクには、0(最小)から( configMAX_PRIORITIES -1)までの独自の優先度があります。 実際、この値には上限がないため、このロジックに追加のRAMが消費されないように、できるだけ少ない値を使用することをお勧めします。
pxCreatedTask-作成されたタスクのハンドル。 タスクを作成するときに、オプションで、将来のタスクのハンドルへのポインターを渡して、タスク自体の後続の制御を行うことができます。 たとえば、特定のタスクを削除します。
この関数は、タスクが正常に作成された場合はpdTRUEを返し、スタックサイズが大きすぎると指定された場合はerrCOULD_NOT_ALLOCATE_REQUIRED_MEMORYを返します。 タスクスタックとタスク自体を格納するのに十分なヒープがありません。
次のリストでは、2つのタスクを作成し、それぞれがLEDを点滅させる完成したプログラムの短い例を示しました。
void vGreenBlinkTask( void *pvParametrs ) { for( ;; ) { P8OUT ^= BIT7; // 700 FreeRTOS . FreeRTOSConfig.h 1. vTaskDelay( 700 ); } } void vRedBlinkTask( void *pvParametrs ) { for( ;; ) { P8OUT ^= BIT6; // 1000 FreeRTOS . FreeRTOSConfig.h 1. vTaskDelay( 1000 ); } } void main(void) { // . . vInitSystem(); // . , ! xTaskCreate( &vGreenBlinkTask, (signed char *)"GreenBlink", configMINIMAL_STACK_SIZE, NULL, 1, NULL ); xTaskCreate( &vRedBlinkTask, (signed char *)"RedBlink", configMINIMAL_STACK_SIZE, NULL, 1, NULL ); // . . vTaskStartScheduler(); // , . // . for( ;; ) { } }
次の投稿では、タスク間の相互作用と割り込みの処理について書きます。