FreeRTOSタスク管理の基本【学習・実践向け:具体的な使い方】

FreeRTOSを使ったタスク管理の基本を構成の概念を説明しながら実際のプログラム内の具体的な記述を挙げて解説していますので実践のプログラムにすぐに活用できます。学習向けとしていますが、もちろん実践で使えるものです。

タスクの優先度と使用頻度

めかのとろ

アプリケーションプログラムで2種類の処理Aと処理BをRTOSでタスク管理する方法について解説します。処理AはTaskA、処理BはTaskBとして優先順位のあるなし、タスク実行頻度の指定あるなしでどのように実行されるかを見ていきましょう。

 2つのタスクTaskAとTaskBの優先順位が同じで、タスク実行頻度になにも指定しない場合: 

めかのとろ

FreeRTOSの基本設定では1秒間にTick数を1000で指定しているのでタイムスライス(Tick)は1msです。

めかのとろ

つまり、タイムスライス1ms毎にTaskAとTaskBは交互に実行中状態レディー状態がRTOSカーネルにより切り替えられます。タイムスライス1msの間に処理Aおよび処理Bの内容をそれぞれ繰り返します。例えば、図のように処理Aを一回実行するのに要する時間が0.2msであれば5回処理を繰り返したところで処理Bに切り替わります。

 TaskAの優先順位がTaskBのよりも高く、TaskAを5ms中断させる場合:

めかのとろ

優先順位はxTaskCreate関数の第5引数の数値を1から5まで指定します。(設定ヘッダファイルFreeRTOSConfig.hのconfigMAX_PRIORITIESを6にした場合)
FreeRTOSでは数値が大きい方が優先順位は高くなります。ここではTaskAに優先度2、TaskBに優先度1を指定していますのでTaskAの優先度が高くなります。

めかのとろ

TaskAの実行を一定時間中断させるためにはvTaskDelay関数を使用します。関数の引数には待ち時間を指定します。Tickが1msなので引数を5に指定して処理Aを一度実行するとTaskAは5ms間ブロック状態(blocked)となり中断します。この後コンテキストスイッチによりTaskBに切り替わり実行中(Running)となります。

めかのとろ

待ち時間5msが経過するとTaskAは最優先度ですので再び実行します。つまり、約5msの周期で処理Aが一度だけ行われます。

 TaskAの優先順位がTaskBのよりも高く、TaskAを10ms、TaskBを2ms中断させる場合:

めかのとろ

次の例は、動作はtype3と同じなのですが、タスクにパラメータを渡しています。
xTaskCreate関数の第4引数に渡したい値を格納したポインタを指定しますとタスクにパラメータ(値)を渡すことができます。TaskAとTaskBのそれぞれの待ち時間を渡す例です。

 タスク実行周期を正確に設定したい場合:

めかのとろ

これまでの例ではvTaskDelay関数でタスクに待ち時間を入れていました。タスク内の処理に要する時間はまちまちのため、実行周期は多少前後します。

めかのとろ

実行周期を正確に設定したい場合はvTaskDelayUntil関数を使用します。サンプル図のような構成で、xTaskGetTickCount関数で前回のタスク起動時間を取得してvTaskDelayUntil関数に渡しています。

めかのとろ

筆者の体験ではモータの動作を伴うタスクの実行周期を正確に設定すべくこのvTaskDelayUntil関数を使用したところ、タスクを切り替えの過渡期にモータの動作が不安定になることがありました。

めかのとろ

よくよく調べてみると、切り替えの直後はxTaskGetTickCount関数で取得したxLastWakeTimeの値が不定であったため、切り替え直後だけ動作が不安定になっていたようです。モータのモーションコントロールに演算をしており、タスク切り替えのつなぎの部分で演算値が不安定となったからでした。

めかのとろ

問題の解決方法は他にあるかもしれませんが、このようなシビアな状況では問題がなければvTaskDelayUntil関数は使用せずvTaskDelay関数を使うことで問題は解決しました。

めかのとろ

いままでは待ち時間で時間を指定するのに引数の単位はTickでした。指定単位をmsにするためにはFreeRTOSの定数portTICK_RATE_MSを図のように使用すれば指定値の単位をmsとすることができます。

めかのとろ

Tickがちょうど1msであれば定数portTICK_RATE_MSを使用しなくても指定値の単位はmsとなりますが、そうでない場合に使用すると便利です。

タスク切り替え

めかのとろ

FreeRTOSでは任意に複数のタスクのうち、特定のタスクを有効にしたり、無効にしたりすることができます
xTaskCreate関数で登録したタスクはプログラムが開始するとRTOSカーネルの管理のもとに順次実行されます。

めかのとろ

実際のアプリケーションでは複数の機能としてタスクを登録するのですが、登録したすべてが常に必要でなく、必要に応じて有効にしたり、他のタスクと入れ替えたりしながら使用する用途も多いです。

めかのとろ

このようなタスクの切り替えに使用するものがvTaskResume関数vTaskSupend関数です。

タスク切り替え xTaskResume関数、xTaskSuspend関数実行例:
 xTaskSuspend(TaskA);
 xTaskResume(TaskB);

めかのとろ

関数の引数はxTaskCreat関数の第6引数で指定したタスクハンドラを指定します。タスクが有効な場合にvTaskSuspend関数を実行するとどの状態からもサスペンド状態(Supened)に移行し、休止状態となります。vTaskResume関数を実行するとまずレディー状態(Ready)へ移行して、優先順位などの条件次第で実行中(Running)となります。

めかのとろ

タスク切り替えのプログラム例を挙げてみます。
TaskCはタスク切り替え用管理タスクとして、switch関数で変数”mode”が0か1でTaskA、TaskBを切り替えています。

タスク管理
めかのとろ

これまでRTOSを使用してタスク管理を解説してきましたが、RTOSを使用しなければ結構手間のかかる処理が、RTOSではいとも簡単に実現できてしまいます。ここではRTOSの基本的なタスク管理に限っていますがこれでも大抵のアプリケーションは実現できてしまいます。慣れるに従って更に踏み込んで発展させて、より効率のよいシステムを構築してみてください。