Sunday 15 April 2018

ESP8266 contention during programming

To put the ESP8266 into serial programming mode it needs to be reset with GPIO 2 held high, GPIO 15 low and GPIO 0 low. On the other hand to start it executing flash GPIO 0 needs to be high during reset. I have seen lots of circuits on the web, for example the NodeMCU board and Adafruit's  Huzzah board that pull GPIO 0 to ground with a switch and / or with DTR from a USB to serial adapter.  Reset can be driven from RTS to automate programming with the Arduino IDE.

A lesser known fact is that when the ESP8266 goes into programming mode it outputs a 26 MHz clock on GPIO 0 with considerable drive strength and fast edges. Shorting this to ground or DTR is not good at all as it causes massive contention and generates a lot of noise. This can cause programming to fail unless there is some hefty decoupling on the supply rail. The simple solution is to put a resistor between GPIO 0 and whatever is pulling it low. Here is what the signals look like with 10K between GPIO 0 and DTR from an FTD1232.

The oscillation doesn't show up at full amplitude with a slow time base but I can assure you it is full swing with plenty of overshoot due to not being terminated. You can see a bit of it coupled onto the TX line and this is when it is through 10K. Imagine how noisy things get when it is fighting with the FTD1232 DTR line and winning.

Another lesser know fact is that when the ESP8266 is in reset its GPIO lines get pulled up internally. You can see with 10K pulling it down the GPIO line only goes down to about 0.7V during reset.

Before reset my application is driving GPIO 0 low. RTS goes low a short time before DTR, so it briefly becomes an input and gets pulled to 3.3V by DTR before it pulls it low again. This explains the spike on the left.

I haven't seen any circuits published that avoid this contention.


  1. Can you confirm that the value to use is 10K between GPIO0 and ground?

  2. Yes 10K to ground would put it into programming mode. Normally this would be via a switch with a pull up so it runs when the switch is not pressed or connected to DTR for auto programming. Again with a pull up so when the programmer is disconnected it runs.