FreeRTOS理解その11(マイコンによる違い)


FreeRTOSを用いて、いくつかのボードでソースコードが共通となるようプログラミングおよびテストをしていたところ、マイコンによる差を見つけたので、ここに記録する。

用いたボード(マイコン)および環境

Arduino(ATmega328p)、M5Stack(ESP32)、Nucleo-F303RE(STM32)を、Arduino IDEにて扱う。

サンプル内容

あるタスク(loop())がシリアル通信によりPCからダミーデータを受けると、loop()内で定義されているカウンタ値を別タスク(Task1())に伝え、その別タスクがシリアル通信によりPCにそれを伝えるというもの。例えば、次のような結果が得られる。

サンプルソースコード

CompBoard0.ino
//#define ARD
#define ESP32
//#define STM32

#ifdef ARD     // ARDUINO word NG for STM32
#include <Arduino_FreeRTOS.h>
#include <queue.h> 
#define STACK_SIZE (64+32)  // 80 NG
#endif

#ifdef ESP32
#define STACK_SIZE (512+128+64)  // 640+32+16 NG
#endif

#ifdef STM32
#include <STM32FreeRTOS.h>
#define STACK_SIZE (64+32+16)    // 96 NG
#endif

TaskHandle_t xTask;
QueueHandle_t qMsg;

void Task1(void *arg) {
  uint32_t count;
  char buf[8];
  for (;;) {
    if (xQueueReceive(qMsg, &count, portMAX_DELAY) == pdPASS) {
      sprintf(buf, "N=%d", count);
      Serial.println(buf);
    }
    vTaskDelay(1);
  }
}

void setup() {
  Serial.begin(9600);
  qMsg = xQueueCreate(1, sizeof(uint32_t));
  xTaskCreate(Task1, "Task1", STACK_SIZE, NULL, 0, &xTask);
#ifdef STM32
  vTaskStartScheduler(); // ESP32: Must not exist;  STM32: Must,  ARD: Either OK
#endif  
}

void loop() {
  static uint32_t val = 0;
  if (Serial.available()) {
    (void)Serial.readString();     
    xQueueSend(qMsg, &val, portMAX_DELAY);
    val++;
  }
#ifdef ESP32
  vTaskDelay(1); // STM32 and ARD: Must not exist;  ESP32: Either OK
#endif
}
  • setup():タスクTask1()の作成、タスクloop()とタスクTask1()との通信用のキューを作成する。
  • loop():シリアルからデータを受けたら、データを読み捨て、キューにカウンタ値(val)を入れる。
  • Task1():キューにデータがある場合、カウンタ値(count)を読み取り、それを加工したデータをシリアルに送信する。

なお、使用するマイコンに応じて、「#define ARD」(Arduino)、「#define ESP32」、「#define STM32」のいずれかを定義する。

結果&考察

各マイコン(Arduino(ATmega328p)、M5Stack(ESP32)、Nucleo-F303RE(STM32))での差を下記表に示す。

必要スタックサイズ(16バイト単位) setup()のvTaskStartScheduler() loop()のvTaskDelay()
Arduino 96 有無関係なし? 有ると動作せず
M5Stack 704 有ると動作せず 有無関係なし?
Nucleo 112 必須 有ると動作せず

かなり差があることが判明。

  • 「有ると動作せず」とは、上述した結果が得られないことを意味する。
  • 「有無関係なし?」とは、vTaskStartScheduler()やvTaskDelay()が、有っても無くても、上述した結果が得られていることを意味する。
  • ESP32(M5Stack)にて必要なスタックサイズが突出している。

あくまで私の環境の結果であり、すべてのケースに当てはまるかどうかまでは不明である。

おまけ

  • タスク生成時のタスク優先度を変えてみたが、結果は変わらない様子(詳細未調査)。
  • 「#define ARDUINO」がある状態で、Nucleo(STM32)のBuildはできず。