LoginSignup
3
4

More than 1 year has passed since last update.

FreeRTOSとiTRONの比較

Last updated at Posted at 2021-08-19

iTRONは仕様であって製品としてのOSではないですが、iTRON系のOSからFreeRTOSへの乗り換え、またはその逆を念頭に両者を比較します。

  • メモリ割り当て
  • タスク
  • イベントフラグ
  • セマフォ
  • ミューテックス
  • キュー/データキュー
  • キューセット
  • メールボックス
  • メモリプール
  • ソフトウエアタイマー/周期ハンドラ
  • カーネル状態
  • 割り込み処理

メモリ割り当て

FreeRTOS,iTRONとも、動的か静的かを選択できます。動的の場合はタスクなどのオブジェクトのメモリをヒープ領域から確保し、静的の場合はコンパイル時に領域が決まります。
FreeRTOSでは、動的か静的かをコンフィグレーションで選択し、静的の場合は割り当て処理をアプリケーションで(静的になるように)実装します。生成時は、xEventGroupCreateStaticのように、~StaticというAPIを使います。
iTRONではアプリケーションでの実装は不要で、コンフィグレーションファイルに静的APIを記述するという形です。静的APIは元のAPI名をすべて大文字にしたもので、cre_tskならCRE_TSKになります。OSによってはGUIで設定できたりします。
起動時に一通り生成した後は、生成も削除もしないというケースであれば、動的も静的も実質的に同じです。

タスク

状態

FreeRTOS iTRON
実行状態 Running Running
実行可能状態 Ready Ready
待ち状態 Blocked Waiting
強制待ち状態 Suspended Suspended
二重待ち状態 × Waiting-Suspended
休止状態 × Dormant

×は(FreeRTOSには)存在しない状態で、それ以外は基本的に同じです。

待ち状態はイベントフラグやセマフォなどによる待ちで、システムコールで(自発的に)待ちに入ります。強制待ち状態は、他のタスクが待ちに入らせるもので、当のタスクは処理の状況に関わらず停止します。

二重待ち状態は、待ち状態のタスクをSuspendした状態です。FreeRTOSではこれもSuspendedです。アプリケーションから見れば、動作はFreeRTOS,iTRONとも同じです。イベントフラグで待っているタスクをSuspendしたとして、その状態でフラグがセットされても、Resumeされない限り実行可能にはなりません。
そもそもSuspend自体使うことが稀だと思うので、どちらがいいということもないです。

アイドルタスク

FreeRTOS iTRON
アイドルタスク あり OSによる
優先度 0以上
大きい方が優先
1以上
小さい方が優先

アイドルタスクは、実行可能なタスクがないときに実行される、OS内部で生成されるタスクです。iTRONは実装依存ですが、ない場合はアプリケーションでアイドルタスクをつくればいいだけです。
基本的には何もしないタスクで、他のタスクが実行可能になるまでCPU時間を消費します。電池など消費電力の制約がシビアな環境では、ハード的にスリープ(クロックを停止)したりもします。

優先度

FreeRTOS iTRON
0以上 1以上
順序 大きい方が優先 小さい方が優先

FreeRTOSの最低優先度0はアイドルタスクの優先度です。他のタスクも使用できますが、特別な理由がなければ使わない方が無難です。

ちなみに、優先度は他のタスクよりも大きいか小さいかだけが意味を持ちます。優先度1のタスクと優先度10のタスクにおいて、他にタスクがなければ、後者を優先度100にしたとしても動作は変わりません。

スケジューリング

FreeRTOS,iTRONとも優先度ベースのスケジューリング方式であって、優先度の高いタスクが実行可能な間は、それよりも低優先度のタスクはどれだけ待っても実行状態(Running)になりません。
同じ優先度のタスクの間では、FreeRTOSはデフォルトでタイムスライシング(ラウンドロビン)方式です。自発的に待ちに入らなくても、ティック間隔(システムタイマーの周期)で次のタスクに切り替わります。
iTRONは先に実行可能になったタスクが優先で、そのタスクが待ち状態になるまでは次のタスクには変わりません。
FreeRTOSではコンフィグレーション(configUSE_TIME_SLICING = 0)でiTRONと同じ方式に変更可能、iTRONはOS自体にタイムスライシングの機能はありませんが、API(rot_dtq)を使ってアプリケーションでラウンドロビンを実現することはできます。
個人的には、リアルタイムシステムでラウンドロビンでないと困ることはほとんどないと思うので、FreeRTOSの方がいいと言うほどのこともないです。

イベントフラグ

FreeRTOS,iTRONとも、ひとつのイベントフラグを複数のタスクで待つことができます。ただし、そのときの動作は若干異なります。

FreeRTOS iTRON
生成 xEventGroupCreate cre_flg
セット xEventGroupSetBits
xEventGroupSetBitsFromISR
set_flg
iset_flg
ウエイト xEventGroupWaitBits wai_flg
複数のタスク
特に指定不要

生成時にTA_WMULを指定
起床と同時に
ビットをクリア

ウエイト時に指定(xClearOnExit)

生成時にTA_CLRを指定
起床順 タスク優先度順 タスク優先度またはウエイト順
生成時にTA_TPRIまたはTA_TFIFOを指定
クリア指定時の
起床タスク
すべて 先頭のタスク

FreeRTOSでは複数のタスクが待っていた場合、すべてのタスクが実行可能になり、現在実行中のタスクと合わせて優先度の最も高いタスクに切り替わります。iTRONでは、TA_CLRの場合、待ち行列の先頭タスクだけが実行可能になります。すべてのタスクを起床するには、TA_CLRを付けずにイベントフラグを生成し、最後に起床したタスクがクリア(clr_flg)します。「最後に」や「クリア」はアプリケーションでやる必要があるので、iTRONは少し不親切です。

また、割り込みサービスルーチン(ISR)からイベントフラグをセットする場合、FreeRTOSでは(OS内部で生成される)デーモンタスクが必要になります。
ISRからxEventGroupSetBitsFromISRをコールすると、実際にはデーモンタスクを起床、デーモンタスクが待ちタスクを起床、という流れです。デーモンタスクを生成しないコンフィグレーションの場合は、ISRからイベントフラグをセットすることはできません。iTRONではこのような制約やデーモンタスクなるものはないので、iTRONの方がわかりやすいです。

FreeRTOSがこのようにしている理由は、リアルタイムOSとして応答性を保証するするためです。
待ちタスクの数には上限がないので、
- 数が多くなると、それだけ待ちを解除するための処理時間が長くなる
- 処理時間の上限が不定になる(やろうと思えば無限に大きくできる)
ISRは割り込み禁止状態なので、一定時間内の応答が保証できなくなります。それを避けるため、デーモンタスクに処理を移して、すぐに割り込み禁止状態を終了するようにしています。
iTRONはそうなっていないですが、現実的にはそんなにたくさんのタスクが待つようなアプリケーションは考えにくいし、その場合でもアプリケーションでケアすればよいということだろうと思います。

とは言え、ひとつのイベントフラグを複数のタスクが待つということ自体が稀ではないかと思います。そういう状況になったら、設計を見直してみた方がいいかもしれません。

イベントフラグ(簡易版)

FreeRTOSのEvent Groupは多機能である反面オーバーヘッドが大きいので、ひとつのタスクしか待たない場合には、Task Notificationというものをイベントフラグとして使うことができます。

FreeRTOS iTRON
生成 - cre_flg
セット xTaskNotify
xTaskNotifyFromISR
set_flg
iset_flg
ウエイト xTaskNotifyWait
(eAction = eSetBits)
wai_flg
複数のタスク 不可 TA_WSGLを指定したら不可
起床と同時にビットをクリア
APIの引数(ulBitsToClearOnExit)で都度指定

TA_CLRを指定

Task Notificationはタスクの生成と同時に生成されます。xTaskNotifyは、待ちタスク(起床させるタスク)を指定するので、必然的に待ちはひとつのタスクのみになります。xTaskNotifyFromISRはISRの中でタスクを起床するので、デーモンタスクは不要です。
iTRONのset_flgは、フラグのIDを指定するだけで、どのタスクが起床するかはセットする側にはわかりません。wai_flgする際に、既に他のタスクがそのフラグで待っている場合はエラー(E_ILUSE)になります。
ほとんどの場合、FreeRTOSのイベントフラグ = Task Notificationと考えてよいです。

セマフォ

FreeRTOS iTRON
生成 xSemaphoreCreateBinary
xSemaphoreCreateCounting
cre_sem
解放 xSemaphoreGive sig_sem
取得 xSemaphoreTake wai_sem
起床順 タスク優先度順 タスク優先度またはウエイト順
生成時にTA_TPRIまたはTA_TFIFOを指定

FreeRTOSのxSemaphoreCreateBinaryは、初期値0のセマフォになります。つまり、初期状態で取得(Take)しようとブロックするので、最初に解放(Give)する必要があります。初期値を1にするにはxSemaphoreCreateCounting(uxMaxCount = uxInitialCount = 1)を使います。

セマフォを解放すると、待ちタスクがひとつ実行可能になりますが、FreeRTOSでは待ちタスクの中で最高優先度のタスクになります。iTRONではウエイト順、つまり(優先度に関係なく)先に取得しようとしたタスクから実行可能にすることもできます。

セマフォ(簡易版)

ひとつのセマフォに対して取得するタスクがひとつだけの場合は、Task Notificationを使うことができます。

FreeRTOS iTRON
生成 - cre_flg
解放 xTaskNotifyGive
vTaskNotifyGiveFromISR
sig_sem
isig_sem
取得 ulTaskNotifyTake wai_sem

ミューテックス

FreeRTOS iTRON
生成 xSemaphoreCreateMutex
xSemaphoreCreateRecursiveMutex
cre_mtx
ロック xSemaphoreGive unl_mtx
アンロック xSemaphoreTake loc_mtx
多重ロック 不可
優先度制御 優先度継承 優先度継承
優先度上限

FreeRTOSのロック,アンロックはセマフォと同じAPIです。
多重ロックはロック中のミューテックスを再度ロックしてもいいというもので、2回ロックしたら2回アンロックする必要があります。xSemaphoreCreateRecursiveMutexで生成したミューテックスのみ可能です。

優先度継承はFreeRTOS,iTRONとも同じで、高優先度のタスクがミューテックスをロックしようとしてブロックするとき、ロックしているタスクが低優先度だった場合は、そのタスクの優先度を引き上げるというものです。

mutex.png

タスクA(優先度a)がミューテックスをロックしているときに、タスクB(優先度b > a)が実行可能になり、そのミューテックスをロックしようとすると、ブロックして(優先度の低い)タスクAに処理が移ります。ただし、このときタスクAの優先度は一時的にbに上がります。タスクAがミューテックスをアンロックすると、タスクBに切り替わると同時にタスクAの優先度はaに戻ります。

優先度上限は、ロックする時点で自分自身の優先度を引き上げるというもので、FreeRTOSには代替となるものがなさそうです。

キュー/データキュー

FreeRTOS iTRON
生成 xQueueCreate cre_dtq
送信 xQueueSend snd_dtq
受信 xQueueReceive rcv_dtq

FreeRTOSではOS内にデータサイズ×データ数の領域を確保しますが、iTRONではポインタ×データ数の領域になります。FreeRTOSではアプリケーション側で領域を確保する必要はありませんが、コピーを伴うので、大きなデータには不向きです。iTRONでは4バイト(16bit CPUなら2バイト)までのデータならFreeRTOSと同じように使えますが、それ以上の場合はアプリケーションで領域を確保する必要があります。

キューセット

FreeRTOS iTRON
生成 xQueueCreateSet ×
ウエイト xQueueSelectFromSet ×

複数のキュー,セマフォ,ミューテックスを同時に待つことができます。WindowsのWaitForMultipleObjectsやLinuxのselectのようなものですが、対象はキューだけです(セマフォとミューテックスはキューを使って実装されているので可)。イベントフラグとキューを同時に待つようなことはできません。ここはiTRONの欠点と言えるかもしれません。

メールボックス

FreeRTOS iTRON
生成 × cre_mbx
送信 × snd_mbx
受信 × rcv_mbx

iTRONのメールボックスはリンクリストのことで、一般的にはメモリプールとセットで使われます。FreeRTOSにはメールボックスそのものはありませんが、キューで代替可能です。

メモリプール

FreeRTOS iTRON
生成 × cre_mpf
取得 × get_mpf
解放 × rel_mpf

動的にメモリを確保するためのもので、1ブロックのサイズ×ブロック数の領域をOS内に確保します。~用に10バイトのブロックを10個、~用に20バイトのブロックを5個というように、用途に応じて複数のメモリプールを生成できる点が、mallocによる確保と異なります。FreeRTOSでは(セマフォ等を使って)アプリケーションで実装する必要があります。

ソフトウエアタイマー/周期ハンドラ

FreeRTOS iTRON
生成 xTimerCreate cre_cyc
開始 xTimerStart sta_cyc
停止 xTimerStop stp_cyc

指定した時間が経過したらコールバック関数が呼ばれます。FreeRTOSはOS内で生成したタイマーサービスタスクから、iTRONは割り込みハンドラからです。タイマーサービスタスクは、コンフィグレーションで優先度を設定できます。

クリティカルセクション

FreeRTOS iTRON
割り込み禁止(ネスト可) taskENTER_CRITICAL ×
割り込み許可(ネスト可) taskEXIT_CRITICAL ×
割り込み禁止(ネスト不可)
CPUロック
taskDISABLE_INTERRUPTS loc_cpu
割り込み許可(ネスト不可)
CPUロック解除
taskENABLE_INTERRUPTS unl_cpu
スケジューリング禁止
ディスパッチ禁止
vTaskSuspendAll
xTaskResumeAll
dis_dsp
ena_dsp

iTRONでは割り込み禁止のことをCPUロック、スケジューリング(コンテキストスイッチ)禁止のことをディスパッチ禁止と言います。

割り込み禁止はCPUの機能で、処理としてはCPU固有の命令を実行するだけです。ネスト不可は本当に割り込みを禁止するだけで、ネスト可は禁止した回数だけ許可しないと最終的に割り込み許可されません。iTRONにはありませんが、単純なものなのでラッパーをつくるのは簡単です。

スケジューリング禁止はOSの機能ですが、ネスト可能かを除いてFreeRTOS,iTRONとも同じです。この状態では割り込みは許可されていますが、タスクの切り替えは保留されています。割り込みが発生して、本来高優先度のタスクに切り替わる状況であっても、そのまま元のタスクに戻り、スケジューリングが許可された時点でタスクが切り替わります。FreeRTOSはネスト可能で、iTRONはネスト不可です。
すべてのタスクからアクセスする変数に対する排他制御などで使うものですが、本来セマフォやミューテックスを使うべきところでも使ってしまいがちです。

割り込み処理

iTRONでは、割り込みハンドラと割り込みサービスルーチン(ISR)が区別されています。FreeRTOSは特に区別はありません。

割り込みハンドラは割り込みによって直接ジャンプする関数で、OSは介在しません。iTRONの割り込みサービスルーチンは、カーネル管理の割り込みと呼ばれ、カーネル内で登録された割り込みハンドラから呼び出されます。割り込みサービスルーチンの目的は、割り込みフラグのクリアなど、CPU依存の処理を隠蔽することです。

一方、FreeRTOSは特に区別はなく、iTRONで言う割り込みハンドラのみです。

全体を通して

RTOSの機能はほとんど共通で、ちょっとした差異はあるものの移行は難しくないと思います。
どちらかと言うと、FreeRTOSの方がストレートかなという気はします。API名もわかりやすいです。iTRONは独自の用語を使ったり、実装依存と濁されたりするところがあります。T-Kernelを使えばいいのかもしれないですが。

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4