ESP32はRaspberry Pi Picoと同様にデュアルコアです。ESP32のボードマネージャの不調も修復して,ごそごそ触り始めています。

128*64のRGBLEDパネルの画面表示を楽に行うことを目標にまずはシンプルにマルチコア機能を試してみました。


ESP32-devkit でLEDの緑をCore1で1秒間隔で, 赤をCore0で0.5秒間隔で同時進行で光らせてみました。




上の画像のプログラムです。

普通のLチカですが,Arduino標準のloop()関数はCore1で動き,作った"task1"関数がCore0でループをしています。




ここまで動いたということは,例えばtask1関数の無限ループの内にLEDパネルへの画像出力部を入れるとマルチタスクで途切れずに処理してくれるはず,,,かな。



以下はESP32のマルチコア機能関係で自分なりのメモです。

参考にしてお世話になっているWebページ
ESP32のFreeRTOS入門 その2 タスクの作成 (Lang-ship)
ESP32でマルチコアを試す12行 (Qiita)
ESP32 Technical Reference Manual (Espressif Systems)


1.デュアルコアの構成



PRO_CPU (Core0),プロトコール(PROtocol) CPU
 wifiやbluetoothなど無線機能で使用するので,そのようなソフトでは重い処理を持ち込まない。

APP_CPU (Core1),アプリケーション(APPlication) CPU
 主にユーザーのソフトが動く。Arduino標準のsetup()関数やloop()関数はこちらで動いている。



2.FreeRTOS,Free Real Time Operating System

 ESP32は基本的にFreeRTOSで動いている。EPS32ではFreeRTOSを一部アレンジして特化(拡張?)しているらしい。

マルチタスクはこのOSの機能で,マルチコアやマルチスレッドに対応している。ArduinoもこのOS上で動いているので,その関数を使う。


1) マルチタスク用の関数を作る

タスク関数の最小構成
ーーーーーーーーーーーーーーーーーー
void タスク名(void *pvParameters){
  while (1) {
    // ここにプログラムを書く
    delay(1);
   }
}

ーーーーーーーーーーーーーーーーーー
・引数はvoid型(不定型?)のポインタ変数としておく
 (void *pvParameters) と書く例が多い
 (void *args),(viod *arg),(void* arg )の例もあり,これも動いた

・while(1){ } は無限ループの定番

・delay(1)は無限ループ中に他にdelayが無い時は必須
 delayはWDT(Watch Dog Timer)をリセットし,ループを継続させる
 ESP32のWDTは3秒以上反応がないとお出ましするらしい
 Arduinoのloop()はWDTを無効にして動いている



2) タスクの作成 xTaskCreateUniversal() 

 xTaskCreate() – シングルコアでマルチスレッドのタスクを作成
 xTaskCreatePinnedToCore() – コアを指定してタスクを作成
 xTaskCreateUniversal() – マルチコア・スレッドに対応してタスクを作成


ーーーーーーーーーーーーーーーーーー
void setup(){    // setup{}内でタスクを作成

 xTaskCreateUniversal(
  タスク名,
  "タスク名",
  スタックメモリサイズ,
  起動パラメータ,
  タスク優先順位,
  タスクハンドル,
  Core ID
 );

}
ーーーーーーーーーーーーーーーーーー
・スタックメモリサイズ:タスク動作時の作業用に4096か8192にしておく
            loop()の設定は8192(以前は4096)とのこと

・起動パラメータ:あまり使わないので NULL にしておく

・タスク優先順位:(低)0<-->24(高),setup()やloop()の優先順位は1

・タスクハンドル:マルチスレッドなら設定すると良い。NULLでも良い
         TaskHandle_t thp[2];  //のように変数を作成し
         xTaskCreateUniversal(・・, &thp[0],1);  //などと使う

・Core ID:タスクの動くコアを指定。0か1

上記プログラムでの設定例
xTaskCreateUniversal(task1, "task1", 8192, NULL, 1, NULL, 0);



以上のように,先人の設定に沿ってシンプルにマルチコアを動かしてみました。

これがうまくいけば,HUB75(E)規格のダイナミック表示のLEDパネルに使えそうですね(^^)。


後,コア間のデータのやりとりにrp2040では専用のFIFO(First In First Out)がありましたがESP32ではキュー(Queue)を作成して使います。必要であれば試してみたいですね。

ま,なんとなくポインタ系の設定や機械的な設定が多めに感じるのは,ハードに近い場所で動いているからでしょうかね。