STM32でNUTTXを使ってみる

Named Message Queue Interfaces


マルチタスクのシステムを設計する際に、一番重要なのはタスクの同期とタスク間通信です。
そこで、タスクの同期とタスク間通信を行うNamed Message Queue Interfacesを紹介します。
マルチタスクのシステムを構築する際には、タスクの起動、資源の排他制御、タスク間通信だけで、ある程度のことはできてしまいます。

この動作を確認するためのサンプルアプリを公開しています。
こちらの手順でapps/examplesディレクトリに追加してくださ い。
以下の手順でサンプルアプリをファームに組み込みます。
$ make clean
$ make menuconfig

Application Configuration > Examples で以下のアプリを追加してください。


新規アプリを追加したらひたすらExitで抜けます。
最後に以下の画面で[.config]を上書きします。


新しい[.config]を使ってファームウェアをビルドし、新しいファームウェアをマイコンに書き込みます。
nshに接続するとmq_testアプリが追加されています。




sendの引数で実行すると、MessageQueueにメッセージを格納します。
一度に格納できるメッセージの長さは32Byte、格納できるメッセージの数は20です。
タスク間で多量のデータをやり取りするときは、ファイル経由にするなどの工夫が必要です。
recvの引数で実行すると、MessageQueueからメッセージを取り出します
メッセージは登録した順に取り出すことができます。
nsh> mq_test send
nsh> mq_test send
nsh> mq_test recv
nbytes=32 prio=42
msg_buufer=g_system_timer=984
nbytes=32 prio=42
msg_buufer=g_system_timer=1350
nsh>



sendの引数にはメッセージの優先度を指定することができます。
メッセージの優先度を指定すると、メッセージは登録した順ではなく、優先度順に取り出すことができます。
nsh> mq_test send
nsh> mq_test send 50
nsh> mq_test send 60
nsh> mq_test recv
nbytes=32 prio=60
msg_buufer=g_system_timer=18253
nbytes=32 prio=50
msg_buufer=g_system_timer=17622
nbytes=32 prio=42
msg_buufer=g_system_timer=17142
nsh>



startの引数で実行すると、2つのタスクを起動します。
myTask1は[foo] myTask2は[bar]のMessage Queueを待ちます。
nsh> mq_test start
task_create name:myTask1 priorty:100
task_create name:myTask2 priorty:100
myTask1 start PID:10 system_timer:41560
myTask1 Open Message Queue[foo]
myTask1 Wait on Message Queue[foo]
myTask2 start PID:11 system_timer:41560
myTask2 Open Message Queue[bar]
myTask2 Wait on Message Queue[bar]
nsh> ps
  PID GROUP PRI POLICY   TYPE    NPX STATE    EVENT     SIGMASK   STACK COMMAND
    0     0   0 FIFO     Kthread N-- Ready              00000000 001000 Idle Task
    2     2 100 RR       Task    --- Running            00000000 002000 nsh_main
   19    19 100 RR       Task    --- Waiting  MQ empty  00000000 002000 myTask1 foo
   20    20 100 RR       Task    --- Waiting  MQ empty  00000000 002000 myTask2 bar
nsh>

これに続けてfooの引数で実行すると、[foo]のMessage Queueにメッセージを格納します。
myTask1がこれを受け取ります。
nsh> mq_test foo
myTask1 Receive from Message Queue[foo] nbytes=32 prio=47
myTask1 msg_buufer=g_system_timer=43975
myTask1 Wait on Message Queue[foo]
nsh>

これに続けてbarの引数で実行すると、[bar]のMessage Queueにメッセージを格納します。
myTask2がこれを受け取ります。
nsh> mq_test bar
myTask2 Receive from Message Queue[bar] nbytes=32 prio=47
myTask2 msg_buufer=g_system_timer=54017
myTask2 Wait on Message Queue[bar]
nsh>



今まで紹介したAPI以外に以下のAPIが用意されています。

Clocks and Timers
サンプルアプリを見ても、タイムアウト付きセマフォーロック時の時間計算ぐらいしか使っていません。

Signal Interfaces
カーネル内部では多用されていますが、ユーザアプリのレベルでは有効な使い方が思いつきません。

Environment Variables
これも有効な使い方が分かりません。

Shared Memory Interfaces
期待していたんですが、
Shared memory interfaces are only available with the NuttX kernel build (CONFIG_BUILD_KERNEL=y).
NOTE: This build configuration requires that the platform support a memory management unit (MPU) and address environments.
Support, however, may not be implemented on all platforms.

共有メモリ インターフェイスは、NuttX カーネル ビルド (CONFIG_BUILD_KERNEL=y) でのみ使用できます。
注: このビルド構成では、プラットフォームがメモリ管理ユニット (MPU) とアドレス環境をサポートしている必要があります。
ただし、サポートはすべてのプラットフォームに実装されているわけではありません。

だそうで、STM32では使えません。
グローバル変数+セマフォで代用することができます。

Pthread Interfaces
Nuttxでのタスクとスレッドの違いはこ ちらに 紹介されています。
タスクとスレッドの違いは、親タスクの資源を共有できるかどうかだけみたいです。

(原文)
Systems like Linux also support POSIX pthreads. In the Linux environment, the process is created with one thread running in it. But by using interfaces like pthread_create(), you can create multiple threads that run and share the same process resources.

NuttX also supports POSIX pthreads and the NuttX pthreads also support this behavior. That is, the NuttX POSIX pthreads also share the resources of the parent task. However, since NuttX does not support process address environments, the difference is not so striking. When a task creates a pthread, the newly create pthread will share the environment variables, file descriptors, sockets, and streams of the parent task.

Note: These task resources are reference counted and will persist as long as a thread in the task group is still active.

(自動翻訳)
LinuxのようなシステムはPOSIX pthreadsもサポートする。
Linux環境において、プロセスは作成されて、それにおいて1つのスレッドが動く。
しかし、pthread_create()のようなインタフェースを使うことによって、あなたは、同じプロセス資源を共有して実行する複数のス レッドを作 成できる。

NuttXもまたPOSIX pthreadsをサポートし、NuttX pthreadsもまたこのような振る舞いをサポートする。
すなわち、NuttX POSIX pthreadsもまた親タスクの資源を共有する。
しかし、NuttXがプロセスアドレス環境をサポートしないので、違いはそんなに著しくない。
タスクによりpthreadが作成される時には、新しく作成されたpthreadは、親タスクの環境変数、ファイル記述子、ソケット、およびスト リームを共有する。

注:これらのタスク資源は、参照がカウントされ、タスクグループのスレッドがまだアクティブな限り持続する



APIの使い方に間違いがあるかもしれません。
こ ちらのドキュメントで確認してください。

ファームの書き込み方法と、nshへの接続方法はこちらに紹介しています。
STM32F4 Discovery
STM32F3 Discovery
STM32F103RB Nucleo
STM32F103 BluePill/BlackPill
STM32F103 VEボード
STM32F407 VGボード

続く...