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!

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)

AT+CIOBAUD=9600

If it responds with an ERROR, try AT+IPR

AT+IPR=9600

Remember to change the Arduino IDE baud rate.

Restart

AT+RST
[Vendor:www.ai-thinker.com Version:0.9.2.4]
ready

Firmware version

AT+GMR
0018000902-AI03
OK

Act as station and access point

AT+CWMODE=3

List networks

AT+CWLAP
+CWLAP☹4,”HOME-C95C”,-69,”cc:03:fa:6f:c9:5c”,1)
+CWLAP☹4,”CenturyLink1440",-83,”28:28:5d:27:a4:71",1)
+CWLAP☹4,”HOME-B343",-87,”58:23:8c:e4:b3:43",1)
+CWLAP☹4,”HUGHESNET”,-84,”e0:91:f5:b8:f6:11",2)
+CWLAP☹3,”martinezmcgee”,-89,”a0:21:b7:b3:ef:88",2)
+CWLAP☹4,”Cheyenne”,-91,”e0:91:f5:b8:f8:47",2)
+CWLAP☹0,”xfinitywifi”,-77,”96:6b:3d:9c:c6:90",6)
+CWLAP☹4,”lovettwilner”,-82,”00:22:6b:6d:45:e9",6)
+CWLAP☹3,”ASUS”,-90,”ac:22:0b:8d:7c:66",6)
+CWLAP☹4,”tazah”,-87,”00:1b:63:2c:18:4c”,6)
+CWLAP☹4,”HOME-6582",-89,”e8:89:2c:54:65:80",11)

Join a network. This may take a few seconds

AT+CWJAP="xfinitywifi","password"
OK

See if we got an ip address

AT+CIFSR
192.168.4.1
192.168.1.115
OK

Be a server (seems that it can’t be client and server at same time)

AT+CIPMUX=1

Listen on port

AT+CIPSERVER=1,1111

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

Link
+IPD,0,7:hello
OK

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

AT+CIPSEND=0,4
> hi
SEND OK

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.

AT+RST
OK
c_ÇÏRöâFjSöfJ[úâ
[Vendor:www.ai-thinker.com Version:0.9.2.4]
ready

Arduino

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

Firmware update

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

git clone https://github.com/themadinventor/esptool.git

At this time the project was at commit

12debb7bfe5e978060ff1919bf87d00ed52c4a72

Install

python setup.py install

Get the esp8266 AT firmware

git clone https://github.com/espressif/esp8266_at.git

Current commit

4d00060634d4c74267ad38d27aa58805680a872c

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
Connecting…
Erasing flash…
Writing at 0x00000400… (100 %)
Erasing flash…
Writing at 0x00012c00… (33 %)
Traceback (most recent call last):
File “./esptool.py”, line 536, in <module>
esp.flash_block(block, seq)
File “./esptool.py”, line 195, in flash_block
struct.pack(‘<IIII’, len(data), seq, 0, 0)+data, ESPROM.checksum(data))[1] != “\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
Connecting…
Erasing flash…
Writing at 0x00000400… (100 %)
Erasing flash…
Writing at 0x00036c00… (100 %)
Erasing flash…
Writing at 0x0007c000… (100 %)
Erasing flash…
Writing at 0x0007ec00… (100 %)
Leaving…

Now unplug GPIO0 and GPIO2 to run AT commands.

Unlike the previous firmware, this firmware defaults to 115200, and expects \r\n.

AT+RST
OK
ets Jan 8 2013,rst cause:4, boot mode☹3,7)
wdt reset
load 0x40100000, len 612, room 16
tail 4
chksum 0x12
load 0x3ffe8000, len 788, room 4
tail 0
chksum 0x50
load 0x3ffe8314, len 264, room 8
tail 0
chksum 0x4a
csum 0x4a
2nd boot version : 1.1
SPI Speed : 40MHz
SPI Mode : QIO
SPI Flash Size : 4Mbit
jump to run user1
r
ready

Firmware version

AT+GMR
00200.9.4
OK

I need a lower baud rate to use with SoftSerial on Arduino. I tried setting it to 9600 but got an error

AT+CIOBAUD=9600
ERROR

After digging through esp8266.com I found the command has changed to AT+IPR.

AT+IPR=9600

But now if we run AT+RST again we non-ascii after the OK

AT+RST
OK
cŸÇÏR[¶fJ[:fJSjîóÂOÂGÇW˨HHWV,V¯Hø

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

(13)(10)+IPD,0,4:hi(13)(10)(13)(10)OK(13)(10)

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.

 esp->print(“AT+CIPSEND=”); 
esp->print(connectionId);
esp->print(“,”);
esp->print(sendLen);
esp->print(“\r\n”);

This responds with

(13)(10)(13)(10)OK(13)(10)AT+CIPSEND=0,4(13)(13)(10)>(32)

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

esp->print(“ok”);
esp->print(“\r\n”);
esp->flush();

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
AT+CIPCLOSE=id
// stop server
AT+CIPSERVER=0
// restart
AT+RST
// enable multiple connections (required for server mode)
AT+CIPMUX=1
// start listening
AT+CIPSERVER=1,1111

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.

Client

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

OutputStream.write(int) 

(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

OutputStream.write(byte[])

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.

References

Show your support

Clapping shows how much you appreciated Andrew Rapp’s story.