Getting Started with ESP 01 Programming: How to use an Arduino Uno to program an ESP01. Although there are 4 GIPOs at the connector, find out the ONLY One you can Use Easily! Why is the 8 pin connector badly designed?

ESP 01 Programming is made a little tricky, in that unlike all other Arduino boards, there is no built-in USB to Serial converter and there is no on-board power regulator chip.

This is done to save space, and the idea is that you use an external serial programmer to program the ESP01.

The image above shows a ESP01S (left) - You can identify it as it has a single white box to the right and below the antenna - this is the blue LED (it's off), and ESP01 (right) - has four components in the same place.

A common error you will get during programming is:=
"A fatal error occurred: Failed to connect to ESP8266: Timed out waiting for packet header"

TIP: Find out the reason and (partial) solution to why you get that error (and how to get round it) - on this page.

ESP01 Programming

Warning: Actually Programming this board is ultra tricky!
See Troubleshooting below.

How to program an ESP01 using an Arduino Uno
You need to be able to see the data sent from the ESP01 (to check, that while you're sitting there twiddling your thumbs, the ESP01 actually got the message to start doing something!).

You can do this with the Uno RX and TX LEDs or use an oscilloscope.

Getting this to program is a real pain! But information on this page should help!

Alternatively use an ESP8266 with built in Serial chip and reset circuit.

Programming hardware

For programmingy ou can do one of the following:

  • Use an external FTDI serial adaptor (but adjust for 3V3),
  • Use a separate programming board,
  • Use an Uno as a programmer (easy 3V3 operation)!

The interesting method used here is to use a Arduino Uno as a programmer for your ESP01. You could use any Arduino board as the programmer as it is used as a serial adaptor i.e. only the serial connections from the on-board USB interface connect to the target (ESP-01).

Warning: This device must only be operated at 3V3.
Do not use 5V with the ESP01 -you will blow it up!

In this tutorial, we will cover the basics of ESP 01 programming through a simple example using the Arduino IDE and an Arduino Uno board. By the end, you'll understand the key concepts needed to begin developing your own interactive and connected ESP 01-based creations.

ESP01 pinout

ESP01 pinout with GPIO1 and GPIO3

What is the ESP 01?

Because it has no extras on board (with minimal pinout), the ESP 01 is highly affordable. It is actually the cheapest way to make a WiFi connected unit.

The only down side is that you do not get a voltage regulator so powering them is difficult - in a design you will want either an block adaptor and voltage regulator, or a 3V3 switcher from mains.

The ESP 01 is a the smallest WiFi board you can get, based around the ESP8266 chip. It lets you easily connect projects to WiFi networks but only provides 2GPIO pins for use. In many cases this is more than enough especially for simple on/off control.

Note: With careful design you can use two more GPIO (see below).

Despite its small size, the ESP 01 module is still powerful because it uses the ESP8266 chip with built-in TCP/IP networking capabilities and 32-bit RISC CPU. It runs on 3.3V and communicates over UART (serial) interface, making it compatible with common microcontrollers like the Arduino.

Note: There are two types of ESP01 (ESP01 and ESP01S). Find out the differences between them (and chips fitted) in that link.

How many Usable pins?

There is really only one easy to use pin: GPIO2 and a slightly more difficult to use GPIO0.

How many pins can you use on the ESP01?

In fact there are 4 usable I/O pins but there are constraints on three of them. Three of the GPIO pins are required during programming. The only usable GPIO pin that has no constraints is GPIO2.

Here is a list of constraints on the GPIO pins

Free for user use - No constraints.
Must be held low for programming  - in all circuits -(this is a dedicated input that indicates Flash Mode when held low). Must be held high during boot (or reset) in your circuit.
Used as serial RX pin during ESP 01 programming. If you unplug the ESP01 then and insert it into your circuit then you can use it as a normal I/O
Used as serial TX pin during ESP 01 programming. If you unplug the ESP01 then and insert it into your circuit then you can use it as a normal I/O

These constraints apply during ESP 01 programming so you either use circuitry that does not interfere with the signal levels during programming or - the easier way - remove the board from your circuit after programming and plug it into your target system!

Control GPIO0

The more tricky one is GPIO0 - that must be held high during boot, since it is a dedicated input that indicates "Enter Flash Mode". If it is held low during power up the chip will enter Flash Programming Mode.

So add a pull-up resistor in your circuit (or use ESP01S) and ensure the external circuit does not pull it low until after boot. The easy way - make it an output (which is active after boot - it will be an input during boot by default and a pull-up - attached on the ESP01S, but not the ESP01 - will ensure it does not enter programming mode).

Note: ESP01 has a 12k pull-up on GPIO0 whereas ESP01 does not.

What is the CH_PD pin?

The pin CH_PD stands for CHip Power Down. Some people also call it the Chip Enable pin (chip is on when at 3V3 and off when at 0V), Holding it high allows normal operation whereas when it is low the chip is set to low power mode. Add your own pull-up in your circuit or use an ESP01S.

For the ESP01S a 12k pull-up holds this high for you. For the ESP01 (older) you have to add your own pull-up.

Note: ESP01 has a 12k pull-up on CH_PD whereas ESP01 does not.

What is the RST pin?

This is the chip ReSeT pin. You pull it low (then high) to reset the chip. If you want to program the chip hold GPIO1 low and the reset the chip. Add your own pull-up in your circuit or use an ESP01S.

On the ESP01S a 12k pull-up holds this high for you. For the ESP01 (older) you have to add your own pull-up.

Note: ESP01 has a 12k pull-up on RST whereas ESP01 does not.

Details of the Uno Rx Tx circuit

While developing the circuit I noticed that even when the Uno is held in reset the voltage at the RX pin was 5V. We really don't want 5V applied to the ESP01.

The Rx, Tx part of the schematic is shown below. On the left is the USB chip and on the right is the ATmega328p. To the far right is the Uno connector.

Uno Rx Tx schematic
So between USB chip (left side) and the 328pins is one single 1k resistor each for Rx and Tx paths. The Arduino Uno pin connections directly attach to the ATmega328p. The 1k resistors protect the USB chip so that if the USB chip output high, and you pull the pin low, limited current can flow.

The following diagrams show reset for UBS and Uno:
Uno USB reset circuit

Reset for the USB chip is entirely separate and only goes to an ICSP connector.

Uno reset circuit showing DTR signal through C5 to reset pin of the 328p chip (see this "Arduino ISP" page for how it operates), and to the connectors:

Uno 328p reset circuit
It means holding the reset line for the 328p low, resets the 328p but the USB chip still outputs 5V to the Rx pin as it is not reset.

You can't reset the USB chip anyway as it must operate the serial lines - the problem is that when not active it drives 5V on the Arduino Rx line (pin 0). The TXD1 signal from the USB chip drives the RX line into the 328p.

Solving the Rx Tx problem.

The problem is one of nomenclature.

Uno Rx Tx schematic

When thinking about the Uno the Uno RXD input (Arduino pin 0) receives data from the USB chip (USBTX pin name TXD1, signal name M8RXD), and when you use the Uno Rx, it is an input at Arduino pin 0.

When thinking about the USB chip to program an external ESP 01, the signal connected to the UNO Rx is an output from the USB chip (USBTX pin is TXD1, signal name M8RXD).

In fact for ESP 01 programming:
  • Uno RX is USBTX,
  • Uno TX is USBRX.
The solution is therefore to non-intuatively Not swap Uno Rx and Uno Tx when programming the ESP01; connect Rx to Rx, and Tx to Tx. This because we need the "USB chip operation" not the Uno centric operation!

Note: This was only discovered after connecting the circuit - and shows how useful it is to check everything before you plug in your target board.

Note: This is true for any Arduino module that has on board serial chip.

Solving the next TX problem

I did notice this before - the voltage at Arduino pin 0 was a bit low (with external voltage drop divide -1k, 2k) but pushed on anyway.

Uno Rx Tx schematic

With the output from the TXD1 line (labelled M8RXD) - it has an in-series 1k resistor. With the original circuit that drops the voltage to get from 5V to 3V3, I originally had at the output at the Arduino pin going to a 1k and 2k divider.

This would work if that other serial resistor (RN4B) was not there! However we can use the existing 1k and lose the 1k in the external circuit. This will give the correct drop down voltage, giving the desired voltage divider, using 1k (RN4B), 2k(external) . The external 2k will form a voltage divider with RN4B above to give max 3V3 at Arduino pin 0.

Warning: This 1k resistor may not be present on other types of Arduino board - in that case use an external 1k, 2k voltage divider at the output.

Programming the ESP 01

To program the ESP 01, you need to hold GPIO0 low and do a reset. This is why external boards use a toggle switch and a push button: so you can hold GPIO0 low and then blip the reset to enter Flash programming mode.

The key point for the schematics below is that programming of the Arduino Uno is bypassed; all it is really doing is using the other chip on the Uno board that handles the serial USB to Serial RS232 interface (Tx and Rx). This is why the ATMega328p is held in reset (so that its pins are set as inputs for non interference of Rx and Tx pins).

The other point about the ESP01 is that it must only use 3V3 and that is the reason for the drop down potential divider (R1 (now the on board 1k RN4B), R2). It also shows use of the internal 3V3 regulator from the Uno to power the ESP01.

Note: The available power will only be sufficient for programming. In use the ESP01 can use 100's of mA. If you use WiFi it may work for testing but could be unreliable. Use a higher current source 3V3 supply for reliable operation.

ESP 01 programming schematic

The following circuit shows the three pull-up resistors that are not included on the ESP 01 board so you have to add them externally as shown here:

ESP 01 programming circuitNote: Observe the RESET connection on the Uno.
Observe that RX and TX are Not swapped intentionally (here's why).

Warning: For the Uno you must use RX and TX signals as shown above.

The above circuit diagram will work with both ESP-01 and ESP-01S but the following one is a bit easier as it uses less components.

ESP 01S programming schematic

The following circuit shows the easier circuit for ESP 01S programming. You don't need the three pull-ups as they are already on the ESP01S board:

ESP 01s programming circuit
Note: Observe the RESET connection on the Uno.
Observe that RX and TX are Not swapped intentionally (here's why).

Warning: For the Uno you must use RX and TX signals as shown above.

How to enter flash programming mode

  1. Hold GPIO1 low (toggle switch SW1).
  2. Blip RST low (push button, then release) - or cycle the power.

Using a DIP adaptor

The problem with the 8 pin IDC connector is that it is not breadboard friendly so you could either use flying dupont wires or create/buy an adaptor. I bought one. Now, the next problem is that the IDC is not polarised - meaning you can get the connections completely wrong (by 180 degrees = magic smoke)!

Warning: Connect the ESP01 the right way round or get smoke!

IDC adaptor engineering lesson

Actually there is a very good design lesson here. If you observe the connector and then rotate it 180 degrees. Yep, you really do get magic smoke - you will destroy the ESP01 because ESP01 VCC is connected to GND, and ESP GND is connected to VCC - exactly what you don't want!

ESP01 connector pins showing BAD symmetrical VCC and GND

For a real "engineered" design the VCC and GND connections should never be placed so that they can be symmetrically opposite. Basically put Tx on pin2, Vcc on pin8 (Rx is pin1) - GND is on pin7. That way when the connector is rotated wrongly you get power applied to signal wires and not the power supply of the ESP8266 i.e. it would not blow up.

Warning: Don't put the ESP01 the wrong way round.

Lets say you swapped connections for VCC and Tx (as above) - for all new ESP01 board designs, then if you accidentally rotate 180 degrees you would be applying VCC to Rx, and GND to Tx = no effect.

Note This is not a problem just for the adaptor, it is a problem that can happen for any ESP01 that you plug into any board designed to hold the ESP01!

The other solution is to use proper IDC connectors and not just pins - you can get IDC plug and adaptor sockets with a notch/and matching tab, so you could not physically insert them the wrong way round.

Get the orientation right

You have to be able to get the pins matched up so, here's the back and front images of the adaptor. If unsure, buzz out where GND and TXD are located and fit accordingly - your board may be different!

ESP01 DIP adaptor backESp01 DIP adaptor front

TXD is bottom left:

ESP01 pin adaptor connections

This is the correct way to insert the ESP 01 for programming.

ESP01 in DIP adaptor for programming

Warning: Don't put the ESP01 the wrong way round.

Once you have setup the circuit to match the schematic check the voltages are what you expect at the connector before plugging in the ESP 01 to program it.

Programming the ESP01 using An Uno

Steps for programming the ESP01 using an Arduino Uno:

  1. Install the ESP8266 board package in the Arduino IDE. This adds ESP8266 board support to the IDE.
  2. Select the correct ESP8266 board in the Tools > Board menu. Search for and use "Generic ESP8266".
  3. Connect the ESP-01 to the Arduino Uno as outlined above. The Uno will communicate with the ESP-01 over serial to upload code.
  4. Open/write your ESP8266 sketch/code in the Arduino IDE. Make sure to include WiFi and ESP8266 libraries as needed.
  5. Select the correct serial port that the Uno is using in Tools > Port.
  6. Blip the reset button in your circuit.
  7. Click the upload button to program the ESP-01. The Arduino Uno acts as a serial-to-USB converter and programmer in this process.
  8. The ESP-01 will reset and run your uploaded code. You can monitor serial output on the Arduino IDE serial monitor.
So in summary, the Arduino Uno provides the programming interface between the ESP-01 module and computer/Arduino IDE through its serial port functionality.

Troubleshoot IDE and the Uno

A message you might get is this:

Compilation error: ESP8266WiFi.h: No such file or directory

You might get this message even though you have installed the library - the library is not the problem!

When you use the Uno for ESP 01 programming, the IDE does not really operate as you want; it interrogates the board and thinks it is the Uno (it is, but you are bypassing it).

The key point here is to first select the port that the Arduino Uno is located at, and then switch to the real target board you want to program (since the Uno is used as a serial driver only - you are not using the Uno as the target board!).

The Arduino IDE will forget this between sessions so follow along with the screen shots below to get the Uno and ESP8266 working as you need:

1. Select the Arduino Uno and port

Select Arduino Uno port in IDE

2. Use Board Selector

Now click "Select other board and port..." (see image above).

Select board and port Arduino IDE

You can see that the correct port is selected. Now type in "generic" in the "Search Board" box.

3. Switch to Generic ESP8266

Selecct generic eps8266 in arduino ide boards selector

Select Generic ESP8266 Module and keep the original port selection. Click OK.

4.Check that you are setup for the ESP8266

At the top of the IDE you should see this; meaning that the Uno is now bypassed and you can successfully program the ESP8266 without a library warning!

Arduino ide shows bypassed Uno for ESP8266

Simple Sketch Examples

WiFi connection example

The following sketch is a simple one that connects to WiFi and reports the IP address assigned if successful.

Now open the Arduino IDE and select the board as "Generic ESP8266 Module" and the correct serial port. If you are between sessions the IDE can forget so use the trouble shooting checklist above to setup the Uno for ESP8266 programming. Now continue programming.

We will use an example sketch from the ESP8266 WiFi library to connect the ESP 01 to a WiFi network and print its IP address. Copy and paste the code below, add your own WiFi SSID and password fields, then upload it.

#include <ESP8266WiFi.h>

const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";

void setup() {
  Serial.begin(74880); // This allows you to see ESP01 start data.
  Serial.println("\nESP 01 Starting WiFi test...");
  WiFi.begin(ssid, password);
  while(WiFi.status() != WL_CONNECTED) {
  Serial.print("Connected to WiFi network with IP Address: ");

void loop() {}

TIP: Using a serial baud rate of 74880 lets you see ESP8266 serial messages (from  the bootloader) as well as your own - it's useful to see what's going on.

If uploading is successful, the ESP 01 will connect to WiFi and print its IP address back over the serial monitor. This demonstrates how easily the powerful ESP8266 chip inside can be programmed to connect to wireless networks using the Arduino IDE environment.

Working with GPIO

The ESP 01 provides 2 GPIO (if you have the ESP01S) then GPIO2 is connected to an on board blue LED, if not add an external LED and limit resistor (1k).

There are two programmable pins on the ESP01 & ESP01S that you can configure as either digital inputs or outputs to interface with sensors, actuators, and other hardware. The two available GPIOs that are attached to the connector are GPIO0 and GPIO2. However GPIO0 must be held high during boot so it's easier to use GPIO2.

Here is an example of how to control and write to pin GPIO2:

#define LED_PIN 2

void setup() {
  pinMode(LED_PIN, OUTPUT);

void loop() {
  digitalWrite(LED_PIN, HIGH);  
  digitalWrite(LED_PIN, LOW);

Combined Web And GPIO example

Although you can use the above code standalone, here's an example of combining both Web and GPIO operations. In addition an extra LED is controlled from GPIO0. Note also the non blocking timing which allows asynchronous LED flashing.

#include <ESP8266WiFi.h>

#define LEDPIN 2
#define LEDPIN_ 0

const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";

void setup() {

  Serial.begin(74880); // This allows you to see ESP01 start data.
  Serial.println("\nESP 01 Starting WiFi test...:LED1:");


  digitalWrite(LEDPIN, LOW);
  digitalWrite(LEDPIN_, LOW);
  WiFi.begin(ssid, password);
  while(WiFi.status() != WL_CONNECTED) {
    for(int i=0;i<3;i++ ) {
      digitalWrite(LEDPIN, HIGH);
      digitalWrite(LEDPIN, LOW);
  Serial.print("Connected to WiFi network with IP Address: ");

static long timewas = millis(),timewas_ = millis();
static byte LEDtog =0, LEDtog_=0;
#define TOGTIME 300
#define TOGTIME_ 500

void loop() {

  if (millis()-timewas>TOGTIME) {
    digitalWrite(LEDPIN, LEDtog ? HIGH : LOW );
  if (millis()-timewas_>TOGTIME_) {
    digitalWrite(LEDPIN_, LEDtog_ ? HIGH : LOW);

How could you use TX, RX and GPIO0

During programming TX is an output from the ESP01 and RX is an input to the ESP01, but after that they are fair game.

The key is to attach circuits that do not interfere with the RX and TX signals, if you keep the programmer attached, and the easiest way to do that is to make your circuit be inputs. That means do not attach circuits that generate signals but only ones that receive signals.

For instance you could make RX and TX, I2C signals (it is unlikely that the correct signals sequence would make the attached I2C device react. Or you could attach LEDs (as long as the load is not too great).

Alternatively, if you unplug the ESP01 from the programmer and put it into your own circuit you can use the TX and RX pins as normal I/O. The only requirement is that GPIO0 is held high initially (so that the ESP01 does not enter boot mode).

Troubleshooting ESP 01 programming

Both of the chips I have would often fail to program ESP01 and EPS01S.

Occasionally I got it to program the Flash, but more often than not it returned the boot error codes (see below).

By observing the reset problem and (partial solution below) it now seems that the device will program more reliably - not every time but far better than before - Note this is for both ESP01 and ESP01S - they have the same problem.

Looking around the web there a quite a few instances of ESP 01 programming failure for no particular reason. You could see this sort of error message in the Arduino IDE:


A fatal error occurred: Failed to connect to ESP8266: Timed out waiting for packet header

It could be flying wires etc. However I looked on an oscilloscope at the signals and they seemed very good. Sometimes the ESP01 would output data on request at the header reading stage and then would program correctly but mainly it did not. I tried solder lead inspection, using a high current power source, adding more caps (10uF) externally to the board, resoldering with iron, then hot air gun - all that did not work.

But, after using the reset technique below - it became easier to program reliably.

The reset problem

It is probably best just to get another ESP01 chip!

However I now think this:

I am not convinced the following messages accurately reflect what is going on in the circuit because if you time your reset signal to about 25% before the end of Arduino IDE compilation completion then the chances of programming the board greatly increase.

It feels as though the reset timing is the most important factor. If you reset too early, it seems as though the ESP01 times out. If you reset to late, it does not have time to react - no output on oscilloscope from ESP01 to Arduino pin. The sweet spot is near the end of compilation!

The interesting thing is that the signals do look clean.

Another observation is that it is useful to view the response from the ESP01. Initially I used an oscilloscope to view Rx and Tx but you only really need to look at the Tx and Rx LEDs on the Arduino Uno.

While the sequence of initial programming is running during this serial output text (shown in the programming window):


You should see both Rx and Tx LEDs go on at the same time, and then a long period of both LEDs off. If you only see one LED (Rx) it means the ESP01 is not responding; blipping the reset can sometimes get the programming sequence going again - or programming drops out and you have to have another go!

Once the headers have been exchanged (this can take many ....._____ sequences) programming will start; you'll get lots of Rx LED (USB chip to ESP01) with a few Tx LED blips - the acknowledge from the ESP01. You can also see the percentage Flash programming completed in the output window.

In the end you will get the ESP01 to flash but it's going to take some patience and probably watch those LEDs (to detect activity on TX pin of ESP01).    

Another useful observation is that using the ESP8266, on a board with built in serial that uses automatic reset, I never get these problems.

The automatic reset circuit recommended by Espressif uses CTR and DTR to control the reset pin and CH_EN pins is probably what is needed to get reliable ESP 01 programming (but you'll need to find the DTR and CTR signals from the serial output chip on the Uno to do it!):

ESP8266 automatic reset circuit (also ESP01 remedy)

Source of schematic link (Search for: 'As an example of auto-reset circuitry implementation'):

Boot messages on ESP 01 programming

 ets Jan  8 2013,rst cause:2, boot mode:(1,6) - these are typical reset messages.
 ets Jan  8 2013,rst cause:2, boot mode:(1,7) - these are typical reset messages.

Boot Message Explanation

Do not take these messages as accurate indications of your circuit setup as I said above, I think it is more to do with reset timing.

The message "ets Jan 8 2013,rst cause:2, boot mode:(1,7)" indicates that the device has experienced a hardware reset due to an insufficient power supply. This error typically occurs when the device is not receiving enough power to operate properly.

The message "ets Jan 8 2013,rst cause:2, boot mode:(1,6)" indicates that the device has experienced a hardware reset due to an improper power supply. This error typically occurs when the device is not receiving enough power to operate properly or when there is a voltage fluctuation.

Here's a breakdown of the message:

ets Jan 8 2013: This is the timestamp of the reset event, indicating that it occurred on January 8, 2013.

rst cause:2: It indicates that the module was last reset due to an external reset.

boot mode:(1,7)
The second number (7) indicates that the GPIO pins are not being used and GPIO0 is low, GPIO2 is high.

boot mode:(1,6):
The second number (6) indicates that the GPIO pins are set to input mode and GPIO0=low, GPIO2=low during reset. 

The first number is the GPIO0 status while the second is for GPIO2. IF you enter normal mode you get the output : boot mode:(3,6).


Be prepared for a length programming session - if you have patience you can get these things to program but it's may not be easy!!!

The reset technique discussed here should let you program the chip without getting that annoying error message; but you will sometimes still get it!

The method discussed here greatly increases the reliability of ESP 01 programming.

Written by John Main who has a degree in Electronic Engineering.

Note: Parts of this page were written using poe as a research assistant.


Have your say about what you just read! Leave me a comment in the box below.

Don’t see the comments box? Log in to your Facebook account, give Facebook consent, then return to this page and refresh it.

Privacy Policy | Contact | About Me

Site Map | Terms of Use