こちらのサイトでは主に ESP-IDF 環境での記事を紹介して来ました。
今回は、VSCode の PlatformIO拡張 + Arduino フレームワークの構成でプロジェクトを作ってみます。
やや動作が遅いのですがプログラムをステップ実行したり、変数の値をデバッガ上で確認することができたりします。
Arduino IDEの環境でしか動作させたことがない方には、ぜひ体験して頂きたい内容となっています。
JTAGによるデバッグは複雑なプログラムの動作を追いかけるのに便利です。
まずプロジェクトをつくった後でArduinoのプログラム構成について簡単に説明します。
この記事は JTAG でデバッグすることを前提にして書いています。
環境構築については こちら をご覧になってください。
投稿時の開発環境を記しておきます。
PC:
Windows10 OS
開発ボード :
ESP32-DevKitCーVE
(Soc : ESP32-D0WD-V3)
デバッガー(H/W):
FT2232D
デバッガー (S/W) :
Visual Studio Code + PlatformIO + Arduino Framework
Arduinoとは
元々はマイコンボードを指すようですが、そのプログラムをつくる環境(Arduino IDE)のソフトウェアを言うこともあるようです。
実は私、Arduino IDE を触ったことがありません。
皆さまの方が良くご存じだと思いますので紹介はこの程度にしておきます。
プロジェクトをつくる
VSCodeで、もし使っていたプロジェクトを開いていたら、File – Close Folder して閉じておきます。
その後にVSCodeからPlatformIOをOpenします。
以下の内容でプロジェクトを新規に作成します。
Name : ESP32A-Arduino
Board : Espressif ESP32 Dev Module
Framework : Arduino Framework
Name : ESP32A の “A” は Framework (Arduino Framework)の頭文字を示しています。
(後から見てわかるように、Arduinoを使うことを明示しています)
platformio.ini に以下の4行を追加して、 Ctrl + s で保存しておきます。
COM[8]の8の部分はデバイスマネージャーのポート(COMとLPT)で Silicon Labs CP210x から始まるCOMの番号を記述します。
(今回のコードでは不要ですが、プログラムのアップロードやモニターを使う場合に必要です)
debug_tool = minimodule
upload_port = COM[8]
monitor_port = COM[8]
monitor_speed = 115200
デバッグする
PlatformIOでプロジェクトをつくると、プログラムのスケルトン(骨組み)がつくられます。
VSCodeメニューから Run – Start Debugging を選択するか F5キーを押します。
この環境は非常に便利なのですが、動作が遅いのが欠点です。
(ステップ実行できる等の便利な機能と引き換えに、動作が遅いことは我慢してください)
そうすると、以下のフローディングウィンドウが出てきます。
左から
continue(F5):実行
Step Over(F10):関数を実行
Step Into(F11):関数の中に入って実行
Step Out(Shift+F11):関数の外まで実行
Restart(Ctrl+Shift+F5):リスタート
Stop(Shift+F5):停止
の動作になります。
その他にブレークしたい行にカーソルをあててF9キーを押すと行番号の左に赤い〇がつきブレークポイントを貼ることができます。
もう一度F9キーを押すと解除します。
カッコの中はショートカットキーで覚えておくと便利です。
しばらく待つと、水色のステータスバー(ウィンドウの一番下の帯の部分)がオレンジ色にかわります。
無事にここまでたどり着くとデバッグができる状態になります。
(もしうまく行かない場合には、環境構築などについて見直してみてください)
もうひとつの main.cpp
この状態で loopTaskWDTEnabled = false; のところにカーソルが停止しています。
プログラムがここで停止している状態です。
私たちがつくったプロジェクトの src フォルダの下に main.cpp がつくられるのですが、これとは別のmain.cppがあり、プログラムはそのソースコード上で停止しています。
その2行下に、以下のコードが書かれています。
xTaskCreateUniversal(loopTask, "loopTask", getArduinoLoopTaskStackSize(), NULL, 1, &loopTaskHandle, ARDUINO_RUNNING_CORE);
ESP32のプログラムはRTOS上で動いていて、この関数はスレッド(タスク)をつくるためのものです。
第一引数のloopTaskがマルチスレッドで動作する関数になります。
カーソルをスクロールして、今停止しているカーソルの少し上の方を見てみると以下のコードが書かれています。
void loopTask(void *pvParameters)
{
setup();
for(;;) {
#if CONFIG_FREERTOS_UNICORE
yieldIfNecessary();
#endif
if(loopTaskWDTEnabled){
esp_task_wdt_reset();
}
loop();
if (serialEventRun) serialEventRun();
}
}
この部分がマルチスレッドで動作することになります。
この部分のコードを簡単にすると、以下のようなイメージで、setup()が1度だけ実行された後、loop()が繰り返し呼ばれます。
loopTask()
{
setup();
while(true) {
loop();
}
}
プロジェクトツリーの srcフォルダ下の main.cpp にある setup()とloop()がこれらの関数になります。
setup()の行にカーソルをあててF9キーを押すか、行番号の左側をクリックしてブレークポイントを貼ります。
そしてF5キーを押してプログラムを実行します。
少し待つと、setup()のところでプログラムが停止します。
次にF11キーを押して関数の中に入っていきます。
すると src>main.cpp にある setup() に来ます。
中身がないので、F10キーを押して関数内をぬけます。
loopTask()に戻ってくるので、今度は loop()の行の左側をクリックしてブレークポイントを貼ります。
そしてF5キーを押してプログラムを実行します。
少し待つと、loop()のところでプログラムが停止します。
次にF11キーを押して関数の中に入っていきます。
すると src>main.cpp にある loop() に来ます。
loopTask()の中を見ればわかるように、setup()は1回だけ実行されて、その後loop()は繰り返し実行されます。
ということで、setup()にはペリフェラルの初期化処理など1度だけ実行すればよさそうなコードを書き、loop()には繰り返し実行する処理を書けば良いことがわかります。
プログラムを動作させながらsetup(), loop()が動作するしくみを理解できました。
Arduino IDEでは確認できないプログラムの中を度覗くことができるのでデバッグ環境として一度使ってみてはいかがでしょうか。