Ever feel like you’re riding the Struggle Bus when using the esp8266?
tl;dr
Try a different USB serial adapter.
The Debug
This is the first part of a series on the insanely stupid amount of debugging I had to endure, in order to get started with this magnificent chip.
A lot of people seem to have problems programming it, myself included. There are a lot of documented cases of weird errors showing up, such as a flash failing at 7 or 8%, every time [1] [2] :
While I was getting up to speed on the esp8266, I built at least three programming circuits, and each one failed to upload a program correctly to the chip.
This was extremely irritating and I wasted a ridiculous amount of time trying to figure out what’s going on, whether I was at fault, or the circuit was at fault, or the uploader program was at fault.
I tried adding decoupling capacitors to the 3.3v → ground lines, I tried tying up the RESET and GPIO2 lines.
I tried the NodeMCU flasher, esptool.py
, and esptool-ck
, and none of them worked.
I tried on a Windows machine, on a Mac, and on a Linux machine, again nothing worked.
I tried attaching jumper cables directly between the programming pins and an FTDI serial adapter, and it still froze on upload.
I tried adding a separate 2A regulated power supply, this didn’t help either.
I even tried buying an EEPROM programming clip and seeing if I could write the EEPROM that way, no luck.
The esp8266 has become my white whale, as they say. And I will see it at the gates of Hell, waiting for me with a espcomm_send_command(FLASH_DOWNLOAD_DATA) failed
message.
Or with obtuse responses like:
$ ./esptool.py --baud 115200 --port /dev/cu.usbserial-A50285BI write_flash 0x00000 nodemcu_integer_0.9.6-dev_20150704.bin
Connecting...
Erasing flash...
Took 2.21s to erase flash block
Writing at 0x00008000... (7 %)
A fatal error occurred: Invalid head of packet
$ ./esptool.py --baud 115200 --port /dev/cu.usbserial-A50285BI write_flash 0x00000 nodemcu_integer_0.9.6-dev_20150704.bin
Connecting...
Erasing flash...
Took 2.32s to erase flash block
Writing at 0x00005000... (4 %)
A fatal error occurred: Invalid head of packet
$ ./esptool.py --baud 115200 --port /dev/cu.usbserial-A50285BI write_flash 0x00000 nodemcu_integer_0.9.6-dev_20150704.bin
Connecting...
Erasing flash...
Took 2.28s to erase flash block
Writing at 0x00003c00... (3 %)
A fatal error occurred: Invalid head of packet
$ ./esptool.py --baud 57600 --port /dev/cu.usbserial-A50285BI write_flash 0x00000 nodemcu_integer_0.9.6-dev_20150704.bin
Connecting...
Erasing flash...
Took 2.28s to erase flash block
Writing at 0x00000000... (0 %)
A fatal error occurred: Invalid head of packet
$ ./esptool.py --baud 57600 --port /dev/tty.usbserial-A50285BI write_flash 0x00000 nodemcu_integer_0.9.6-dev_20150704.bin
Connecting...
Erasing flash...
Took 2.17s to erase flash block
Writing at 0x00000000... (0 %)
A fatal error occurred: Invalid head of packet
$ ./esptool.py --baud 230400 --port /dev/tty.usbserial-A50285BI write_flash 0x00000 nodemcu_integer_0.9.6-dev_20150704.bin
Connecting...
Erasing flash...
Took 2.24s to erase flash block
Writing at 0x00008000... (7 %)
A fatal error occurred: Invalid head of packet
$ ./esptool.py --baud 460800 --port /dev/tty.usbserial-A50285BI write_flash 0x00000 nodemcu_integer_0.9.6-dev_20150704.bin
Connecting...
Erasing flash...
Took 2.25s to erase flash block
Writing at 0x00008000... (7 %)
A fatal error occurred: Invalid head of packet
$
It was high time for me to start debugging esptool-ck
, to find out why it was failing, and to see if there were problems I could solve.
I’d tried everything everything, and I was beginning to suspect my crappy, Chinese-knockoff FTDI converter is to blame. It was the one common denominator I thought could not possibly be the problem.
This gave me a good opportunity to mess around with JetBrains’ CLion, since importing esptool-ck
into Xcode turned into a complete and utter clusterfuck. (Way to go, Apple. Why is Xcode such a pain in the ass to import existing files into and set dependencies? Seriously, way too hard.)
After a bit of debugging, I caught esptool-ck
blocking on the tcdrain()
call multiple times when running in multiple CLion lldb debugging sessions. This is interesting, and seems to be a good place to start.
I suspected that OS X might have some issues, so as a start, I modified espcomm.c
to remove calls to tcdrain()
under OS X. The fact that esptool-ck
was unable to exit, when it got stuck in the tcdrain()
pointed to a potential hardware issue with the counterfeit circuit. A genuine device should simply not exhibit problems here.
Another particularly gruesome issue with the crappy knock-off FTDI boards, was that they refused to execute the close()
properly and would actually hang. So the only way to fix the situation was to unplug the counterfeit FTDI board and power cycle the esp8266.
In the end, the problem was with the counterfeit FTDI hardware. Don’t buy this adapter for esp8266 programming, you will totally regret it:
After testing out an adapter using a genuine FTDI chip, all of the programming methods worked just fine.