ESP32 - Toolchain setup on OSX
Tomer Weller 1 Contributor
April 07, 20169 Versions
Not Featured in any Journals


@article{ESP32Toolcha2016, title={ESP32 - Toolchain setup on OSX}, author={Tomer Weller}, year={2016}, note={version: 57a22c6f5a4037b8e01ad324}, publisher={PubPub}, }


Tomer Weller. (2016). ESP32 - Toolchain setup on OSX. PubPub, [https://www.pubpub.org/pub/esp32-osx-setup] version: 57a22c6f5a4037b8e01ad324


Tomer Weller. "ESP32 - Toolchain setup on OSX". PubPub, (2016). [https://www.pubpub.org/pub/esp32-osx-setup] version: 57a22c6f5a4037b8e01ad324


Tomer Weller. "ESP32 - Toolchain setup on OSX". PubPub, (2016). [https://www.pubpub.org/pub/esp32-osx-setup] version: 57a22c6f5a4037b8e01ad324
Setting up an OSX toolchain for building and deploying ESP32 firmware

I've recently received an ESP32 test unit from Espressif. ESP32 is the successor for the very popular ESP8266, an extremely cheap and capable WiFi System on a chip. This version includes, beyond WiFi, also Bluetooth, BLE, a dual processor and much more.
This guide should get you up and running with building ESP32 firmware and deploying it using OSX El Capitan. Official documentation is currently only available for Linux and I personally prefer developing on my own system and not on a virtual machine.
For the time being, the only way to build firmware for ESP32 is using espressif's ESP32 RTOS SDK which is based on FreeRTOS. This means writing some hardcore C code. If you're looking for Arduino programming you should probably wait for espressif's Arduino Core project to support this chip.

1. Heads up

  • You should be comfortable with the command line and the OSX Disk Utility (a new disk partition needs to be created for the build process)
  • For the sake of speed this tutorial uses breadboard prototyping. If you're working on a serious project I highly recommended milling your own PCB board.
  • Throughout this guide I make some opinionated choices regarding naming and directory structure. Feel free to change these but make sure you're persistent.

2. Hardware check-list

  • ESP32 - I'm using the ESP-WROOM-03 module that has been distributed to beta testers (along with a breakout board and headers).
  • 3.3V power supply. I'm using a breadboard power supply like this but any stable source will do. I would refrain from using the USB port power - those might not be able to account for bursts in usage.
  • Breadboard and some jumper wires.
  • FTDI serial cable.

3. Software dependencies

You wil also need a custom version of crosstool-ng which we will configure and build later in this tutorial.

4. Wiring & Sanity Check

Wire things up:
  • VCC (ESP32) - VCC (POWER)
  • EN (ESP32) - VCC
  • GND (ESP32) - GND (POWER)
  • TX (ESP32) - RX (FTDI)
  • RX (ESP32) - TX (FTDI)
  • GND (ESP32) - GND (FTDI)
Note : you should probably put a capacitor on VCC-GND to protect from power surges. I did not do so because (a) my power supply gives a pretty steady current and (b) laziness
Connect your FTDI cable, while the ESP32 is not powered, and open a serial monitor using miniterm.py (a part of the pysrial package).
> miniterm.py /dev/{ftdi_port} 115200 #your FTDI port should look something like /dev/tty.usbXXXX
--- Miniterm on /dev/tty.usbserial-FTH9KZ63: 115200,8,N,1 ---
--- Quit: Ctrl+]  |  Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
Powerup the chip. you should see some readable data printing in the terminal and at some point:
Start app OK!
Congratulations. Your ESP32 is alive.
Note : to reset the chip you don't have to power cycle it. You can simply disconnect and reconnect the EN PIN. A wise man might choose to put a button there to function as a physical reset button.

5. Setup Crosstool-ng

crosstool-ng is the tool you'll be using to build the toolchain for building our esp32 firmware. (yes, we need a tool to build a tool to build software, life's a bitch). We're going to build it ourselves because the esp32 requires a non-standard version.
Install build dependencies:
> brew tap Homebrew/homebrew-dupes
> brew install wget git autoconf automake gperftools bison flex texinfo libtool ncurses gawk expat binutils
> brew install gnu-sed --with-default-names
Crosstool-ng also requires a case-sensitive filesystem which, by default, OSX isn't. the solution: using Disk Utility create a new 5GB (anything above 4GB will do) partition, call it crosstool-ng and format it to OSX Extended (Case-sensitive, Journaled).
Now we can pull crosstool-ng from github and build. I prefer having all of my development related resources in a ~/dev folder so I symlink the library from the new partition to ~/dev.
> cd /Volumes/crosstool-ng # our newly created case-sensitive partition
> git clone -b esp108-1.21.0 git://github.com/jcmvbkbc/crosstool-NG.git
> ln -s /Volumes/crosstool-ng ~/dev/crosstool-NG/ # personal preference
> cd ~/dev/crosstool-NG/
> ./bootstrap && ./configure --prefix=`pwd` && make && make install 
> ./ct-ng xtensa-esp108-elf 
> ./ct-ng build # this take a while
To make our newly built toolchain accessible system-wide we need to add it to the system PATH variable.
export PATH=~/dev/crosstool-NG/builds/xtensa-esp108-elf/bin:$PATH
Note: this step will need to be repeated every time you open a new terminal session. To avoid it, you can add this line to your ~/.bash_profile file

6. Setup Workspace

Creating an ESP32 workspace directory and pulling the SDK from github:
> mkdir ~/dev/esp32-workspace
> cd ~/dev/esp32-workspace
> git clone https://github.com/espressif/ESP32_RTOS_SDK.git
> mkdir ESP32_BIN
Making the SDK directories available system wide through environment variables:
> export BIN_PATH=~/dev/esp32-workspace/ESP32_BIN
> export SDK_PATH=~/dev/esp32-workspace/ESP32_RTOS_SDK
Again, this step will need to be repeated every time you open a new terminal session. To avoid it, you can add these lines to your ~/.bash_profile file

7. Build firmware

Building a firmware from the project template
> cp -R ESP32_RTOS_SDK/examples/project_template .
> cd project_template
> make clean 
> make
At the end of the make process you'll see something like
Generate related files successully in folder /Users/weller/dev/esp32-workspace/ESP32_BIN
user.ota------------------>(used for OTA)

8. Deploy firmware

To deploy the firmware we must put the ESP32 in download mode. this is done by pulling down the GPIO0 and GPIO2 pins. That means that in addition to our previous connections, we need to connect:
  • GPIO0 - GND
  • GPIO2 - GND
To ensure Download Mode is on you can connect your terminal application and reset the chip (either by powering off and on or disconnecting and reconnecting the ENABLE PIN). You should see something like this:
> miniterm.py /dev/tty.usbserial-FTH9KZ63 115200
--- Miniterm on /dev/tty.usbserial-FTH9KZ63: 115200,8,N,1 ---
--- Quit: Ctrl+]  |  Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---

 ets Jul  5 2015,rst cause:1, boot mode:(13)

	 _stack_sentry: 0x3fffe1d0,	__stack: 0x40000000,
     _bss_start: 0x3fffcd48,	_bss_end: 0x3fffe1d0,
     _data_start: 0x3fffc000,	_data_end: 0x3fffc864
Download mode is on. Close the serial terminal session.
Now, the esptool can be used to flash the images that comprise the firmware :
> cd ~/dev
> python esptool32.py -p /dev/tty.usbserial-FTH9KZ63 -b 115200 write_flash -ff 40m -fm qio -fs 2m  0x0 ESP32_RTOS_SDK/bin/boot.bin 0x04000 esp32-workspace/ESP32_BIN/irom1.bin 0x40000 esp32-workspace/ESP32_BIN/irom0_flash.bin 0xFC000 ESP32_RTOS_SDK/bin/blank.bin
Return to regular boot mode by disconnecting the GPIO and GPIO2 pins, start a serial terminal session and reset the chip. The startup sequence includes several automatic restarts which give the impression that the chip is stuck in a loop but after about 5 seconds you'll see:
ESP32 RTOS SDK: 1.1.0(42d074b) compiled @ Dec 18 2015 19:39:49
SDK version:1.1.0(42d074b)
mode : softAP(62:01:94:00:00:f5)
dhcp server start:(ip:,mask:,gw:
add if1
ht20 ,2412
bcn 100
Great Success!

9. Test custom code

To assure yourself that you're actually deploying your own firmware and I'm not yanking your chain, make a small change to the code. for example. in project_template/user/user_main.c after this line:
printf("SDK version:%s\n", system_get_sdk_version());
add this line:
printf("*** HELLO ESP32 ***\n");
Repeat steps 8 and 9, when resetting the module you should see:
ESP32 RTOS SDK: 1.1.0(42d074b) compiled @ Dec 18 2015 19:39:49
SDK version:1.1.0(42d074b)
*** HELLO ESP32 ***
mode : softAP(62:01:94:00:00:f5)
dhcp server start:(ip:,mask:,gw:
add if1
ht20 ,2412
bcn 100
Great Success!

10. Now what?

Read the API documentation on the ESP32 forums (Documentation > ESP32_RTOS_SDK API Reference) and start building stuff. Everything is quite new and documentation is sparse. I will try to link some code examples as soon as possible.
Feel free to comment on any issues or add resources. PubPub is awesome.


Show Threads
There is also an error in export SDK_BIN=~/dev/esp32-workspace/ESP32_BIN. Should be BIN_PATH.
Thanks. Fixed! Was your build succesful?
Build succeeds, but the eagle.app.v7.out step takes ages on a max spec MacBook Pro.
Does your implementation get stuck on the following line for ages?
xtensa-esp108-elf-gcc -L/esptools/esp32/workspace/ESP32_RTOS_SDK/lib -nostdlib -T/esptools/esp32/workspace/ESP32_RTOS_SDK/ld/eagle.pro.v7.ld -Wl,--no-check-sections -u call_user_start -Wl,-static -Wl,--start-group -lc -lgcc -lhal -lm -lcrypto -lfreertos -llwip -lmain -lnet80211 -lphy -lpp -lrtc -lwpa user/.output/eagle/debug/lib/libuser.a sample_lib/.output/eagle/debug/lib/libsample.a -Wl,--end-group -o .output/eagle/debug/image/eagle.app.v7.out
Build succeeds, but takes ages.