Programming the ESP8266-01 can have a bit of a steep learning curve.  If you have a Nano and an -01, this just might be your blog.

The approach presented here does away with the need to buy an extra  FTDI, CP2102, or CH340G serial adapter just to program your ESP8266.

When you’re done, you’ll have the ability to use the Nano as a programmer and the example program will give you a transparent wifi to serial gateway that you can use to communicate with your future Nano projects.

I’m going to assume some fairly minimal experience.  You need to be able to read resistor color codes or at least be willing to look them up.  I’ll assume you understand voltage dividers.  You need to be able to wire a breadboard and use a meter.

The tools you’ll need:
Arduino 1.6.4 IDE (or later)
Arduino Core for ESP8266
A Breadboard & a few jumper wires;  M-M and M-F types
A voltage meter that is accurate to 3 digits
An assortment of resistors
A single capacitor between 1uF and 10uF
An Arduino Nano clone
An LDO regulator like an LM317t or a DC-DC buck converter
A DC power source between 6.5V and 40V
If your supply is over about 15V, you’ll need a heat sink or the DC-DC buck converter

I picked a CH340G variant of the Nano because they’re cheap, it’s not FTDI and the drivers have been built into Linux for a long time.  Windows users might have more pain between incompatible FTDI clones, Russian sourced CH340G drivers, or scarce cp2102 based Nano boards.

Get your Nano working in the IDE first, if it doesn’t work then neither will this.  The code in your Nano doesn’t matter much as long as it works, I used the Blink example so that I could see visually if the Nano was running or being held in reset.

[Soothing music plays while you Google for another blog to help you get your Nano programmed for the first time]

LM317t pinout Next, we tackle power for the ESP8266-01.  It needs 3.0V to 3.6V and about 250mA of current.
We’ll be using an external power source because the Nano receives power from USB through a diode and the diodes used by cheap Nano clones like the one I have are 0.7V forward voltage leaving only 4.3V for the ATmega328p and the “+5V” pin.  My buck converter and my LDO couldn’t handle that low a voltage.
I picked an LM318t and a 12v battery that I had sitting here and I chose 3.40V in hopes of minimizing the level conversion headaches.  Wire your power supply at the far right of your breadboard.  The circuit is 12V to Vin, Vout to the +rail, a 2.2K resistor between Vout and Adj, and a 3.9K resistor to the ground rail.  The schematic is: LM317t schematic I took my handy multi-meter and measured the output…  3.65V, way too high, so some adjustments needed.  The LM317 formula said it should have been 3.47V so I was about .2V high.  .2V works out to about .4K lower on the 3.9K resistor so a parallel 33K resistor comes up about right.  I added the resistor and took another measurement, 3.40V dead on.  I picked the whole thing up and brought it to my nice bench meter, 3.3999V, not too shabby.
LM317t schematic The adjusted schematic is to the left.  Bottom line, each approximately 15k in parallel with the resistor to ground will reduce the voltage by .1V.  Try to get the voltage within .05V.  Note, some regulators or supplies don’t work well with no load, put 220 ohms across the output while taking this measurement and most are happy.  Add the 1uF to 10uF capacitor across the output and ground to keep things stable.

Now that there is power, the next thing to deal with is the level shift beteewn 5V the Nano and the ESP which is 3.3V.  The solution is easy, says there are lots of options but programming is a rare task so power loss doesn’t matter, a good strong signal and simplicity are the priorities.  A resistor divider with low value resistors meets the goal.  If you achieved 3.4V in the prior step and have a cheap Nano with 4.3V on the “5V” pin, then the resistor divider values work out to 330 ohms between the Nano’s RX pin and the -01’s RX pin and 1200 ohms from the -01’s RX to ground and results in 3.37V on the -01’s RX pin.  If you didn’t achieve 3.4V on the power supply, you may need to adjust the resistors here instead.   Note, we really are connecting the RX pin to the RX pin and not crossing them like you usually would.  That’s because we’re not talking to the Nano, but actually talking to the CH340G.

The TX pin on the Nano goes directly to the TX pin on the -01.

Connect a wire from the Nano’s RST pin to ground.  This will permanently hold the ATmega328p in reset and prevent it from bothering the RX and TX pins what we’re using to talk with the CH340G.

Breadboard Image

Lastly, we need to wire up the rest of the pins on the -01.  The main points are to connect power, connect GPIO0 to ground to request programming mode, CHPD to 3.4V, and reset to 3.4V through a small resistor.  This resistor should be over 300 ohms and under 33K ohms, but is not critical otherwise, use 2.2K if convenient.  The complete breadboard that I used is to the right.

Now that we have hardware, install the ESP8266 Core using the instructions at

The promised serial gateway program is basically just a slightly patched version of the example WiFiTelnetToSerial.  I adjusted the sbuf allocation and the port but other than that I only removed all the serial messages.  Given that not much was done, I’ll go straight to the code:

  Based entirely on the WiFiTelnetToSerial Example 

  Copyright (c) 2015 Hristo Gochkov. All rights reserved.
  This file is part of the ESP8266WiFi library for Arduino environment.
  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
#include <ESP8266WiFi.h> 

//how many clients should be able to telnet to this ESP8266

#define TCP_PORT 2167 //raw-serial
#define MAX_BUFF 32
const char* ssid = "********";
const char* password = "************";

WiFiServer server(TCP_PORT);
WiFiClient serverClients[MAX_SRV_CLIENTS];

void setup() {
  WiFi.begin(ssid, password);
  uint8_t i = 0;
  while (WiFi.status() != WL_CONNECTED && i++ < 20) delay(500);
  if(i == 21){
    while(1) delay(500);
  //start UART and the server

void loop() {
  uint8_t i;
  size_t bufsize = MAX_BUFF;
  uint8_t sbuf[bufsize];
  //check if there are any new clients
  if (server.hasClient()){
    for(i = 0; i < MAX_SRV_CLIENTS; i++){
      //find free/disconnected spot
      if (!serverClients[i] || !serverClients[i].connected()){
        if(serverClients[i]) serverClients[i].stop();
        serverClients[i] = server.available();
    //no free/disconnected spot so reject
    WiFiClient serverClient = server.available();
  //check clients for data
  for(i = 0; i < MAX_SRV_CLIENTS; i++){
    if (serverClients[i] && serverClients[i].connected()){
        //get data from the telnet client and push it to the UART
        while(serverClients[i].available()) Serial.write(serverClients[i].read());
  //check UART for data
    size_t len = Serial.available();
    if(len>MAX_BUFF) len=MAX_BUFF;
    Serial.readBytes(sbuf, len);
    //push UART data to all connected telnet clients
    for(i = 0; i < MAX_SRV_CLIENTS; i++){
      if (serverClients[i] && serverClients[i].connected()){
        serverClients[i].write(sbuf, len);

To use this code, paste it into the IDE, edit the SSID and Password, choose board type “Generic ESP8266 Module”, plug in your Nano’s USB cable, and choose the appropriate USB port.

To enter programming mode, we add just one more jumper wire from reset to ground.  To program, you connect this wire, then press the “Upload” Button Image button in the Arduino IDE, wait for the white text to stop scrolling, then pull the wire.  The timing is tricky, for me I wait about 1 second after the white text stops but try different delays until you find one that works for you.  I still only succeed about half the time so don’t feel bad if it takes some trial and error to get the timing right.  Once you have something programmed, remove the GPIO0 wire and reset again to let it run.

Using your new Serial Gateway with your Nano project, you may have to adjust the voltage divider on the -01’s RX pin to match the voltage on the “+5V” pin when installed in your project.  Use the voltage divider calculator (link below) to find small resistors that provide just a hair under the -01’s voltage when the input voltage is whatever you measure on the Nano’s “+5V” pin.  The sum of the two resistors added together should be between about 1K and 2K so that you get a nice clean signal.  If you’re using a battery or are power sensitive, consider one of the other level shift options over at or the links in his Addendum, this one is power hungry.  Make sure the level shifter or divider stays on the -01’s RX pin.  Since we’ll be connecting to the Nano and not the CH340G, you now cross the RX and TX pins like usual and since we’re using those pins, nothing can be connected to the USB data pins.  Note most chargers short the data pins and that may activate the USB chip which could blow up either the USB chip or the -01.  If you do decide to try a USB charger, at least put a 1K resistor on the -01’s TX line to give it a chance should your USB chip be activated.  Talking to it is as simple as opening a terminal and entering:

nc ipaddress 2167


“the breadboard image above was created with Fritzing”

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s