ソフト

FreeRTOSの基本的な使い方、タスク・キュー・セマフォの概念と実装例

FreeRTOSの基本的な使い方、タスク・キュー・セマフォの概念と実装例

FreeRTOSの基本的な使い方、タスク・キュー・セマフォの概念と実装例

組み込みシステム開発において、複数の処理を同時に、かつ決められた時間内に実行する必要がある場面は少なくありません。センサーからのデータ収集、ユーザーインターフェースの操作、通信処理といった様々なタスクが複雑に絡み合うと、プログラムの設計は一気に難しくなります。このような課題を解決するために、リアルタイムOS(RTOS)が活用されます。

FreeRTOSは、軽量でオープンソース、そして幅広いマイコンに対応していることから、組み込み開発の現場で特に広く採用されているRTOSの一つです。これから製品開発を始める方や、試作段階で複雑な並行処理に直面している方にとって、FreeRTOSの基本的な考え方を理解することは、安定した製品づくりに不可欠なステップとなるでしょう。

FreeRTOSの基本:タスクとスケジューリング

FreeRTOSでは、実行したい処理の単位を「タスク」と呼びます。例えば、温度センサーからデータを読み取るタスク、そのデータを無線で送信するタスク、LEDを点滅させるタスクなど、それぞれ独立した機能を持つ処理をタスクとして定義します。

各タスクには優先度を設定できます。FreeRTOSの「スケジューラ」は、この優先度に基づいてどのタスクをいつ実行するかを決定します。一般的に、FreeRTOSは「プリエンプティブスケジューリング」を採用しており、より高い優先度を持つタスクは、実行中の低優先度タスクを中断させて、すぐに実行を開始できます。これにより、時間的制約の厳しい処理を優先的に実行することが可能になります。

タスクは `xTaskCreate()` といったAPIを使って生成し、それぞれが独自のスタック領域を持ちます。タスクの設計では、スタックサイズを適切に見積もることが重要です。不足すると実行時エラーの原因となり、多すぎるとメモリを無駄に消費してしまいます。

タスク間通信の基本:キュー

複数のタスクが協調して動作するには、タスク間でデータを安全に受け渡す仕組みが必要です。FreeRTOSでは、その主要な手段として「キュー」を提供しています。

キューは、データを一時的に保管しておくバッファのようなものです。送信側のタスクは `xQueueSend()` を使ってキューにデータを書き込み、受信側のタスクは `xQueueReceive()` を使ってキューからデータを読み出します。この仕組みにより、データの受け渡しを非同期に行うことができます。

例えば、センサーデータを取得するタスクがデータをキューに書き込み、そのデータを処理する別のタスクがキューから読み出して処理を進める、といった使い方が一般的です。キューは、データがまだ届いていない場合や、キューがいっぱいの場合にタスクを待機させる機能も持っており、効率的なタスク連携を実現します。

タスク間同期と排他制御:セマフォとミューテックス

タスク間でのデータの受け渡しだけでなく、特定の処理の実行順序を制御したり、複数のタスクが同時にアクセスすると問題が生じる共有リソース(例えば、特定のハードウェアレジスタやグローバル変数)へのアクセスを制限したりする「同期」や「排他制御」も重要です。FreeRTOSでは「セマフォ」と「ミューテックス」がその役割を担います。

セマフォの種類と利用例

セマフォは、リソースの利用可能数をカウントしたり、イベントの発生をタスクに伝えたりする汎用的な同期メカニズムです。

  • バイナリセマフォ: 0か1の値を持ち、主に排他制御やイベント通知に使われます。ミューテックスと似ていますが、ミューテックスが所有権の概念を持つ点が異なります。`xSemaphoreCreateBinary()` で作成し、`xSemaphoreGive()` でセマフォを放出し、`xSemaphoreTake()` で取得します。
  • カウンティングセマフォ: 0以上の任意の値を持ち、複数の同種のリソースの利用可能数を管理するのに使われます。例えば、3つのプリンターがある場合、セマフォの初期値を3として、1つ使うごとにセマフォの値を減らし、使い終わったら増やす、といった制御が可能です。

デッドロックを防ぐミューテックス設計

ミューテックスは、セマフォの一種ではありますが、特に共有リソースへの排他制御に特化しています。あるタスクがミューテックスを取得している間は、他のタスクはそのミューテックスを取得できず、リソースへのアクセスを待機します。これにより、複数のタスクが同時に共有リソースを書き換えることによるデータの破損を防ぎます。

ミューテックスを使用する上で特に注意すべきなのが「デッドロック」です。デッドロックとは、複数のタスクがお互いに必要なリソースをロックし合い、どちらも処理が進まなくなる状態を指します。例えば、タスクAがリソースXをロックし、リソースYを待機。同時にタスクBがリソースYをロックし、リソースXを待機する、といった状況です。

デッドロックを防ぐためには、ミューテックスの取得順序を統一する、ロックする時間を最小限にする、FreeRTOSが提供する「優先度継承」などの機能を利用するといった設計上の工夫が必要です。優先度継承は、低優先度タスクがミューテックスを保持しているときに、高優先度タスクがそのミューテックスを待機した場合、一時的に低優先度タスクの優先度を高優先度タスクの優先度まで引き上げることで、デッドロックや優先度逆転を防ぐメカニズムです。

製品開発におけるFreeRTOS活用のポイント

FreeRTOSを使うことで、システムの複雑な並行処理を効率的に記述できますが、製品として安定稼働させるためにはいくつかのポイントがあります。

まず、タスクのスタックサイズと優先度設計です。試作段階では問題なく動いていても、特定の処理が重くなったり、意図しない割り込みが発生したりすると、スタックオーバーフローや優先度逆転によるハングアップが発生することがあります。デバッグが難しいため、設計段階で十分に検討し、余裕を持たせた設計が求められます。

次に、タスク間通信と同期の設計です。キューやセマフォの誤った使い方、特にデッドロックの可能性を考慮しないミューテックスの利用は、システム全体の不安定化を招きます。複数のタスクが関わる処理は、一つずつ丁寧に動作検証を行う必要があります。

当社サイコス・ジャパン株式会社では、35年以上の製品開発経験の中で、FreeRTOSをはじめとするリアルタイムOSを用いた組み込みシステムの開発に数多く携わってきました。機構設計から電子回路、基板、組み込みソフト、クラウド、そして量産まで、製品開発の全工程を一社で手掛けているため、各工程の連携をスムーズに進められます。

FreeRTOSのようなRTOSを組み込んだ製品は、その複雑さゆえに、試作から製品化へのステップで課題に直面することも珍しくありません。もし、試作機は動いているものの、量産や安定稼働に向けた設計に不安がある場合は、ぜひ一度ご相談ください。

← 技術コラム一覧に戻る
無料相談する