May 11, 2018

The ESP32 IDF and toolchain

This is an ever growing and developing set of pages as I start to use and learn about the supplied tools.

Setting up the ESP32 IDF and toolchain

I am doing this on an x86_64 Fedora linux system running Fedora 27. First some packages need to be installed. These were necessary packages that were not already installed on my system, you may need others (YMMV).
dnf install pyserial
dnf install gperf
Then we install the IDF (IoT Development Framework). I do this via git. In theory this allows a git pull to keep it up to date. Odds are I will just delete and reclone it as needed, but we will see.
cd /opt
mkdir esp32
cd esp32
git clone --recursive https://github.com/espressif/esp-idf.git
This puts the IDF in /opt/esp32/esp-idf Note that our old friend "esptool" can be found at:
/opt/esp32/esp-idf/components/esptool_py/esptool/esptool.py
We may consider putting it in /usr/local/bin, but we will see.

The toolchain

Information about this (and a link to download it) may be found at: Once it is downloaded, I do things a little differently than the instructions, since I want to keep the IDF and toolchain both in /opt.
cd /opt/esp32
mv ~/Downloads/xtensa-esp32-elf-linux64-1.22.0-73-ge28a011-5.2.0.tar.gz .
tar xzvf xtensa-esp32-elf-linux64-1.22.0-73-ge28a011-5.2.0.tar.gz
This yields the directory /opt/esp32/xtensa-esp32-elf.

Environment variables

I use bash like any sane person these days, so I need to add a few lines to my .bashrc file as follows:
# stuff for ESP32 development
export PATH=/opt/esp32/xtensa-esp32-elf/bin:$PATH
export IDF_PATH=/opt/esp32/esp-idf
I verify that this is right by launching a new terminal window and typing "printenv"; also:
xtensa-esp32-elf-gcc -v
Using built-in specs.
COLLECT_GCC=xtensa-esp32-elf-gcc
COLLECT_LTO_WRAPPER=/opt/esp32/xtensa-esp32-elf/bin/../libexec/gcc/xtensa-esp32-elf/5.2.0/lto-wrapper
Target: xtensa-esp32-elf
Configured with: /builds/idf/crosstool-NG/.build/src/gcc-5.2.0/configure --build=x86_64-build_pc-linux-gnu --host=x86_64-build_pc-linux-gnu --target=xtensa-esp32-elf --prefix=/builds/idf/crosstool-NG/builds/xtensa-esp32-elf --with-local-prefix=/builds/idf/crosstool-NG/builds/xtensa-esp32-elf/xtensa-esp32-elf/sysroot --with-sysroot=/builds/idf/crosstool-NG/builds/xtensa-esp32-elf/xtensa-esp32-elf/sysroot --with-newlib --enable-threads=no --disable-shared --with-pkgversion='crosstool-NG crosstool-ng-1.22.0-73-ge28a011' --disable-__cxa_atexit --enable-cxx-flags='-fno-rtti -ffunction-sections' --with-gmp=/builds/idf/crosstool-NG/.build/xtensa-esp32-elf/buildtools --with-mpfr=/builds/idf/crosstool-NG/.build/xtensa-esp32-elf/buildtools --with-mpc=/builds/idf/crosstool-NG/.build/xtensa-esp32-elf/buildtools --with-isl=/builds/idf/crosstool-NG/.build/xtensa-esp32-elf/buildtools --with-cloog=/builds/idf/crosstool-NG/.build/xtensa-esp32-elf/buildtools --with-libelf=/builds/idf/crosstool-NG/.build/xtensa-esp32-elf/buildtools --enable-lto --enable-target-optspace --without-long-double-128 --disable-libgomp --disable-libmudflap --disable-libssp --disable-libquadmath --disable-libquadmath-support --disable-nls --disable-multilib --enable-languages=c,c++ --disable-libstdcxx-verbose --enable-threads=posix --enable-gcov-custom-rtio
Thread model: posix
gcc version 5.2.0 (crosstool-NG crosstool-ng-1.22.0-73-ge28a011)

Hello World example

This is the standard game in all cases, and I follow the instructions in the linux setup guide.
cd /u1/Projects/Esp32
cp -r $IDF_PATH/examples/get-started/hello_world  .
As instructed, I plug in my device (A Sparkfun ESP32 thing). It is detected as /dev/ttyUSB2.
cd /u1/Projects/Esp32
cd hello_world
make menuconfig
I do as told and navigate to "Serial Flasher Config", edit the device to be /dev/ttyUSB2, and save the configuration. Now I type "make" and it compiles and incredible long list of things, as I record here: The build ends with the following highly instructive message:
To flash all build output, run 'make flash' or:
python /opt/esp32/esp-idf/components/esptool_py/esptool/esptool.py --chip esp32 --port /dev/ttyUSB2 --baud 115200 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect 0x1000 /u1/Projects/Esp32/hello_world/build/bootloader/bootloader.bin 0x10000 /u1/Projects/Esp32/hello_world/build/hello-world.bin 0x8000 /u1/Projects/Esp32/hello_world/build/partitions_singleapp.bin
I type "make flash" and get the following:
 make flash
WARNING: Toolchain version is not supported: 1.22.0-73-ge28a011
Expected to see version: 1.22.0-80-g6c4433a
Please check ESP-IDF setup instructions and update the toolchain, or proceed at your own risk.
WARNING: Toolchain version is not supported: 1.22.0-73-ge28a011
Expected to see version: 1.22.0-80-g6c4433a
Please check ESP-IDF setup instructions and update the toolchain, or proceed at your own risk.
Flashing binaries to serial port /dev/ttyUSB2 (app at offset 0x10000)...
esptool.py v2.3.1
Connecting.....
Chip is ESP32D0WDQ6 (revision 0)
Features: WiFi, BT, Dual Core
Uploading stub...
Running stub...
Stub running...
Configuring flash size...
Auto-detected Flash size: 4MB
Flash params set to 0x0220
Compressed 20592 bytes to 12159...
Wrote 20592 bytes (12159 compressed) at 0x00001000 in 1.1 seconds (effective 151.4 kbit/s)...
Hash of data verified.
Compressed 136736 bytes to 66909...
Wrote 136736 bytes (66909 compressed) at 0x00010000 in 6.2 seconds (effective 177.6 kbit/s)...
Hash of data verified.
Compressed 3072 bytes to 103...
Wrote 3072 bytes (103 compressed) at 0x00008000 in 0.0 seconds (effective 1532.5 kbit/s)...
Hash of data verified.

Leaving...
Hard resetting via RTS pin...
After this, typing "make monitor" yields readable output for a while, then inscrutable junk due to an improper baud rate. Note that Ctrl+] exits the terminal emulator.
make monitor
WARNING: Toolchain version is not supported: 1.22.0-73-ge28a011
Expected to see version: 1.22.0-80-g6c4433a
Please check ESP-IDF setup instructions and update the toolchain, or proceed at your own risk.
MONITOR
--- idf_monitor on /dev/ttyUSB2 115200 ---
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
�ets Jun  8 2016 00:22:57

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
ets Jun  8 2016 00:22:57

rst:0x10 (RTCWDT_RTC_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:5628
load:0x40078000,len:0
load:0x40078000,len:14868
entry 0x40078628
..... junk .....

Sparkfun ESP32 Thing baudrate issue

The IDK assumes a 40 Mhz crystal, and the "thing" uses a 26 Mhz crystal. So the IDK sets a 115200 baud rate and gets 115200 * (26/40) = 74880 baud. This is awkward at best or impossible to specify from picocom or other linux terminal emulators. The right thing to do is to clue in the IDK about the actual crystal frequency and all will be well.

This can be done using "make menuconfig". Select, "Component config" -- "ESP32 specific" -- Main XTAL. The menu lets you select 40 or 26. Selecting 26, then make; make flash; make monitor and everything works fine, just like the WeMOS module below with the 40 Mhz setting.

WeMOS module works fine

Before discovering the crystal frequency option in menuconfig, I confirmed that this was the issue by switching to a WeMOS module I had handy. It apparently uses a 40 Mhz crystal and works fine as follows (all this at 115200):

entry 0x40078628
I (29) boot: ESP-IDF v3.1-dev-961-ga2556229 2nd stage bootloader
I (29) boot: compile time 19:21:04
I (29) boot: Enabling RNG early entropy source...
I (35) boot: SPI Speed      : 40MHz
I (39) boot: SPI Mode       : DIO
I (43) boot: SPI Flash Size : 4MB
I (47) boot: Partition Table:
I (50) boot: ## Label            Usage          Type ST Offset   Length
I (58) boot:  0 nvs              WiFi data        01 02 00009000 00006000
I (65) boot:  1 phy_init         RF data          01 01 0000f000 00001000
I (73) boot:  2 factory          factory app      00 00 00010000 00100000
I (80) boot: End of partition table
I (84) esp_image: segment 0: paddr=0x00010020 vaddr=0x3f400020 size=0x04518 ( 17688) map
I (99) esp_image: segment 1: paddr=0x00014540 vaddr=0x3ffb0000 size=0x021b4 (  8628) load
I (105) esp_image: segment 2: paddr=0x000166fc vaddr=0x40080000 size=0x00400 (  1024) load
0x40080000: _iram_start at /opt/esp32/esp-idf/components/freertos/xtensa_vectors.S:1685

I (111) esp_image: segment 3: paddr=0x00016b04 vaddr=0x40080400 size=0x08750 ( 34640) load
I (134) esp_image: segment 4: paddr=0x0001f25c vaddr=0x400c0000 size=0x00000 (     0) load
I (135) esp_image: segment 5: paddr=0x0001f264 vaddr=0x00000000 size=0x00dac (  3500)
I (142) esp_image: segment 6: paddr=0x00020018 vaddr=0x400d0018 size=0x115dc ( 71132) map
0x400d0018: _flash_cache_start at ??:?

I (180) boot: Loaded app from partition at offset 0x10000
I (180) boot: Disabling RNG early entropy source...
I (180) cpu_start: Pro cpu up.
I (184) cpu_start: Starting app cpu, entry point is 0x40081034
0x40081034: call_start_cpu1 at /opt/esp32/esp-idf/components/esp32/cpu_start.c:224

I (0) cpu_start: App cpu up.
I (195) heap_init: Initializing. RAM available for dynamic allocation:
I (201) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (207) heap_init: At 3FFB29A0 len 0002D660 (181 KiB): DRAM
I (213) heap_init: At 3FFE0440 len 00003BC0 (14 KiB): D/IRAM
I (220) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (226) heap_init: At 40088B50 len 000174B0 (93 KiB): IRAM
I (232) cpu_start: Pro cpu start user code
I (250) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
Hello world!
This is ESP32 chip with 2 CPU cores, WiFi/BT/BLE, silicon revision 0, 4MB 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.
ets Jun  8 2016 00:22:57

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:5628
load:0x40078000,len:0
load:0x40078000,len:14868
entry 0x40078628
......................
And the unit restarts over and over in this fashion.

Try the blink demo also

My WeMOS board ain't got no LED, so we will have to try this with the Sparkfun thing.
cp -r $IDF_PATH/examples/get-started/blink  .
cd blink
make menuconfig (as above, set ttyUSB2)
make
make flash
And a blue LED next to the pin labelled "5" begins to blink slowly. I guess I would call that success. The GPIO number is set to 5 in the menuconfig - this value can be changed or inspected under the "Example Configuration" submenu.

A peek at the supplied Makefile

It consists of two lines, as follows:
PROJECT_NAME := hello-world
include $(IDF_PATH)/make/project.mk
project.mk is a 579 line monster that in turn includes other Makefiles.
Feedback? Questions? Drop me a line!

Tom's Computer Info / tom@mmto.org