ESP32-freeRTOSのtask関連ラッピングクラス

freeRTOSのタスク関連を使ううえで、APIなどちょっと長くて面倒だなと思ったのでC++でラッピングクラスを作ってみた。
また、実装時にいろいろ間違ったことなどをTips的に載せてみる。

タスクラッピングクラス

https://github.com/take4blue/librarieseesp32/tree/master/lib/freertos_utility

簡単な使い方については、examplesフォルダのものを参照してもらうとして、今回生成したのは、以下の2つのテンプレート。

  • TaskControl
  • TaskControlV

前者が仮想関数がない場合に使うもので、後者が仮想関数を用意するクラスで使うもの。

クラスメソッドのtask内にタスク内で処理する内容を記述し、startProcessを呼び出すことでタスクが生成、管理対象となる。
ほかクラスメソッドとしてsuspend/resumeとnotify関連も入れてあるので、簡単なものならこれで対応できると思う。

notify関連の簡単な動作例は、sample2側に入れてある。

タスクを使用するときの気づき

freeRTOSのタスクで実装していた時に、よく考えればわかりそうなのだが、気が付かづに実装していろいろエラーを出してしまったことをちょっと羅列してみる。

優先順位

値が小さいほうが優先順位が高いと思った。
そのため、タスクが起動されないという問題が発生してしまった。
(これは後述)

実際は値が大きいほど優先順位は高くなる。

ESP32のマニュアル側にはその詳細が記載されていなかったため、過去の経験からそう思い込んでしまっていた。
いくつかのサイトをめぐっても、同じような間違いをしているのが結構いるようだった。

設定可能な値は0以上となっていて、app_mainは(最小値+1)つまり1の優先順位になっている。

app_mainの位置づけ

エントリー用のタスクとして登録起動されたもの。
そのため、returnしても問題はない。
returnした後、app_mainのタスクは破棄されるようだ。

Application Startup Flow - ESP32 - — ESP-IDF Programming Guide latest documentation

これに関連しての問題として、app_main内にオート変数としてTaskControlの派生オブジェクトを生成し、タスクを生成する実験を行っていたのだが、タスク起動後タスクが変な動きをしてしまっていた。

原因はapp_mainはそのままreturnしてしまっていたため、オブジェクトも破棄されてしまっていたため。当然といえば当然なのだが、気が付くまで時間を使ってしまった。

タスクを生成する場合、そのタスクに関する変数などは、グローバルなどに置いておくのが良いだろう。またタスクを生成してそちらでマイコンの制御を行うのであれば、app_mainはリターンしておくのが良いのだろう。

一部サイトでは、app_mainの最後で永久ループを入れたほうが良いような書き方をしていたのがあるが、何もしないタスクを残すのはリソースの無駄でしかないと思う。

タスクの起動

優先順位と関連する話題なのだが、実装したタスクが起動しないといった状況に陥ったときがあった。

extern "C"
void app_main()
{
  test2.startProcess("test2", 4096, 5, 1);
  test3.startProcess("test3", 4096, 5, 0);
  test1.startProcess("test1", 4096, 5, 0);
}

メインから上のような形で3つのタスクを起動したのだが、test1のタスクのみ起動しなかった。
test1~test3のタスクはfor文の永久ループで常にRunning状態になるようなもの。

これは、app_mainのプライオリティが1のためtest3のタスクが最優先で実行し続けてしまいtest1のタスク起動まで処理がされなかったため。

test3が動作したのは、test2がコア1での動作だったのでコア0のapp_mainはまだ動けたから。

一応、メインと同じプライオリティにしたところtest1まで動作させることはできた。

この問題に関しても、タスク関連のソースをちらちら見ている限り、プライオリティは高めに設定しているのが多く、そのほとんどがタスク起動直後vTaskDelayを呼び出している。
これは、タスクをブロッキング状態にさせ、app_mainの動作をさせているのかな?と思ったりもした。

コメント

タイトルとURLをコピーしました