Author Archives: Peter Gheude

Installing esptool on macOS and programming an ESP8266 “Witty”


This is a walkthrough of how I installed the Python-based esp8266/esp32 serial bootloader utility esptool on my Apple iMac – a 27-inch, Mid 2011 running macOS High Sierra – and used it to program an ESP8266 “Witty” module with esp8266/Basic. Python 3 was installed and a Python “venv” virtual environment was created to contain the python libraries used by esptool. As the version of macOS used does not include a driver for the “Witty” module’s interface adapter a third-party driver was installed.

Device driver for the witty’s interface

The witty uses a CH34x USB/serial chipset which macOS High Sierra (10.13) and earlier doesn’t have a native driver for. After connecting it to the iMac the witty’s (USB) serial port was not found. A driver for the CH34x chipset was found on GitHub at
The latest version (1.5) of this driver is released as a signed package, however the signer of the package is not an “identified developer”. The security controls in this macOS haven’t been disabled so installing this package requires manual confirmation of its installation. That is done in System Preferences->Security & Privacy->[General] as shown here:

The driver was installed by following the installation instructions from the GitHub page – including the “force quit” suggestion to avoid having to reboot. After installing this driver for the CH34x the witty’s serial adapter appeared as /dev/tty.wchusbserialfd140

Installing Python 3

macOS comes with Python 2 installed as a “system” utility. Rather than risk interfering with the native python installation (by inadvertently introducing incompatible packages, etc.) I opted to install Python 3 from I downloaded and ran the macOS 64-bit installer. The installation completed without incident.

Creating a “virtual environment” with venv

Not knowing where my Python development future might be headed I decided to use the “virtual environment” (venv) facility available in Python to keep any configuration changes and installed packages local to the project (to avoid running into configuration/package conflicts later with other Python projects). I created and activated a virtual environment named esp32-env within a project directory (named ESP32), updated its pip utility and installed esptool:

iMac:Documents ws$ mkdir ESP32 && cd ESP32
iMac:ESP32 ws$ python3 -m venv esp32-env
iMac:ESP32 ws$ . esp32-env/bin/activate
(esp32-env) iMac:ESP32 ws$ pip install --upgrade pip
(esp32-env) iMac:ESP32 ws$ pip install --upgrade esptool

To verify that esptool was installed correctly I ran it without any arguments:

(esp32-env) iMac:ESP32 ws$ v2.8
usage: esptool [-h] [--chip {auto,esp8266,esp32}] [--port PORT] [--baud BAUD] [--before {default_reset,no_reset,no_reset_no_sync}]
               [--after {hard_reset,soft_reset,no_reset}] [--no-stub] [--trace] [--override-vddsdio [{1.8V,1.9V,OFF}]]
                ... v2.8 - ESP8266 ROM Bootloader Utility

positional arguments:
                         Run esptool {command} -h for additional help
     load_ram            Download an image to RAM and execute
     dump_mem            Dump arbitrary memory to disk
     read_mem            Read arbitrary memory location
     write_mem           Read-modify-write to arbitrary memory location
     write_flash         Write a binary blob to flash
     run                 Run application code in flash
     image_info          Dump headers from an application image
     make_image          Create an application image from binary files
     elf2image           Create an application image from ELF file
     read_mac            Read MAC address from OTP ROM
     chip_id             Read Chip ID from OTP ROM
     flash_id            Read SPI flash manufacturer and device ID
     read_flash_status   Read SPI flash status register
     write_flash_status  Write SPI flash status register
     read_flash          Read SPI flash content
     verify_flash        Verify a binary blob against flash
     erase_flash         Perform Chip Erase on SPI flash
     erase_region        Erase a region of the flash
     version             Print esptool version
 optional arguments:
   -h, --help            show this help message and exit
   --chip {auto,esp8266,esp32}, -c {auto,esp8266,esp32}
                         Target chip type
   --port PORT, -p PORT  Serial port device
   --baud BAUD, -b BAUD  Serial port baud rate used when flashing/reading
   --before {default_reset,no_reset,no_reset_no_sync}
                         What to do before connecting to the chip
   --after {hard_reset,soft_reset,no_reset}, -a {hard_reset,soft_reset,no_reset}
                         What to do after is finished
   --no-stub             Disable launching the flasher stub, only talk to ROM bootloader. Some features will not be available.
   --trace, -t           Enable trace-level output of interactions.
   --override-vddsdio [{1.8V,1.9V,OFF}]
                         Override ESP32 VDDSDIO internal voltage regulator (use with care)

Testing esptool with the witty

To test that esptool was working with my witty I tried its flash_id command. This worked without having to specify the serial port device. It confirmed the size of the flash – 4MB.

(esp32-env) iMac:ESP32 ws$ flash_id v2.8
Found 2 serial ports
Serial port /dev/cu.wchusbserialfd140
Detecting chip type... ESP8266
Chip is ESP8266EX
Features: WiFi
Crystal is 26MHz
MAC: ec:fa:bc:0c:e7:68
Uploading stub...
Running stub...
Stub running...
Manufacturer: 20
Device: 4016
Detected flash size: 4MB
Hard resetting via RTS pin...

As a further test I read out the entire flash, which still held the original “as-shipped” program, and saved it to a file:

(esp32-env) iMac:ESP32 ws$ read_flash 0 0x400000 tmp.bin v2.8
Serial port /dev/tty.wchusbserialfd140
Detecting chip type... ESP8266
Chip is ESP8266EX
Features: WiFi
Crystal is 26MHz
MAC: ec:fa:bc:0c:e7:68
Uploading stub...
Running stub...
Stub running...
4194304 (100 %)
4194304 (100 %)
Read 4194304 bytes at 0x0 in 399.4 seconds (84.0 kbit/s)...
Hard resetting via RTS pin...

A hexdump examination of the saved file appeared reasonable – it was not all 0x00 or 0xff and included relevant-looking strings.

Uploading the esp8266/Basic image with esptool

The 4MB esp8266/basic image was downloaded from:
The flashing instructions linked on the GitHub site are only relevant for the Windows flashing tool and don’t require, or indicate, the starting address in the flash to program the image to. After confirming the correct starting address with Peter Gheude – 0x0, esptool was executed with the write_flash command to write the image starting at address zero:

(esp32-env) iMac:ESP32 ws$ write_flash 0 ~/Downloads/ESP8266Basic.cpp.bin v2.8
Serial port /dev/tty.wchusbserialfd140
Detecting chip type... ESP8266
Chip is ESP8266EX
Features: WiFi
Crystal is 26MHz
MAC: ec:fa:bc:0c:e7:68
Uploading stub...
Running stub...
Stub running...
Configuring flash size...
Auto-detected Flash size: 4MB
Compressed 523104 bytes to 346130...
Wrote 523104 bytes (346130 compressed) at 0x00000000 in 30.9 seconds (effective 135.4 kbit/s)...
Hash of data verified.

Hard resetting via RTS pin...

Once the flash programming completed and the esptool had reset the witty, a WiFi access point was available with an ID created from the prefix string “ESP” and what looked as though it should have been the MAC address of the witty, however the actual id seen when browsing for its WiFi access point was: ESPEE:FA:BC:0C:E7:68

After connecting my iPhone’s WiFi to that access point the esp8266/Basic “home” page could be opened in the web browser at the URL

Further ESP8266/ESP32 resources on this site can be found here.

Links to downloads/source code

CH34x device driver for macOS:
Python 3: