VSCode+PlatformIOを使ったESP32のデバッグ開発環境

#マイコンはブレークポイントを使ってデバッグできない？
そう思っていた時期が私にもありました。
全てのマイコンとはいいませんが、JTAG規格に対応したマイコンは、ブレークポイントを用いたデバッグが可能です。M5Stackで一層人気を博しているESP32ですが、嬉しいことにJTAGに対応しています。
**つまり、ESP32はブレークポイントをはってデバッグできるんです!!**

# 前提
以下については解説を省略します。記事を参考に構築してください。
Windows10基準の説明ですが、macでも後述のドライバの設定以外は同じです。

* ESP32のセットアップ
 * [ESP32(ESP-WROOM-32)でLチカ (WindowsでArduino IDE使用)](https://qiita.com/rukihena/items/6a904368700eb1c7d2a3)
* PlatformIOの環境構築
 * [PlatformIO IDE for VSCode でESP32のプログラム開発](http://kunsen.net/2018/07/28/post-618/)

#JTAGとは
[JTAG](http://www.tokudenkairo.co.jp/jtag/whatisjtag.html)はシリアルポート経由でIC内部の回路と通信するための規格です。以下の5種類の信号線を用いて、マイコンのクロックの制御や、内部状態を知ることができます。ただしTRSTはピンがない場合もあります。

|信号名|用途|
|:-:|:-:|
|TDI|データ入力|
|TDO|データ出力|
|TCK|クロック|
|TMS|状態制御|
|TRST|リセット|

![esp32-breakout-board-pinout-My-Electronics-Lab.jpg](https://qiita-image-store.s3.amazonaws.com/0/167138/be5bbb96-b329-42ec-bc1c-7df654804fbc.jpeg)

#必要なもの
・[ESP32](http://akizukidenshi.com/catalog/g/gM-11647/)
当然デバッグするマイコンは必須です。モジュールそのままでははんだ付け等が必要になるので、[ブレークアウト基盤](http://akizukidenshi.com/catalog/g/gK-11755/)やPCとUSBで繋げるだけで利用できる[開発用基盤](http://akizukidenshi.com/catalog/g/gM-11819/)の購入をおすすめします。
<img src="http://akizukidenshi.com/img/goods/C/M-11647.jpg" width=250px>
・[FT2232H MiniModule](https://jp.rs-online.com/web/p/interface-development-kits/7300142/)
今回の主役のデバッグアダプタ（後述）です。残念ながら秋月電子での取扱はありません。[RSコンポーネンツ](https://jp.rs-online.com/web/)から購入できます。
<img src="https://media.rs-online.com/t_large/F7300142-02.jpg" width=250px>
・[USB Mini-B](http://akizukidenshi.com/catalog/g/gC-07606/)
何故か未だにマイコン界隈でたまに使われるMini-Bケーブル。全部microにして。。。
<img src="http://akizukidenshi.com/img/goods/L/C-07606.jpg" width=250px>
・[[オス-メス]のジャンパーワイヤー](http://akizukidenshi.com/catalog/g/gC-08936/)
・[[メス-メス]のジャンパーワイヤー](http://akizukidenshi.com/catalog/g/gP-03476/)
メス-メスのジャンパーワイヤーは無くてもいいですが、合ったほうが何かと便利かもしれません。
<img src="http://akizukidenshi.com/img/goods/L/C-08936.jpg" width=250px><img src="http://akizukidenshi.com/img/goods/C/P-03476.JPG" width=250px>

#デバッグの仕組み
マイコンのデバッグは、**「GDB、OpenOCD、デバッグアダプタ」**の三種の神器を用いて実行されます。一般的にPCにはマイコンのデバッグのための適切な種類の電気信号を供給する機能はありません。その役割を担うハードウェアがデバッグアダプタです。その通信の規格にJTAGが使用されているものを用います。OpenOCDは、デバッグアダプタとGDBをつなぐソフトウェアです。OpenOCDはデバッグアダプタに操作用の信号を送信し、TCPポートでデバッグアダプタとの通信内容をGDBに伝えます。GDBからOpenOCDを操作するためのコマンドはtelnetを通して送信されます。
![OpenOCD](https://docs.espressif.com/projects/esp-idf/en/latest/_images/jtag-debugging-overview.jpg)

* 参考
 * [OpenOCD](http://openocd.org/doc/html/About.html#OpenOCD-Web-Site)
 * [Espressifのデバッグ用公式ドキュメント](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/jtag-debugging/)

# デバッグアダプタの準備
## FT2232H MiniModuleの配線
FT2232H MiniModuleを前提とします。その他のFT2232Hのブレークアウト基盤などを用いている方は利用マニュアルなどをご参考ください。
FT2232H MiniModuleは**実はそのままUSBでPCとつなげても正しく認識されません。**（ここで結構泣かされました）以下の配線をする必要があります。[メス-メス]のジャンパーワイヤー等が必要になります。

* **電源の供給**

USB電源供給の場合（基本こっち）

|電源|供給先|
|:-:|:-:|
|VBUS(CN3-1)|VCC(CN3-3)|

外部電源供給の場合

|電源|供給先|
|:-:|:-:|
|外部5V電源|VCC(CN3-3)|

* **供給された電源を3.3Vで使用するための配線**

|電源|供給先|
|:-:|:-:|
|V3V3(CN2-1,3,5)|VIO(CN2-11,21及びCN3-12,22)|

<img src="https://qiita-image-store.s3.amazonaws.com/0/167138/a8cca113-5f5f-41d1-3980-cf67537e2d3c.png" width=400px>

この状態でPCとUSBで接続してください。シリアルコントローラーが2つ認識されればOKです。
![シリアル](https://community.platformio.org/uploads/default/original/2X/2/269e2dde187b98a1cb6e1994aa5a1749b3e635e7.PNG)

## ドライバの設定 for windows10
FT2232Hは2チャンネルのデバッグアダプタです。1つは一般的なプログラムの書き込み等に利用されるUARTで、2つめがJTAG用のチャンネルです。このままではPCがどっちのCOMポートをUART、またはJTAGに使用すればよいかわかりません。そのため、[Zadig](https://zadig.akeo.ie/)というドライバを置き換えるソフトウェア（インストール無しで使用できます）で一方のドライバをJTAG用のドライバに置き換えます。
FT2232Hを接続した状態でZadigを起動し、「Options->List All Devices」をチェックします。すると、リスト内に「FT2232H MiniModule」、または「Dual RS232-HS」というドライバが表示されます。「Interface 0」のものを選択し、「Replace Driver」をクリックします。（画像はすでに置き換え済みなので「Reinstall Driver」になってます）
![image.png](https://qiita-image-store.s3.amazonaws.com/0/167138/a34ab8ec-409b-e3a0-81d8-ad3146986138.png)
ドライバ置き換え後、FT2232Hを再接続するとUARTのみがCOMポートとして認識され、COMポートのドライバのプロパティからハードウェアIDのVIDとPIDかそれぞれ0403、6010になっていることが確認できればOKです。
<img src="https://qiita-image-store.s3.amazonaws.com/0/167138/e1d37b89-4a33-fe1d-d9a4-dd839e59ac29.png" width=350px><img src="https://qiita-image-store.s3.amazonaws.com/0/167138/01749a11-df5d-9bf7-7ee6-32609bb6678e.png" width=350px>

## ドライバの設定 for mac

私は手持ちのmacで試したことが無いのですが、下記の記事でmacでの環境構築を実践されています。

* [ESP32をFT232HでJTAGデバッグする時にハマったこと](https://qiita.com/bishi/items/c753f2b24f46ad162936)

# デバッグアダプタとESP32の接続
以下のように配線します。

* **UARTの配線**

|FT2232H|信号名|ESP32|
|:-:|:-:|:-:|
|BD0(CN3-26)|RX|RXD0|
|BD1(CN3-25)|TX|TXD0|
|GND(CN3-2,4)|GND|GND|

* **JTAGの配線**

|FT2232H|信号名|ESP32|
|:-:|:-:|:-:|
|AD1(CN2-10)|TDI|GPIO12|
|AD2(CN2-9)|TDO|GPIO15|
|AD0(CN2-7)|TCK|GPIO13|
|AD3(CN2-12)|TMS|GPIO14|
|AC2(CN2-20)|RST|EN|
|GND(CN2-2,4,6)|GND|GND|

結構カオスになります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/167138/babbf3c3-8e5d-d247-c92e-e19656214907.png)

この段階でシリアルポートを開いて、ESP32とのUARTでの通信ができていればセットアップが無事完了したことになります。（書き込みモード等で起動して「waiting for download」の文字が受信されればOK）

# PlatformIOは凄い
これでハードウェア側の全ての準備が整いました。本来であれば、この後下記のような面倒な手順をふむことになります（未調査）

* OpenOCDのソースをダウンロード
* OpenOCDのバイナリをビルド
* OpenOCD用の設定ファイルを作成（大分ややこしい）
* OpenOCD起動
* GDB起動
* デバッグ開始

しかし、PlatformIOを用いればF5を押せば終わります。
まずPlatformIOでESP32の新規プロジェクトを作成します。後でplatformio.iniを修正すれば変更できるので、Frameworkはどっちでもいいです。PlatformIOの操作は冒頭の[PlatformIOの環境構築](http://kunsen.net/2018/07/28/post-618/)を参考にしてください。

* Board：Espressif ESP32 Dev Module
* Framework：Arduino または ESP-IDF

<img src="https://qiita-image-store.s3.amazonaws.com/0/167138/64eaf700-6766-fd9f-051e-626ab1cd8a10.png" width=450px>

platformio.iniを定義します。FrameworkにArduinoを使用しない場合は他のものを指定してください。

```ini
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200
upload_speed = 921600
debug_tool = minimodule
```

main.cppにとりあえずのテストコードを作成し、プログラムをESP32に書き込みます。（2秒周期でLEDを点滅させるプログラムです）

```cpp

#include <Arduino.h>

void setup() {
    Serial.begin(115200);
    Serial.println("start");
    pinMode(4, OUTPUT);
}

boolean on = true;
unsigned long current = 0;
void loop() {
    if (millis() - current < 2000) {
        return;
    }
    on ? digitalWrite(4, HIGH) : digitalWrite(4, LOW);
    on = !on;
    current = millis();
    return;
}
```

好きなところにブレークポイントをはり、ESP32が起動している状態でF5を押してください。うまくいっていればブレークポイントで止まります。当然変数の値等もWatch式やマウスホバーで確認できます。もし、変な場所で止まる、止まっているが画面に反映されない等の状態になったら、ブレークポイントを一度削除し、再度配置して「続行」するとうまくいったりします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/167138/97d5c92f-1aea-448a-224f-b4864890a251.png)

# エラーが出た場合
ブレークポイントで止まらない等、うまくいかない場合はJTAGのピンの接続などを確認してください。
以下のようなエラーが出た場合は、次に示す手順でOpenOCDの設定ファイルを修正してください。このエラーはFTDIの最新ドライバではFT2232Hのデバイス表示名が「FT2232H MiniModule」になっているが、PlatformIOが自動で作成するOpenOCDの設定ファイルのデバイス表示名がFTDIの古いドライバの「Dual RS232-HS」で作成されることにより発生します（多分）。

```
Open On-Chip Debugger 0.10.0-dev (2018-06-04-09:51)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
adapter speed: 20000 kHz
esp32 interrupt mask on
force hard breakpoints
Info : tcl server disabled
Info : telnet server disabled
Error: no device found
Error: unable to open ftdi device with vid 0403, pid 6010, description ‘Dual RS232-HS’, serial ‘’ at bus location '’
.pioinit:10: Error in sourced command file:
Remote communication error. Target disconnected.: No error.
```

* **OpenOCD設定ファイルのドライバ表示名修正手順**
 * 下記のディレクトリのバックアップを作成（念の為）
 * %HOMEPATH%/.platformio/packages/tool-openocd-esp32/share/openocd/scripts/interface
 * Zadigで表示されるドライバ表示名を書き留めます（多分「FT2232H MiniMoule」）
 * ディレクトリ配下の全ファイルに対し、エラーで表示されているドライバ表示名（「Dual RS232-HS」）をgrepでZadigで表示されたドライバ表示名（「FT2232H MiniModule」）に置換します

![image.png](https://qiita-image-store.s3.amazonaws.com/0/167138/e2d63a9e-09ff-771c-a6d0-e10b3992ebb4.png)

# 最後に
そもそもマイコンでデバッグ必要なほど複雑なプログラム書くの・・・？