ESP32開発環境をつくってデバッグしてみる
espressifのESP32ページを見て、ESP32デバッグ環境を作り、テストしてみた。(結論的にはここだけでは足らず)
準備
開発環境(ESP-IDF, OpenOCD)
ここからToolchainのダウンロード。ESP-IDFをインストールすると、デバッグ環境(OpenOCDなど)も同時にインストールされるようだ。
ターゲットとなるESP32モジュール
事情があってマイナーなモジュールであるFireBeetle。
デバッグ用ボード
espressifサイトのJTAG DebuggingからOpenOCDサイトに飛ぶ。FT2332HかFT232Hが選択肢。入手しやすかったFT232Hを搭載するボード(秋月電子で購入)を使用。
プロジェクト”hello_world”
開発環境インストール後に、Step 5. Start a Projectに遷移する。ここの手順に従って、”hello_world”プロジェクトをターゲットとする。ESP-IDF Command Prompt (cmd.exe)を開き、作業を進めていく。
ソースコード(as isです)
/* Hello World Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
# include <stdio.h>
# include "freertos/FreeRTOS.h"
# include "freertos/task.h"
# include "esp_system.h"
# include "esp_spi_flash.h"
void app_main()
{
printf("Hello world!\n");
/* Print chip information */
esp_chip_info_t chip_info;
esp_chip_info(&chip_info);
printf("This is ESP32 chip with %d CPU cores, WiFi%s%s, ",
chip_info.cores,
(chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
(chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "");
printf("silicon revision %d, ", chip_info.revision);
printf("%dMB %s flash\n", spi_flash_get_chip_size() / (1024 * 1024),
(chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");
for (int i = 10; i >= 0; i--) {
printf("Restarting in %d seconds...\n", i);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
printf("Restarting now.\n");
fflush(stdout);
esp_restart();
}
つまづき1
手順に従って、Step 7. Configureにある、”idf.py set-target esp32”をタイプするが実行できず。ここの情報によると、IDFのバージョンによっては、これは不要らしい。
つまづき2
同じStep 7. Configureにある、”idf.py menuconfig”を実行。この中の”Serial flasher config”を選ぶが、ESP32モジュールと接続されているポート(COM5など)が見えない。とりあえず、無視して進めてみた。
Build -> Flash -> Monitor
Step 8. Build the Projectにある、プロジェクトのBuild、モジュールへの書き込み(Flash)、実行状況の確認(Monitor)を行った。
C:\Users\xyz\esp\hello_world>idf.py build
(メッセージ省略)
C:\Users\xyz\esp\hello_world>idf.py -p COM5 flash
(メッセージ省略)
C:\Users\xyz\esp\hello_world>idf.py -p COM5 monitor
(最初のメッセージ省略)
Hello world!
This is ESP32 chip with 2 CPU cores, WiFi/BT/BLE, silicon revision 1, 2MB external flash
Restarting in 10 seconds...
Restarting in 9 seconds...
Restarting in 8 seconds...
Restarting in 7 seconds...
Restarting in 6 seconds...
Restarting in 5 seconds...
Restarting in 4 seconds...
Restarting in 3 seconds...
Restarting in 2 seconds...
Restarting in 1 seconds...
Restarting in 0 seconds...
Restarting now.
まずは成功。
デバッグ
espressifのJTAGのページに沿って進める。OpenOCDはインストール済み、JTAG Adapter(デバッグ用ボード:FT232H)は選択済み。
つまづき3
FT232H搭載ボードがPower Onせず。調べると、USB給電するには、JP3 Jumperをショートする必要がある。
OpenOCD実行
実行時にInterfaceやBoardを指定する必要がある。私の環境下では、下記ディレクトリに
C:\Users\xyz\.espressif\tools\openocd-esp32\v0.10.0-esp32-20190313\openocd-esp32\share\openocd\scripts>dir /a:d
2020/08/08 10:07 <DIR> .
2020/08/08 10:07 <DIR> ..
2020/08/08 10:07 <DIR> board
2020/08/08 10:07 <DIR> chip
2020/08/08 10:07 <DIR> cpld
2020/08/08 10:07 <DIR> cpu
2020/08/08 10:07 <DIR> fpga
2020/08/08 10:07 <DIR> interface
2020/08/08 10:07 <DIR> target
2020/08/08 10:07 <DIR> test
2020/08/08 10:07 <DIR> tools
があり、
openocd -f interface/ftdi/um232h.cfg -f board/esp-wroom-32.cfg
を実行する。
つまづき4
そのまま上記を実行したところ、
Error: libusb_open() failed with LIBUSB_ERROR_NOT_SUPPORTED
とエラー表示。ここなど(日本語による情報も複数サイトにあり)から、OpenOCD実行にはCOMポートではなくUSBポートが使われる必要があるらしい。Zadigというツールで対応する。

"Single RS232-HS"を選択してUSBドライバに置き換える。すると、デバイスマネージャーで、

USBのところでデバッグボードが認識されている。
デバッグボードとターゲットとの接続
espressifサイトのConfigure Hardwareに従う。

ENピンの接続が必要と記載されたサイト情報もあったが、私の環境では上記でOKであった。
つまづき5
openocd -f interface/ftdi/um232h.cfg -f board/esp-wroom-32.cfg
を実行したが、何度も、
Error: JTAG scan chain interrogation failed: all ones
が出てしまった。調べると、デバッグボードがブレッドボードにきちっとささっていなかっただけ(デバッグボードのピンが短すぎた)。別の方法で、きっちりと接続を行い、このエラーは解消。上記openocdの成功実行時には、次のように表示される。
C:\Users\xyz\esp\hello_world>openocd -f interface/ftdi/um232h.cfg -f board/esp-wroom-32.cfg
Open On-Chip Debugger v0.10.0-esp32-20190313 (2019-03-13-09:57)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
adapter speed: 20000 kHz
Info : Configured 2 cores
esp32 interrupt mask on
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : ftdi: if you experience problems at higher adapter clocks, try the command "ftdi_tdo_sample_edge falling"
Info : clock speed 20000 kHz
Info : JTAG tap: esp32.cpu0 tap/device found: 0x120034e5 (mfg: 0x272 (Tensilica), part: 0x2003, ver: 0x1)
Info : JTAG tap: esp32.cpu1 tap/device found: 0x120034e5 (mfg: 0x272 (Tensilica), part: 0x2003, ver: 0x1)
Info : esp32: Debug controller 0 was reset (pwrstat=0x5F, after clear 0x0F).
Info : esp32: Core 0 was reset (pwrstat=0x5F, after clear 0x0F).
Info : esp32: Debug controller 1 was reset (pwrstat=0x5F, after clear 0x0F).
Info : esp32: Core 1 was reset (pwrstat=0x5F, after clear 0x0F).
Info : Detected debug stubs @ 3ffb2970 on core0 of target 'esp32'
Info : Listening on port 3333 for gdb connections
Info : esp32: Debug controller 0 was reset (pwrstat=0x5F, after clear 0x0F).
Info : esp32: Core 0 was reset (pwrstat=0x5F, after clear 0x0F).
Info : esp32: Debug controller 1 was reset (pwrstat=0x5F, after clear 0x0F).
Info : esp32: Core 1 was reset (pwrstat=0x5F, after clear 0x0F).
Info : esp32: Debug controller 0 was reset (pwrstat=0x5F, after clear 0x0F).
Info : esp32: Core 0 was reset (pwrstat=0x5F, after clear 0x0F).
Info : esp32: Debug controller 1 was reset (pwrstat=0x5F, after clear 0x0F).
Info : esp32: Core 1 was reset (pwrstat=0x5F, after clear 0x0F).
shutdown command invoked
Info : Restore debug stubs @ 3ffb2970 on core0 of target 'esp32'
Warn : Flash driver of esp32.flash does not support free_driver_priv()
Warn : Flash driver of irom does not support free_driver_priv()
Warn : Flash driver of drom does not support free_driver_priv()
CUIでデバッグ
大昔の人間なので、gdbはCUIでしか使ったことがない。なので、espressifサイトのCommand Lineを選択。別のコマンドプロンプト(ESP-IDF Command Prompt (cmd.exe))を実行する。
cd ~/esp/hello_world
この配下で、次の内容のgdbinitという名称の設定ファイルをつくる。
target remote :3333
set remote hardware-watchpoint-limit 2
mon reset halt
flushregs
thb app_main
c
gdbinitファイルを指定して、下記のようにgdb実行する。
C:\Users\xyz\esp\hello_world>xtensa-esp32-elf-gdb -x gdbinit build/hello-world.elf
GNU gdb (crosstool-NG esp-2019r2) 8.1.0.20180627-git
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=i686-host_w64-mingw32 --target=xtensa-esp32-elf".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from build/hello-world.elf...done.
0x400e2caa in esp_pm_impl_waiti ()
at C:/Users/undeux3/esp-idf/components/esp32/pm_esp32.c:484
484 asm("waiti 0");
JTAG tap: esp32.cpu0 tap/device found: 0x120034e5 (mfg: 0x272 (Tensilica), part: 0x2003, ver: 0x1)
JTAG tap: esp32.cpu1 tap/device found: 0x120034e5 (mfg: 0x272 (Tensilica), part: 0x2003, ver: 0x1)
esp32: Debug controller 0 was reset (pwrstat=0x5F, after clear 0x0F).
esp32: Core 0 was reset (pwrstat=0x5F, after clear 0x0F).
Target halted. PRO_CPU: PC=0x5000004B (active) APP_CPU: PC=0x00000000
esp32: Core 0 was reset (pwrstat=0x1F, after clear 0x0F).
esp32: Debug controller 1 was reset (pwrstat=0x5F, after clear 0x0F).
esp32: Core 1 was reset (pwrstat=0x5F, after clear 0x0F).
Target halted. PRO_CPU: PC=0x40000400 (active) APP_CPU: PC=0x40000400
Hardware assisted breakpoint 1 at 0x400d3a80: file ../main/hello_world_main.c, line 17.
Target halted. PRO_CPU: PC=0x400D3A80 (active) APP_CPU: PC=0x400E2CAA
[New Thread 1073438372]
[New Thread 1073436472]
[New Thread 1073441028]
[New Thread 1073428764]
[New Thread 1073412788]
[New Thread 1073413528]
[New Thread 1073429896]
[Switching to Thread 1073434572]
Thread 1 hit Temporary breakpoint 1, app_main () at ../main/hello_world_main.c:17
17 {
(gdb)
すると、コードの最初の部分で止まる。デバッグ開始。for文の中でブレークポイントを設けてみる。行番号35。
(gdb) l
12 #include "esp_system.h"
13 #include "esp_spi_flash.h"
14
15
16 void app_main()
17 {
18 printf("Hello world!\n");
19
20 /* Print chip information */
21 esp_chip_info_t chip_info;
(gdb) l
22 esp_chip_info(&chip_info);
23 printf("This is ESP32 chip with %d CPU cores, WiFi%s%s, ",
24 chip_info.cores,
25 (chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
26 (chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "");
27
28 printf("silicon revision %d, ", chip_info.revision);
29
30 printf("%dMB %s flash\n", spi_flash_get_chip_size() / (1024 * 1024),
31 (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");
(gdb) l
32
33 for (int i = 10; i >= 0; i--) {
34 printf("Restarting in %d seconds...\n", i);
35 vTaskDelay(1000 / portTICK_PERIOD_MS);
36 }
37 printf("Restarting now.\n");
38 fflush(stdout);
39 esp_restart();
40 }
(gdb) b 35
Breakpoint 2 at 0x400d3ae7: file ../main/hello_world_main.c, line 35.
(gdb) i b
Num Type Disp Enb Address What
2 breakpoint keep y 0x400d3ae7 in app_main
at ../main/hello_world_main.c:35
(gdb) c
”c”で継続すると、行番号35で止まる(ブレークする)。ここでは変数”i”の値を”10”から”5”に変更して継続する(”c”)。
Continuing.
Note: automatically using hardware breakpoints for read-only addresses.
Target halted. PRO_CPU: PC=0x400D3AE7 (active) APP_CPU: PC=0x400E2CAA
Thread 1 hit Breakpoint 2, app_main () at ../main/hello_world_main.c:35
35 vTaskDelay(1000 / portTICK_PERIOD_MS);
(gdb) p i
$1 = 10
(gdb) p i=5
$2 = 5
(gdb) c
Continuing.
Target halted. PRO_CPU: PC=0x400D3AE7 (active) APP_CPU: PC=0x400E2CAA
Thread 1 hit Breakpoint 2, app_main () at ../main/hello_world_main.c:35
35 vTaskDelay(1000 / portTICK_PERIOD_MS);
(gdb) c
Continuing.
Target halted. PRO_CPU: PC=0x400D3AE7 (active) APP_CPU: PC=0x400E2CAA
Thread 1 hit Breakpoint 2, app_main () at ../main/hello_world_main.c:35
35 vTaskDelay(1000 / portTICK_PERIOD_MS);
(gdb) c
(以下継続)
このとき、別のコマンドプロンプト(ESP-IDF Command Prompt (cmd.exe))の”idf.py -p COM5 monitor”の表示は次のようになっていた。
Hello world!
This is ESP32 chip with 2 CPU cores, WiFi/BT/BLE, silicon revision 1, 2MB external flash
Restarting in 10 seconds...
Restarting in 4 seconds...
Restarting in 3 seconds...
Restarting in 2 seconds...
変数”i”を無理やり変更した結果のとおりの表示となっている。
結果
成功!