Arduinoで遊ぶページ

Arduinoで遊んだ結果を残すページです。
garretlab
マルチタスク・デュアルコアの実験(ESP-WROOM-32)

概要

Arduino core for the ESP32を使った、ESP-WROOM-32開発ボードのマルチタスク・デュアルコアの実験です。もはやArduinoではないような気もしますが、マルチタスクとデュアルコアについて試してみました。

Arduino Uno等では難しかった、マルチタスクでの動作が簡単にできます。各タスクを、任意のコアで動作させることも、スケジューラ任せで動作させることも可能です。

Arduino core for the ESP32のインストールのページはこちら

実験

Arduino core for the ESP32の実装

Arduino core fore the ESP32のmain.cppを見てみると、以下のようになっていました。

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "Arduino.h"

#if CONFIG_AUTOSTART_ARDUINO

#if CONFIG_FREERTOS_UNICORE
#define ARDUINO_RUNNING_CORE 0
#else
#define ARDUINO_RUNNING_CORE 1
#endif

void loopTask(void *pvParameters)
{
    setup();
    for(;;) {
        micros(); //update overflow
        loop();
    }
}

extern "C" void app_main()
{
    initArduino();
    xTaskCreatePinnedToCore(loopTask, "loopTask", 4096, NULL, 1, NULL, ARDUINO_RUNNING_CORE);
}

#endif

Arduino core for the ESP32は、FreeRTOS上に実装されていて、Arduinoのsetup()や、loop()は、loopTask()というFreeRTOSのタスク内で実行されているようです。また、loopTask()は、コア番号ARDUINO_RUNNING_COREで実行されるように、タスクが生成されています。

ARDUINO_RUNNING_COREがどう定義されているかを、以下のスケッチで試してみると、1と表示されました。

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "Arduino.h"

#if CONFIG_AUTOSTART_ARDUINO

#if CONFIG_FREERTOS_UNICORE
#define ARDUINO_RUNNING_CORE 0
#else
#define ARDUINO_RUNNING_CORE 1
#endif

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);

  Serial.printf("ARDUINO_RUNNING_CORE = %d\n", ARDUINO_RUNNING_CORE);
}

void loop() {
  // put your main code here, to run repeatedly:
}
#endif

結果は以下の通り、1と表示されました。ということで、複数のコアを用いて動作させることができるようです。

余談ですが、Arduino core fore the ESP32のPrintクラスには、printf()が定義・実装されているので、コンソール出力の際に、printf()を使うことができます。便利です。Uno等と共有するスケッチでは使えませんが。

ということで、Arduinoのsetup()や、loop()は、コア1上で動作させているようです。

タスク制御

タスクの生成(create)、削除(delete)、停止(suspend)、再開(resume)のテストをしてみました。

以下のサンプルスケッチでは、4つのタスクを生成し、それぞれ、以下の動作を行います。

タスク名 実行コア指定有無 動作
task1 なし 永久に動作
task2 なし 永久に動作
task3 あり。コア0で動作させる。 開始後約2.5秒後に停止させ、その約3秒後に再開する。
task4 あり。コア1で動作させる 開始後約2.5秒後に削除する。

ソースコードを見る限り、Serial.write()は、スレッドセーフのようです。

#include "freertos/task.h"
#include "time.h"

TaskHandle_t taskHandle3, taskHandle4;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.printf("setup() runs on core %d\n", xPortGetCoreID());

  xTaskCreate(task, "task1", 4096, NULL, 10, NULL);
  xTaskCreate(task, "task2", 4096, NULL, 20, NULL);
  xTaskCreatePinnedToCore(task, "task3", 4096, NULL, 30, &taskHandle3, 1);
  xTaskCreatePinnedToCore(task, "task4", 4096, NULL, 40, &taskHandle4, 0);
}

void loop() {
  // put your main code here, to run repeatedly:
  delay(2500);
  vTaskSuspend(taskHandle3);
  vTaskDelete(taskHandle4);

  delay(3000);
  vTaskResume(taskHandle3);

  while (1) {
    delay(1000);
  }
}

void task(void *arg) {
  time_t now;
  struct tm tmNow;

  while (1) {
    time(&now);
    localtime_r(&now, &tmNow);

    Serial.printf("%02d:%02d %s runs on core %d\n", tmNow.tm_min, tmNow.tm_sec, pcTaskGetTaskName(NULL), xPortGetCoreID());
    delay(1000);
  }
}

結果は以下の通りでした。

バージョン

Arduino 1.8.3/Arduino core for the ESP32/ESP-WROOM-32



メニューを表示するためにJavaScriptを有効にしてください。

Arduinoで遊ぶページ
Copyright © 2017 garretlab all rights reserved.
inserted by FC2 system