ESPモジュールは、ESP8266、ESP-12EなどのWi-Fi機能で人気があります。これらはすべて、Wi-Fi機能を備えた強力なマイクロコントローラーモジュールです。以前のESPモジュールよりも強力で用途の広いESPモジュールがもう1つあります。その名前はESP32です。BluetoothとWi-Fi接続があり、ESP32のBLE機能についてはすでに説明し、多くのIoTプロジェクトでESP32を使用しました。しかし、ESP32がデュアルコアマイクロコントローラーであることを知っている人はほとんどいません。
ESP32には2つの32ビットTensilicaXtensa LX6マイクロプロセッサが搭載されており、強力なデュアルコア(core0およびcore1)マイクロコントローラになっています。シングルコアとデュアルコアの2つのバリエーションがあります。ただし、価格に大きな違いがないため、デュアルコアバリアントの方が人気があります。
ESP32は、Arduino IDE、Espressif IDF、LuaRTOSなどを使用してプログラミングできます。ArduinoIDEでプログラミングしている間、Core0はすでにRF通信用にプログラムされているため、コードはCore1でのみ実行されます。ただし、このチュートリアルでは、ESP32の両方のコアを使用して2つの操作を同時に実行する方法を示します。ここで、最初のタスクはオンボードLEDを点滅させることであり、2番目のタスクはDHT11センサーから温度データをフェッチすることです。
まず、シングルコアに対するマルチコアプロセッサの利点を見てみましょう。
マルチコアプロセッサの利点
- マルチコアプロセッサは、同時に動作するプロセスが3つ以上ある場合に役立ちます。
- 作業が異なるコアに分散されるため、作業速度が向上し、複数のプロセスを同時に終了できます。
- いずれかのコアがアイドルモードの場合、その時点で使用されていない周辺機器をシャットダウンするために使用できるよりも、消費電力を削減できます。
- デュアルコアプロセッサは、一度に1つではなく、一度に2つを処理できるため、シングルコアプロセッサよりも異なるスレッドを切り替える頻度が少なくなります。
ESP32とFreeRTOS
ESP32ボードには、すでにFreeRTOSファームウェアがインストールされています。FreeRTOSは、マルチタスクで非常に役立つオープンソースのリアルタイムオペレーティングシステムです。RTOSは、リソースの管理とシステムパフォーマンスの最大化に役立ちます。FreeRTOSにはさまざまな目的のための多くのAPI関数があり、これらのAPIを使用して、タスクを作成し、さまざまなコアで実行させることができます。
FreeRTOS APIの完全なドキュメントは、ここにあります。コードでいくつかのAPIを使用して、両方のコアで実行されるマルチタスクアプリケーションを構築しようとします。
ESP32コアIDの検索
ここでは、ArduinoIDEを使用してコードをESP32にアップロードします。コードが実行されているコアIDを知るために、API関数があります
xPortGetCoreID()
この関数は、 void setup() および void loop() 関数から呼び出して、これらの関数が実行されているコアIDを知ることができます。
以下のスケッチをアップロードすることで、このAPIをテストできます。
void setup(){ Serial.begin(115200); Serial.print( "コアで実行されているsetup()関数:"); Serial.println(xPortGetCoreID()); } void loop(){ Serial.print( "loop()関数がコアで実行されています:"); Serial.println(xPortGetCoreID()); }
上記のスケッチをアップロードした後、シリアルモニターを開くと、以下に示すように、両方の機能がcore1で実行されていることがわかります。
上記の観察から、デフォルトのArduinoスケッチは常にcore1で実行されると結論付けることができます。
ESP32デュアルコアプログラミング
Arduino IDEはESP32用のFreeRTOSをサポートし、FreeRTOS APIを使用すると、両方のコアで独立して実行できるタスクを作成できます。タスクは、LEDの点滅、温度の送信など、ボード上で何らかの操作を実行するコードです。
以下の関数は、両方のコアで実行できるタスクを作成するために使用されます。この関数では、優先度、コアIDなどの引数を指定する必要があります。
次に、以下の手順に従って、タスクとタスク関数を作成します。
1.まず、 voidsetup 関数でタスクを作成し ます 。ここでは、2つのタスクを作成します。1つは0.5秒ごとにLEDを点滅させるためのもので、もう1つは2秒ごとに温度を読み取るためのものです。
xTaskCreatePinnedToCore()関数は7つの引数を取ります:
- タスクを実装するための関数名(task1)
- タスクに付けられた任意の名前(「task1」など)
- タスクに割り当てられたスタックサイズ(ワード(1ワード= 2バイト))
- タスク入力パラメーター(NULLにすることができます)
- タスクの優先度(0が最低の優先度)
- タスクハンドル(NULLにすることができます)
- タスクが実行されるコアID(0または1)
次に、xTaskCreatePinnedToCore()関数ですべての引数を指定して、LEDを点滅させるためのTask1を作成します。
xTaskCreatePinnedToCore(Task1code、 "Task1"、10000、NULL、1、NULL、0);
同様に、Task2のTask2を作成し、7番目の引数でコアID1を作成します。
xTaskCreatePinnedToCore(Task2code、 "Task2"、10000、NULL、1、NULL、1);
タスクの複雑さに応じて、優先度とスタックサイズを変更できます。
2.今、私たちが実施していきます Task1code と Task2code 機能を。これらの関数には、必要なタスクのコードが含まれています。私たちの場合、最初のタスクはLEDを点滅させ、別のタスクは温度を取得します。したがって、voidセットアップ関数の外側でタスクごとに2つの別々の関数を作成します。
以下に示すように、0.5秒後にオンボード LED を点滅さ せるTask1code 関数が実装されています。
Void Task1code(void * parameter){ Serial.print( "Task1 running on core"); Serial.println(xPortGetCoreID()); for(;;){//無限ループ digitalWrite(led、HIGH); delay(500); digitalWrite(LED、LOW);遅延(500); } }
同様に、温度をフェッチするための Task2code 関数を実装します。
void Task2code(void * pvParameters){ Serial.print( "Task2 running on core"); Serial.println(xPortGetCoreID()); for(;;){ float t = dht.readTemperature(); Serial.print( "温度:"); Serial.print(t); delay(2000); } }
3.ここでは、 voidループ 関数は空のままになります。 ループ と セットアップ 関数がcore1で実行されることはすでにわかっているので、 voidループ 関数でもcore1タスクを実装できます。
これでコーディングの部分は終わりました。ツールメニューでESP32ボードを選択して、ArduinoIDEを使用してコードをアップロードするだけです。DHT11センサーがESP32のピンD13に接続されていることを確認してください。
これで、以下に示すように、シリアルモニターまたはArduinoIDEで結果を監視できます。
リアルタイムシステムのような複雑なアプリケーションは、ESP32のデュアルコアを使用して複数のタスクを同時に実行することで構築できます。
完全なコードとデモビデオを以下に示します。