Top -> FreeRtos -> designtips2.html
ソリューション # 2
完全にプリエンティブなシステム
<<< | >>>      
概 要
これは伝統的なプリエンプティブ多重タスクソリューションです。 これはメモリとプロセッサのオーバーヘッドに関係なく、RTOSのサービスをフルに活用できます。自立した必要機能に単純化した多数のタスクに分割する。
実 装
システムの一部分として、単独であるいは特定のタイミング条件を持つ個別のタスクが作成される。

        ソリューション # 2機能タスクと優先度

処理が必要なイベントが発生するまで、タスクはブロック状態にある。 イベントは外部装置(キーが押される等)あるいは内部(タイマが時間)がある。
タイミング必要条件に応じて優先度タスクに割り当てられる。
タイミング必要条件がより厳しいタスクはより優先度を高くする。
オペレーションのコンセプト
RTOSは実行可能な(ブロックされていない)最高優先度タスクがプロセッサ時間を得るように保証する。 もしより高い優先度タスクが実行可能になったなら、カーネルは直ちに実行中のタスクを中止する。

このスケジューリングはアプリケーションソースコードの中の構成やコマンドで明示的に記述されず、自動的に起こります。 しかしながら、タスクの適切な優先度の割り当てはアプリケーションデザイナーの責任です。

実行可能がタスクがないとき、アイドル・タスクが実行する。 アイドル・タスクはプロセッサをパワーセーブモードへ移行オプションを置きます。
スケジューラ・コンフィギュレーション
スケジューラーはプリエンティブなオペレーションを構成する。 カーネル・チック周波数は必要とされる時間精度を保証する最も遅い値に設定すべきです。
評 価
Evaluation
従属関係がほとんどない単純な、セグメントされた、フレキシブルな、保守性の良いデザイン。
アプリケーションソースコードの中で明示的な処置なしで、プロセッサを使用するタスクは最も必要性の高いタスクへ自動的に切り替えられます。
アイドル・タスクが電源セーブ(睡眠)モードにプロセッサを移行すれば消費電力は減少します、しかし、不必要に時計(チック)割り込みがプロセッサを目覚めさせため、無駄になるかもしれないが。
カーネルは処理リソースを消費するがこれはカーネル時計(チック)周波数に依存する。
このソリューションは、それ自身のスタックを必要とする多くのタスクと、イベントが受け付ける多数の待ち行列をを必要とする。従って、このソリューションは多くの RAM を使います。
同一優先度のタスク間の頻繁なコンテキストスイッチがプロセッササイクルを浪費する。
結 論
アプリケーションを分割し、タスクとそれぞれのタスクに優先度を割当てることは熟慮を必要とします。

この例は前に紹介した例題アプリケーションの部分的な実装です。FreeRTOS API を使用します。
プラントコントロールタスク
このタスクはすべてのコントロール機能を実行します。これはクリティカルなタイミングがあり、従ってシステム内の最も高い優先度を与える:
#define CYCLE_RATE_MS       10
#define MAX_COMMS_DELAY     2

void PlantControlTask( void *pvParameters )
{
portTickType xLastWakeTime;
DataType Data1, Data2;

    InitialiseTheQueue();

    // A
    xLastWakeTime = xTaskGetTickCount();

    // B
    for( ;; )
    {
        // C
        vTaskDelayUntil( &xLastWakeTime, CYCLE_RATE_MS );
        
        // Request data from the sensors.
        TransmitRequest();
        
        // D
        if( xQueueReceive( xFieldBusQueue, &Data1, MAX_COMMS_DELAY ) )
        {
            // E
            if( xQueueReceive( xFieldBusQueue, &Data2, MAX_COMMS_DELAY ) )
            {
                PerformControlAlgorithm();
                TransmitResults();                
            }
        } 
    }
    
    // Will never get here!
}
上記のコード片のラベルを以下に参照のこと:
  1. xLastWakeTime を初期化する。 この変数は vTaskDelayUntil()APIを使用するに制御機能を実行する頻度を制御する機能に使用されます。
  2. タスク自身は決して終了してはならないので、この行がある。
  3. vTaskDelayUntil () が xLastWakeTime に記録された時刻の正確に 10ms後にこのタスクが実行を始めるべきであるとカーネルに知らせます。 この時刻がくるまで、コントロールタスクはブロックする。 このタスクがシステム内で最も高い優先度タスクであるとき、再び正確な時刻に実行し始めることを保証される。 それはそのとき走っているより低い優先度タスクを事前に制止する。
  4. ネットワークセンサへデータ要求を行い、そのデータが受信されるまでの間に時間差がある、フィールドバスで到着したデータは割り込みサービスルーチンによって xFieldBusQueue に置きます、結果、コントロールタスクは待ち行列のブロックコールでデータが利用可能になるのを待つことができます。 前と同様に、これがシステムで最も高い優先度タスクなので、データが利用可能になったら直ちに実行することを保証します。
  5. Dと同様に第2のセンサからのデータを待つ。
xQueueReceive () からの戻り値が0の場合、データが指定されたブロック期間内に到着しなかったことを示します。 タスクはエラー処理しなくてはならない。 このほか、エラー操作機能は単純化のために省いています。
組み込み Web サーバタスク
組み込み Web サーバタスクは次の擬似コードによって表すことができます。 これはデータがあるときだけプロセッサ時間を使用する、しかし処理の完了には比較的長時間を要するでしょう。
プラントコントロール、 RS232 あるいはキーパッドのスキャニング等に対して、それ等のタスクを妨げないように低い優先度を与える。
void WebServerTask( void *pvParameters )
{
DataTypeA Data;

    for( ;; )
    {
        // Block until data arrives.  xEthernetQueue is filled by the
        // Ethernet interrupt service routine.
        if( xQueueReceive( xEthernetQueue, &Data, MAX_DELAY ) )
        {
            ProcessHTTPData( Data );
        }        
    }
}
RS232 インタフェース
これは組み込みWeb サーバタスクの構造に類似しています。 プラントコントロールタスクのタイミングに影響を与えないように中位の優先度を与える。
void RS232Task( void *pvParameters )
{
DataTypeB Data;

    for( ;; )
    {
        // Block until data arrives.  xRS232Queue is filled by the
        // RS232 interrupt service routine.
        if( xQueueReceive( xRS232Queue, &Data, MAX_DELAY ) )
        {
            ProcessSerialCharacters( Data );
        }        
    }
}
キーパッドを走査しているタスク
これは単純に周期的なタスクです。 タイミング条件が RS232 タスクに類似していることから、中間の優先度を与えられる。
サイクルタイムは指定された限界よりずっと速く定めています。 それはリクエスト後直ちにプロセッサ時間を得られないかもしれないし-また実行中はプラントコントロールタスクによってプリエンプトされるかも知れません。
#define DELAY_PERIOD 4

void KeyScanTask( void *pvParmeters )
{
char Key;
portTickType xLastWakeTime;

    xLastWakeTime = xTaskGetTickCount();

    for( ;; )
    {
        // Wait for the next cycle.
        vTaskDelayUntil( &xLastWakeTime, DELAY_PERIOD );
        
        // Scan the keyboard.
        if( KeyPressed( &Key ) )
        {
            UpdateDisplay( Key );
        }
    }
}
もしシステム全体のタイミングで、これが最下位優先度タスクにできたなら、vTaskDelayUntil () の呼び出しは必要ない。 すべてのより高い優先度タスクがブロックされたときは、キー走査関数は連続実行する− アイドル・タスクに代わって。
LED タスク
これはすべてのタスクの中で最も単純です。
#define DELAY_PERIOD 1000

void LEDTask( void *pvParmeters )
{
portTickType xLastWakeTime;

    xLastWakeTime = xTaskGetTickCount();

    for( ;; )
    {
        // Wait for the next cycle.
        vTaskDelayUntil( &xLastWakeTime, DELAY_PERIOD );

        // Flash the appropriate LED.
        if( SystemIsHealthy() )
        {
            FlashLED( GREEN );
        }
        else
        {
            FlashLED( RED );
        }        
    }
}

NEXT >>> Solution #3: RAM 使用量の節約
Top に戻る