#1.はじめに
M5StackのMPUのESP32には、並列処理を行うために、マルチスレッドという仕組みが用意されています。
自分の勉強用のため、M5StackのExampleのコードを、その内容を噛み砕いて、整理していきます。
#2.プログラムの構造
##2.1. Arduinoのプログラムの基本構造
Arduinoのプログラムは、void setup()とvoid main()の二つの関数によるプログラム構造となっています。
まずvoid setup()で、初期化処理を行います。例えば、変数、定数の宣言、通信部分の設定などがこのvoid setup()関数によって行われます。
そして、実行したいメインのタスク内容は、void loop()の中に記述します。例えば、圧力センサーの値をモニターに表示するタスクを考えましょう。(1) 圧力センサーより測定データを取得する。(2)単位の変換などのデータ処理を行う。(3)LCDやSerialモニターへの出力する、(4)一定な時間間隔でこれらの処理を繰り返し実行します。などの一連の処理部分をこのvoid loop()に書いておきます。
##2.2. マルチスレッド処理のプログラムの構造
マルチスレッドのプログラムは、上記のArduinoの基本プログラムと構造が少し異なります。
まず、void setup()に、**xTaskCreatePinnedCore()**を用いて、並列処理を行いたいタスクを宣言します。タスク数は単数、複数のどちらでもOKですが、並列処理が目的なので、基本的に複数のタスクを宣言することになります。
そして、void loop()にはマルチスレッド用の内容を記述しません。(マルチタスクではないタスクは記述しても構いません。)その代わりに、void task0(), void task1()のような並列処理するタスクを関数として記述し、各々の関数の中にはwhile文を利用したループ構造とします。そのループの中に並列処理されるタスクの処理内容を記述します。
#マルチスレッドを利用する関数
マルチスレッドは、**xTaskCreatePinnedToCore()**を利用し、引数のルールは下記のようになります。
ESP32の場合、Core数が2なので、引数Core IDは0か1になります。
xTaskCreatePinnedToCore(タスクの関数名, "タスク名", スタックメモリサイズ, NULL, タスク優先順位, タスクハンドリングポインタ, Core ID)
例えば、二つのタスクを2番目のコア(Core ID=1)にマルチスレッドで並列処理を行いたい場合は、下記のようなコードになります。
xTaskCreatePinnedToCore(task0, "Task_0", 4096, NULL, 1, NULL, 1)
xTaskCreatePinnedToCore(task1, "Task_1", 4096, NULL, 2, NULL, 1)
#プログラムコード
M5StackのExampleのMultithread例題のコードです。
// Copyright (c) 2020 aNoken
#include <M5Stack.h>
/* task0のループ関数 */
void task0(void* arg) {
static int cnt = 0;
//カウントアップしてシリアルとLCDに表示する
while (1) {
Serial.printf("task0 thread_cnt=%ld\n", cnt);
M5.Lcd.printf("task0 thread_cnt=%ld\n", cnt);
cnt++;
vTaskDelay(1000);
}
}
/* task1のループ関数 */
void task1(void* arg) {
static int cnt = 0;
//カウントアップしてシリアルとLCDに表示する
while (1) {
Serial.printf("task1 thread_cnt=%ld\n", cnt);
M5.Lcd.printf("task1 thread_cnt=%ld\n", cnt);
cnt++;
vTaskDelay(1500);
}
}
void setup() {
M5.begin(); //M5Stackを初期化
M5.Power.begin(); //M5Stackのバッテリ初期化
M5.Lcd.clear(BLACK);
M5.Lcd.setTextColor(YELLOW);
M5.Lcd.setTextSize(3);
M5.Lcd.setCursor(0, 0);
//task0のループ関数を起動
xTaskCreatePinnedToCore(task0, "Task0", 4096, NULL, 1, NULL, 1);
//task1のループ関数を起動
xTaskCreatePinnedToCore(task1, "Task1", 4096, NULL, 2, NULL, 1);
}
void loop() { //Arduinoのメインのループ関数はここで実行
static int cnt = 0;
//カウントアップしてシリアルとLCDに表示する
M5.Lcd.clear(BLACK);
M5.Lcd.setCursor(0, 0);
M5.Lcd.printf("Maintask thread_cnt=%ld\n", cnt);
Serial.printf("Maintask thread_cnt=%ld\n", cnt);
cnt++;
vTaskDelay(1200);
}
#まとめ
M5Stack(ESP32)のマルチスレッドで並列処理を行う方法を整理しました。
#参考資料