Introduction
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
https://github.com/adrianmihalko/ch340g-ch34g-ch34x-mac-os-x-driver
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 https://www.python.org/ 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$ esptool.py esptool.py 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}]] {load_ram,dump_mem,read_mem,write_mem,write_flash,run,image_info,make_image,elf2image,read_mac,chip_id,flash_id,read_flash_status,write_flash_status,read_flash,verify_flash,erase_flash,erase_region,version} ... esptool.py v2.8 - ESP8266 ROM Bootloader Utility positional arguments: {load_ram,dump_mem,read_mem,write_mem,write_flash,run,image_info,make_image,elf2image,read_mac,chip_id,flash_id,read_flash_status,write_flash_status,read_flash,verify_flash,erase_flash,erase_region,version} 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 esptool.py 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 esptool.py 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$ esptool.py flash_id esptool.py v2.8 Found 2 serial ports Serial port /dev/cu.wchusbserialfd140 Connecting.... 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$ esptool.py read_flash 0 0x400000 tmp.bin esptool.py v2.8 Serial port /dev/tty.wchusbserialfd140 Connecting.... 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:
https://github.com/esp8266/Basic/blob/NewWebSockets/Flasher/Build/
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$ esptool.py write_flash 0 ~/Downloads/ESP8266Basic.cpp.bin esptool.py v2.8 Serial port /dev/tty.wchusbserialfd140 Connecting.... 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. Leaving... 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 http://192.168.4.1
Further ESP8266/ESP32 resources on this site can be found here.
Links to downloads/source code
CH34x device driver for macOS:
https://github.com/adrianmihalko/ch340g-ch34g-ch34x-mac-os-x-driver
Python 3:
https://www.python.org/
esptool:
https://github.com/espressif/esptool
esp8266/Basic:
https://github.com/esp8266/Basic/blob/NewWebSockets/Flasher/Build/
END