2017年6月15日木曜日

CMSIS-RTOSが面倒くさい

 Cubeで出力されるFreeRTOSはCMSIS-RTOSのラッパーが含まれているし、Cubeでタスクやキューの設定をすると、CMSIS-RTOSに準拠した?コードが出力される。ということでCMSIS-RTOSってどうやって使うんぞ?とちょっとドキュメントのサンプルソースを見てみた。
 とりあえずQueueを使ってみたかった。

 Message Queue

 かなり面倒くさいようだ。
 つま先でつついた程度で泥沼っぽいぞ、という気がしてきたので、とりあえず今回は違う道を通ることにした。

***

 ざっくりと流れを予想してみると、初期化時にQueue以外に、mallocで使うスペースも準備する。
 Queueに渡す(Putする)時は、予め用意したスペースからosPoolAllocでメモリ割り当てを受ける。そのメモリに情報を入れて、osMessagePutで割り当てられたポインタをQueueに入れる。
 Queueから受け取る(Getする)時は、osMessageGetでQueueから受け取り、必要な情報を取り出す。操作が終われば、osPoolFreeでメモリ割り当てを開放する。

 Queueの準備や、メモリ割り当ての準備は、マクロでいろいろ操作する必要があるので、いちいち書くのは結構面倒。
 Cubeではメモリ割り当ての初期化を行うことができないので、CMSIS-RTOS風の書き方をするなら、自分で初期化を追加する必要がある。またメモリ割り当ては固定長だが、CubeでQueueを大きくした場合は、ソースコードのメモリ割り当て初期化も修正する必要がある。誘蛾灯の雰囲気がプンプンするゾ。

 で、どうしてこういう面倒なことになっているのか。

 FreeRTOSのQueue回りは、ポインタを受け取って、構造体分全体をQueueに割り当てられたメモリにコピーするという処理が有る。おおよそmemcpyのような処理が行われるはずだが、構造体が大きくなればmemcpyに要する時間も長くなるので、処理時間の予測ができない。一方、ポインタだけをQueueに入れる場合、せいぜい4バイトか8バイトの転送で済むので、OSでの処理時間はある程度予想ができる。
 ただし、ただmallocを使う場合は、メモリのフラグメンテーションが問題になる可能性がある。実行時間に制限の付けにくいRTOSでは、フラグメンテーションの可能性は可能な限り避けたいところ。
 ということで、osPoolが出て来る。osPoolは固定長のメモリを小数割り当てるための機能であり、フラグメンテーションは発生しない。また、割当の組み合わせ数はかなり少ないので、空きメモリの検索も高速で行われることが期待できる。


 ということで、CMSIS-RTOSは個人レベルでプログラムを書く場合はかなり面倒だが、安定性を重視して作られている感じがする。

 とはいえ、例えばUARTのような、1回の処理で1バイトしか転送されないと行った場合は、FreeRTOSのような直接転送する方が早そうな気がする。このあたりはCMSIS-RTOSでもちゃんと用意されてるんだろうけども。

 あくまで業務用でも使えるRTOSなので、自分で楽しむレベルの電子工作では過剰かな、という気がする。なので、僕はしばらくFreeRTOSらいくな使い方を続けると思う。いざCMSIS-RTOSが必要になった時に、相当苦労しそうだけど、まぁそれはその時に考えるということで。

0 件のコメント:

コメントを投稿