Getting Started with the ESP8266 and Arduino
The ESP8266 is a low cost serial wifi SOC device. It comes with an AT firmware for interacting with a host or MCU but it’s also a MCU with GPIO capabilities, and can run software. These are available from US suppliers from around $8 and around $3 (shipped) from China, but expect a few weeks or longer for delivery. Previously, wifi boards for use with Arduino would cost upwards of $30 or more!
Update: Since I wrote this post there are some better alternatives to use the esp8266 with Arduino. The NodeMCU board has breadboard friendly pinout and best of all can be programmed from the Arduino IDE. It even supports OTA firmware updates!
To communicate with the ESP8266 I’m using a 3.3V FTDI board and the Arduino IDE Serial console. At first I tried the 115200 baud rate and “Carriage Return” but didn’t get an OK. Then I selected 9600 for baud rate, and both NL & CR and sent an AT command and got back OK. What I found is many of the guides I found refer to the older firmware that defaults to 115K baud rate. Mine came with a newer 0.9.2.4 AT firmware (which I updated, see below).
To get started, wire up the esp8266 to a 3.3V FTDI board.
Now run some AT commands
To change the baud rate use the AT+CIOBAUD command (older firmware)
If it responds with an ERROR, try AT+IPR
Remember to change the Arduino IDE baud rate.
Act as station and access point
Join a network. This may take a few seconds
See if we got an ip address
Be a server (seems that it can’t be client and server at same time)
Listen on port
Note: On a power reset or restart, the esp8266 retains the access point configuration (CWJAP) but CMUX and CIPSERVER must be applied again.
Now from a host terminal, telnet to the device and send a message
telnet 192.168.1.115 1111
“Link” is sent when a client connects. Then the message follows
Note the size of 7, which includes the CR + LF characters.
To send a message back to telnet client we need to add 2 chars to the length for the CR + LF
Almost all the resources I found while searching for help reference the v0.9.2.2 AT Firmware.bin, yet it is no longer available for download on the site (http://www.electrodragon.com/w/File:V0.9.2.2_AT_Firmware.bin.zip) I found it here http://www.xess.com/blog/esp8266-reflash/ and there are some other obscure references to it as well. Later releases have multiple bin files in the “at” folder. The readme describes the address to load the bin files, where as for version 0.9.2.2 it’s just a single file.
At some point later I started seeing some gibberish on restarts.
The esp8266 pins are not 5V tolerant, so I’m using a logic level shifting board to interface with the Arduino. The logic level converter (LLC) board I purchased off ebay seems to be a clone of the Sparkfun LLC. The TX is bidirectional but the RX is directional and *only* works from high side to low side. So, accordingly I wired the ESP TX to the TX low pin and the ESP RX to the RX low pin. More info here https://learn.sparkfun.com/tutorials/using-the-logic-level-converter/hardware-overview
The logic level shifter is convenient to use on a breadboard but if you don’t have one or prefer a simpler solution, a voltage divider circuit can be substituted. I tested with three 1K resistors and it worked flawlessly at 9600 baud (Note: at higher rates it may not function as well). The ESP TX can safely be connected to the Arduino SoftSerial RX as the Arduino will register a 3.3V signal as HIGH.
Some guides show the CH_PD pin (Chip Enable) as not connected but my board would not respond to any command unless this pin was held at VCC.
Caveat: the esp8266 really should not be powered from the Arduino as the Arduino cannot supply quite enough oomph. Although it seemed to work as many others have found, it can fail in unexpected ways if the voltage drops. It’s recommended that the esp8266 be powered by an independent power supply, capable of providing ~300mA.
It’s possible to use other for SoftSerial but keep in mind that some digital pins are not supported by SoftSerial RX, as it requires interrupt support. I choose pin 8 for RX as it works for Leonardo and Atmega 328, but for Mega a different pin would need to be selected. SoftSerial TX can use any digital pin. For more information http://www.arduino.cc/en/Reference/SoftwareSerial
On a succesful boot the ESP blue led flashes twice on power up then goes off until serial is received.
According to this diagram I have the ESP-01 version 2
There is no factory restore option with this firmware version, so the only recourse to get it to the initial state is reflashing. However I was unable to find the version of the firmware that came my device — google searches turn up nothing — so I used the firmware from espressif on github.
The official esp8266 firmware updating tool is a windows UI application but fortunately some awesome person wrote esptool, a command line tool for firmware updates. It is written in Python so should work on a variety of operating systems: Mac, Linux and Windows etc.
The esp wiki specifies the following connections for updating the firmware over UART. Of course this is in addition to Vcc, GND, TX and RX. All pins should be connected except RESET.
CH_PD → High. Enables the chip
GPIO0 → Low. Selects UART download boot mode
GPIO2 → High. Selects UART download boot mode
For more information refer to https://github.com/esp8266/esp8266-wiki/wiki/Uploading
Based on recommendations elsewhere, I have powered the device with an external 3.3V supply and only have the GND, TX and RX of FTDI connected. Oh, and make sure you don’t have the Arduino serial console open when using the esptool.
Get the tool from github
At this time the project was at commit
python setup.py install
Get the esp8266 AT firmware
There are two options for the user1.bin: newer/user1.bin and v0.20/user1.bin; I arbitrarily chose the v0.20/user1.bin version, then later tried the newer version.
I flipped the power switch then started the command. At first I would get errors intermittently:
./esptool.py --port /dev/tty.usbserial-A4004Rim write_flash 0x00000 ../esp8266_at/bin/boot_v1.1.bin 0x01000 ../esp8266_at/bin/newest/user1.bin 0x7C000 ../esp8266_at/bin/esp_init_data_default.bin 0x7E000 ../esp8266_at/bin/blank.bin
Writing at 0x00000400… (100 %)
Writing at 0x00012c00… (33 %)
Traceback (most recent call last):
File “./esptool.py”, line 536, in <module>
File “./esptool.py”, line 195, in flash_block
struct.pack(‘<IIII’, len(data), seq, 0, 0)+data, ESPROM.checksum(data)) != “\0\0”:
File “./esptool.py”, line 110, in command
raise Exception(‘Invalid response’)
Exception: Invalid response
I checked the pins were seated and tried a few more times and finally it worked. Another time I inadvertently left the Arduino IDE console open on the FTDI serial port. It would fail consistently with
serial.serialutil.SerialException: device reports readiness to read but returned no data (device disconnected or multiple access on port?)
Here’s the successful flash output
ceylon:esptool andrew$ ./esptool.py --port /dev/tty.usbserial-A4004Rim write_flash 0x00000 ../esp8266_at/bin/boot_v1.1.bin 0x01000 ../esp8266_at/bin/newest/user1.bin 0x7C000 ../esp8266_at/bin/esp_init_data_default.bin 0x7E000 ../esp8266_at/bin/blank.bin
Writing at 0x00000400… (100 %)
Writing at 0x00036c00… (100 %)
Writing at 0x0007c000… (100 %)
Writing at 0x0007ec00… (100 %)
Now unplug GPIO0 and GPIO2 to run AT commands.
Unlike the previous firmware, this firmware defaults to 115200, and expects \r\n.
ets Jan 8 2013,rst cause:4, boot mode☹3,7)
load 0x40100000, len 612, room 16
load 0x3ffe8000, len 788, room 4
load 0x3ffe8314, len 264, room 8
2nd boot version : 1.1
SPI Speed : 40MHz
SPI Mode : QIO
SPI Flash Size : 4Mbit
jump to run user1
I need a lower baud rate to use with SoftSerial on Arduino. I tried setting it to 9600 but got an error
After digging through esp8266.com I found the command has changed to AT+IPR.
But now if we run AT+RST again we non-ascii after the OK
Also tried flashing the “V0.20” version (esp8266_at/bin/V0.20/user1.bin) which seemed to work fine as well.
I attempted to try the Adafruit library but I did not work at all. I knew the bootmarker would not work since this firmware does not report “ready” @9600, but even without restart it would just timeout with errors.
Writing a Sketch
Update: I wrote an Arduino Library. It’s available at github
For my application I need to setup the esp8266 as a server to receive programming data. I really didn’t want to write the code to do this but I couldn’t find a solution anywhere. Interfacing with the esp8266 AT firmware programmatically is challenging since the command responses are not fixed length in many cases and some responses do not include a reliable delimiter to indicate when the response is complete.
The sketch looks for commands IPD (data), CONNECT, and CLOSE. Any other commands are ignored and actually reset the device. When an IPD arrives, the channel and data length are parsed, e.g
This command indicates the connection id is zero and the length is four. The IPD command always ends with CR,LF,O,K,CR,LF (5 characters), so it’s easy to parse by reading the data length characters plus five.
After parsing the data I return an ACK. First you tell the esp how many characters to send with the CIPSEND command.
This responds with
If “OK” is present in the response it is assumed to be successful.
if (strstr(cbuf, “OK”) == NULL) // error!
Then write the data to the client
The esp8266 retains the wifi connection config on a power cycle but it loses the config to act as a server. The reset procedure I use is
// close active connection
// stop server
// enable multiple connections (required for server mode)
// start listening
One issue I found is that while AT+CIPCLOSE=id triggers a input stream io error on the client, and I could reconnect after it completed, I would not receive data for a few minutes, although the socket writes where successful from the client point of view.
Next I wrote Java client to connect to the esp8266 and transfer data. I discovered a few quirks while developing the client. I found that if the data was sent by multiple calls to
(bytes are signed in Java), then multiple IPD commands would be received on the esp8266, even if flush was called after write calls.. To get around this behavior, I modified the code to instead call
I ran the client all night, continuously sending messages (of 32 bytes) after the ACK was received. I checked in the morning and it had sent over 256,000 messages with no errors, so not bad. The transmission rate was just a hair under 8 messages per second, so just under 256 bytes per second. This includes the Arduino process time and sending back an ACK, so the actual data speed is much higher.
- Pin configuration http://www.electrodragon.com/w/File:ESP8266_V091.png
- Specs http://www.electrodragon.com/w/Wi07c#Firmware
- AT Command Reference https://github.com/espressif/esp8266_at/wiki/AT_Description
- Forum http://www.esp8266.com/
- Guide for updating firmware with the python script https://www.ukhas.net/wiki/esp8266_firmware_update
- Python ESPtool for firmware updates https://github.com/themadinventor/esptool/
- Guide that describes how to act as a server. NOTE: It incorrectly refers to AT+RST as reset; it is a restart command http://rancidbacon.com/files/kiwicon8/ESP8266_WiFi_Module_Quick_Start_Guide_v_1.0.4.pdf
- Horribly disorganized forum for official releases http://bbs.espressif.com/viewforum.php?f=5
- LUA firmware https://github.com/nodemcu/nodemcu-firmware
- Good overview of logic shifting with some solutions http://playground.arduino.cc/Main/I2CBi-directionalLevelShifter#bidirectional
- Addicore has them available at $4.50 (US) http://www.addicore.com/Addicore-ESP8266-WiFi-Wireless-Tranceiver-Module-V-p/130.htm
- Firmware update guide http://pietrushnic.github.io/blog/2015/01/25/esp-12-upgrade-to-esp-iot-sdk-v0-dot-9-5-using-esp-open-sdk-toolchain/
- Looks promising but did not work with my firmware https://github.com/adafruit/Adafruit_ESP8266