モダンOSのお砂場(18) FreeRTOS、ArduinoIDEでビルドできたんだ

Joseph Halfmoon

CQ出版社Interface誌の2021年4月号を読ませていただいたために、FreeRTOSのお勉強を再開。ついては実習はどのボードでどの開発環境でやろうかしらと考えました。いつかの候補の中から穴馬出現。予想していませんでしたArduinoIDE、それも既にインストール済の環境でFreeRTOSのコードがビルドできる、というのです。

※「モダンOSのお砂場」投稿順Indexはこちら

特集を読ませていただくと、入手しやすいFreeRTOS対応のボードが列挙されています。その中でポイントは、ネットワーク対応可能(できれば無線)、そして無線の場合は技適OKであること。そう思ってリストをみれば、当然なんでありますが、手持ちのボードも2種含まれておりました。

  • M5StickC
  • ESP32 DevKit C

どちらもマイコンはEspressif社ESP32であります。諸般の事情からターゲットは ESP32 DevKit Cにいたしました。

さて、開発環境のチョイスはどうしようかしら。ESP32 DevKit Cについては本シリーズの以前の回で既にBLEのサンプルプログラムをビルドしてみたりしているので、FreeRTOSが動かない筈がないのです。そのときの開発環境は、

VS Code + PlatformIO + ESP-IDF環境

でした。そこへ戻るか。これに対して、Interface誌2021年4月号の特集の第4部、第1章でもESP32 DevKitC使った記事が掲載されているのですが、

AWSからESP32 DevKitC用に構成済のソース一式+認証ファイルをダウンロードしてクロス環境(コマンドライン)整備してからビルド

という方式です。主目的がAWSを介したセキュアな通信の実験なので、かくありなん、と。どちらにするか、それともちょっと面倒そうだが折衷案もあるななどと思っているときに穴馬に気付きました。あれれれ、と思ってちょっとびっくりしたのは、Shawn Hymel先生の以下の動画を視聴させていただいた時です。

Introduction to RTOS Part 2 – Getting Started with FreeRTOS | Digi-Key Electronics

普通にArduinoIDEで、Arduino環境のプロジェクト(ESP32用)を開始して、特にライブラリ等インストールすることなく、また、ヘッダファイル等も一切インクルードすることなく、FreeRTOSの関数呼んで、「マルチスレッド」で動いている。およよ、なして?

見ればArduinoIDE環境でESP32シリーズ向けにインストールされる共通パッケージの中には最初から FreeRTOS が含まれているようなのです。そういえばそんな話、どこかで読んだ記憶がある。実際にArduinoIDEにインストール済のESP32用のパッケージの中を覗いてみました。こんな感じ。

FreeRTOSinArduinoLIBESP32上で、Arduino環境のプログラムを動かしていても、裏ではFreeRTOSが動いておる。そして、

  • vTaskチョメチョメ
  • xTaskチョメチョメ

などというお名前のFreeRTOSの関数群、何の前置きもなく使える。Shawn Hymel先生の早口の英語についていくのが辛いので、バッサリやって「とりあえず」動作させるだけの「エッセンス」を取り出して定番LチカのFreeRTOS版コードを書いてみました(末尾に添付。)見た目はArduinoのお作法通りのコード。そのなかでvTaskDelay()、xTaskCreatePinnedTOCore()を呼んでいるだけ。しかしちゃんと動いてますがな。アイキャッチ画像は、動作中の様子。

こないだから「恐るべし」などと書いておりましたが、自分じゃ無意識な間にお世話になっておりました。それどころか、何も意図的に準備しないうちに御馴染の環境で開発できるようになっていたとは。FreeRTOSの跳梁跋扈、まさに恐るべし。

モダンOSのお砂場(17) Zephyr RTOS、VS Codeでサンプル・ビルド へ戻る

モダンOSのお砂場(19) FreeRTOS、メモリのアロケーション へ進む

ともかく極小化したESP32用 FreeRTOS版Blink on Arduino環境
static const BaseType_t app_cpu = 0;
static const int led_pin = 23;

void toggleLED(void *parameter) {
  while (1) {
    digitalWrite(led_pin, HIGH);
    vTaskDelay(100);
    digitalWrite(led_pin, LOW);
    vTaskDelay(100);
  }
}

void setup() {
  pinMode(led_pin, OUTPUT);
  xTaskCreatePinnedToCore(toggleLED, "t1", 1024, NULL, 0, NULL, app_cpu);
}

void loop() {
  // Do nothing.
}