ESP8266

From Leo's Notes
Last edited on 20 May 2021, at 07:47.

ESP8266 is a low cost Wi-Fi capable microcontroller created by Espressif, a Shanghai based company. There are various modules that use the ESP8266 microcontroller that are listed below.

Modules

Non-exhaustive list of modules. For a complete list, see http://www.esp8266.com/wiki/doku.php?id=esp8266-module-family

For ease of use on a breadboard, an adapter board can be used which also includes a pull-up resistor for the EN pin. Each adapter board can be bought for around CAD$0.35 each.

ESP-01

ESP-01 modules expose only a couple GPIO pins. The ESP-01 package does not expose the EN pin which means you will not be able to put the chip in deep sleep and have it come back automatically.

ESP-07

ESP-07 Module

These are about $2.00 USD each

ESP-12E

ESP-12 Module

These are about $1.80 USD each.

The built-in LED is on pin 2.

#define LED_BUILTIN 2

ESP-12F

The difference between the ESP-12E and the ESP-12F is the on-board antenna.

ESP8266 WeMos D1
ESP8266 WeMos D1

WeMos D1 Mini

These are about $3 USD and can be found for slightly less than that on AliExpress.

The WeMos D1 ESP8266 boards come with many compatible stackable sensors and modules. These boards include a micro USB port with an integrated serial connector which will automatically put the ESP8266 into the proper boot mode when flashing and properly resets the device afterwards. There is also a built in reset button which is super convenient.

Additionally, the analog A0 pin has a built-in voltage divider allowing for analog inputs ranging from 0.0V to 3.2V, rather than the ESP8266 bare chip of 0.0V and 1.0V.

The form factor of the WeMos D1 Mini allows for additional modules to be stacked above or below and allows for very fast prototyping. To the bottom left is a picture of a stack of different sensors packed on the WeMos D1.

WeMos Sensor Stack
WeMos Sensor Stack

DHT22 Module

Wemos DHT22 Module Fix
Wemos DHT22 Module Fix

This module uses to D4 (GPIO 2) to communicate with the DHT22. However, since GPIO 2 is also used when the WeMos is reset, this puts the DHT22 in a weird state and will stop functioning until a full power cycle occurs.

A work around is to cut off the header connecting to D4 and then bridge D4 and D3 with solder. Alternatively, break the trace on the board and solder a thin wire from the DHT22 to D3 as pictured on the right. This effectively changes the DHT22 data pin to D3 and avoids the issue that is caused when D4 is pulled high on boot.

Button Module

The button is connected to D3 and ground. There is no pull down resistor to limit current. Ensure that D3 isn't sourcing current.

BMP180 Module

Uses I2C interface connected to D1 and D2.

0.66" OLED Module

Uses I2C interface connected to D1 and D2.

Library example code: https://github.com/mcauser/Adafruit_SSD1306/blob/esp8266-64x48/examples/ssd1306_64x48_i2c/ssd1306_64x48_i2c.ino

Miscellaneous Notes

When using a photoresistor, pull A0 up to 3.3v via the photoresistor, then pull A0 down with a 10K resistor. The Wemos D1 board has a built-in voltage divider that reduces the 3.3v to 1.0v.

Quick Usage

Wiring

Skip this section if you're using a development board because all this is taken care of for you.

The ESP8266 runs on 3.3v and is not 5v tolerant. Unless you are using a development board, you must be careful when powering the board. Since serial data from TTL UART is at 5V, you must use a voltage divider or logic level converter to step the voltage down and avoid damaging the ESP8266.

Each pin can source a maximum of 12mA compared to 20-40mA for most Arduinos. There is one ADC with a voltage range of 0V to 1.0V. Do not exceed these limits or you will risk damaging the ESP8266.

The ESP8266 can boot into one of three modes depending on the GPIO input on power up. You want to boot into the sketch by pulling GPIO 0 and GPIO 2 high with a 10K resistor to Vcc. To program the ESP8266, you will need to reboot the ESP8266 into the UART bootloader by pulling GPIO 0 down while keeping GPIO 2 high. The RST pin should also be connected to the TTL UART DTR pin via a 10K resistor so that it can be reset automatically. For flashing convenience, you may wish to connect a switch to toggle whether GPIO 0 is pulled high or low. A switch pulling RST low is also convenient to have to reset the ESP.

To power on and play with the ESP8266, connect:

Description
Vcc 3.3V
GND Ground
GPIO15 Pull down (10K resistor to Ground)
GPIO 2 Pull up (10K resistor to Vcc)
GPIO 0 Pull up to boot to flash, Pull down to enter UART bootloader for flashing
TXD TTL UART Rx via Logic Level Shifter or voltage divider
RXD TTL UART Tx via Logic Level Shifter or voltage divider
RST Pull up to run; Pull down to reset
EN CH_PD Chip Power Down or the Enable pin. Pull up to run; pull down to halt.

Some modules have a built-in 10K resistor which may cause deep sleep to fail. Check by measuring the resistance manually.

ESP8266-12E Wiring

If you use an adapter board, the board might already include a couple resistors for GPIO-15 and the EN pins and can be ignored.

The ESP8266 will boot using a shared 10K pull-up resistor for GPIO 0 and GPIO 2.

A logic level shifter is required if your USB serial adapter is only 5v. Simply connect the 3.3v side to the LV (low voltage) side of the logic level shifter and the serial side to the HV (high voltage) side.

If your USB serial adapter has DTR, use 2 10K resistors to form a voltage divider and connect the reset pin between the divider for automatic reset when code is uploaded. Otherwise, reset the ESP8266 manually by shorting out the RST pin to ground while simultaneously connecting GPIO-0 to ground to enter programming mode.

Boot Modes

When wiring up your ESP, take into consideration which boot mode you wish to enter when it first powers up. It will go into one of 3 boot modes based on 3 GPIO inputs:

GPIO15 GPIO0 GPIO2 Mode
0V 0V 3.3V Uart Bootloader
0V 3.3V 3.3V Boot sketch (SPI flash)
3.3V x x SDIO mode (not used for Arduino)
  • Uart Bootloader mode is used to upload code to flash
  • Boot sketch (SPI flash) mode is used to boot from flash memory

Because of the behaviors that can be induced by these GPIO pins on start up, these GIO pins shouldn't be used for peripherals without some special planning. Otherwise, you may have inconsistent boot behaviors such as having the ESP boot into SDIO/flash mode randomly.

Deep Sleep

When using ESP.deepSleep(30e6), GPIO 16 should be connected to the RST pin. The ESP8266 will wake itself up by sending a LOW to RST which will reset the device.

Software and firmware

Out of the box, the ESP8266 comes with a default NONOS firmware that accepts AT commands. For custom projects, you may choose to either use an alternative firmware such as Tasmota or write your own program using the Arduino IDE.

Which option should you use? With all the features and maturity of the firmware from the Tasmota project, I will recommend using Tasmota over writing your own sketch unless there is a strong reason otherwise. My reasoning behind this choice is that most projects involving a ESP typically just need to poll some sensors and then acting on the data which is what Tasmota is designed to do, really really well. Rather than write a bunch of custom code and pulling in all the necessary libraries for all the peripherals manually, Tasmota comes bundled with all the nice features such as Wifi Manager and most common libraries to interact with a wide array of peripherals and network protocols. Additionally, Tasmota extremely easy to change pinouts, configure WiFi, and interact with a wide range of peripherals out of the box without needing to write a single line of code..

Tasmota

See the main article on Tasmota for information on how to flash and use Tasmota.

Setting up the Arduino IDE

To write custom code for the ESP8266 using Arduino, you will need to add the ESP8266 boards in the Boards Manager:

Additional Arduino boards in IDE
  1. File -> Preferences -> Additional Boards Manager URLs, add: http://arduino.esp8266.com/stable/package_esp8266com_index.json
  2. Tools -> Board -> Board Manager -> Search for ESP8266 -> Install
  3. Select NodeMCU 1.0 (ESP 12-E Module)

To upload your code to the ESP8266:

  1. Power off the ESP8266
  2. Connect GPIO-0 to ground (disconnect from the 10k pull up)
  3. Power on the ESP8266
  4. Compile & Upload code in Arduino IDE

The default transfer speed is at 115200 baud which is just slow enough to be irritating. You can increase this speed without affecting the reliability of uploads.

Arduino Libraries

Some libraries that are worth checking out are:

  • WiFiManager: Allows changing the AP without needing to recompile and reupload a new sketch.
  • ESP8266httpUpdate: Provides ESPhttpUpdate which allows updating the ESP8266 over the air (OTA).
  • FS.h: Part of the main ESP8266 Arduino core, used to interact with SPIFFS (SPI Flash File System)
  • ArduinoJson: Interact with JSON
  • PubSubClient: A simple MQTT client

WiFiManager

The WiFiManager library makes it easier to update the access point the ESP connects to. When the ESP boots, it connects to the previously used AP. If this fails, the ESP enters a configuration mode where it becomes an access point that can be connected to. Using a web browser, the SSID and password can be set. If successful, credentials are saved in EEPROM and the ESP will reboot.

Project website https://github.com/tzapu/WiFiManager

ESP8266httpUpdate

The ESPhttpUpdate class is part of the set of headers that are downloaded when installing the board via board manager. It allows Over-The-Air (OTA) updating by downloading a firmware from a web server.

// The line below is optional. It can be used to blink the LED on the board during flashing
// The LED will be on during download of one buffer of data from the network. The LED will
// be off during writing that buffer to flash
// On a good connection the LED should flash regularly. On a bad connection the LED will be
// on much longer than it will be off. Other pins than LED_BUILTIN may be used. The second
// value is used to put the LED on. If the LED is on with HIGH, that value should be passed
ESPhttpUpdate.setLedPin(LED_BUILTIN, LOW);

// Add optional callback notifiers
ESPhttpUpdate.onStart(update_started);
ESPhttpUpdate.onEnd(update_finished);
ESPhttpUpdate.onProgress(update_progress);
ESPhttpUpdate.onError(update_error);

t_httpUpdate_return ret = ESPhttpUpdate.update(client, "http://server/file.bin");
// Or:
//t_httpUpdate_return ret = ESPhttpUpdate.update(client, "server", 80, "file.bin");

switch (ret) {
  case HTTP_UPDATE_FAILED:
	Serial.printf("HTTP_UPDATE_FAILD Error (%d): %s\n", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
	break;

  case HTTP_UPDATE_NO_UPDATES:
	Serial.println("HTTP_UPDATE_NO_UPDATES");
	break;

  case HTTP_UPDATE_OK:
	Serial.println("HTTP_UPDATE_OK");
	break;
}

SPIFFS with FS.h

You can make use of flash storage on the ESP and use it to store data. Include the FS.h header which should already exist in your Arduino IDE. Initialize the SPIFFS object and then use it to interact with files. You can create, read, and write to files like on a regular filesystem. The FS.h file can be found at https://github.com/esp8266/Arduino/blob/eea9999dc5eaf464a432f77d5b65269f9baf198d/cores/esp8266/FS.h

Storage is not erased by default when re-uploading a sketch, so any settings you save are persistent.

Learn more about SPIFFS at https://github.com/pellepl/spiffs.

ArduinoJson

Used in conjunction with SPIFFS, you can save device settings inside a JSON file and load it. ArduinoJson makes it easy to write and parse JSON data.

Project website https://arduinojson.org/

PubSubClient

A simple MQTT client.

Project website https://github.com/knolleary/pubsubclient

Other

AT Command Reference

New out of the box, the stock firmware (ESP8266 NONOS SDK) will boot and begin accepting AT commands immediately over serial at 115200 baud. You will see garbage being dumped when the ESP8266 boots because the espressif boot ROM will write a boot log at 74880 baud (https://github.com/espressif/esptool/wiki/ESP8266-Boot-ROM-Log).

See:

AT+RST


OK

 ets Jan  8 2013,rst cause:2, boot mode:(3,7)

load 0x40100000, len 2408, room 16 
tail 8
chksum 0xe5
load 0x3ffe8000, len 776, room 0 
tail 8
chksum 0x84
load 0x3ffe8310, len 632, room 0 
tail 8
chksum 0xd8
csum 0xd8

2nd boot version : 1.6
  SPI Speed      : 40MHz
  SPI Mode       : QIO
  SPI Flash Size & Map: 32Mbit(512KB+512KB)
jump to run user1 @ 1000

⸮⸮⸮
ready
AT+CWMODE=3


OK
AT+CWLAP

+CWLAP:(4,"SHAW-BDF273",-73,"44:e1:37:f5:ac:c1",1,31,0)
+CWLAP:(4,"SHAW-BDF273-Guest",-70,"46:e1:37:f5:ac:c2",1,33,0)
+CWLAP:(4,"TELUS5578",-82,"28:28:5d:11:32:f4",1,16,0)
+CWLAP:(3,"Linksys11303",-72,"58:ef:68:29:64:50",1,13,0)
+CWLAP:(4,"Jazzwalz",-78,"1c:ab:c0:af:f9:f8",1,28,0)
+CWLAP:(3,"dd-wrt",-64,"10:6f:3f:e7:df:70",1,6,0)
+CWLAP:(4,"SHAW-827C50",-86,"f0:f2:49:82:7c:58",1,23,0)
+CWLAP:(3,"HP-Print-9D-Officejet Pro 8610",-84,"94:57:a5:95:cc:9d",1,25,0)
+CWLAP:(3,"Hi Clayton!",-82,"a8:4e:3f:74:52:a8",1,18,0)
+CWLAP:(3,"tl746704-EXT",-73,"02:be:f5:00:95:15",1,15,0)
+CWLAP:(3,"CSISVAN2",-83,"b8:8d:12:63:0c:c3",1,23,0)
+CWLAP:(3,"tl746704",-71,"00:25:f0:74:67:04",1,32767,0)
+CWLAP:(4,"SHAW-FC70A1",-74,"78:96:84:fb:21:99",3,26,0)
+CWLAP:(3,"Winternet is Coming",-75,"88:1f:a1:2e:a7:8a",4,-24,0)
+CWLAP:(0,"HP-Print-AC-ENVY 4500 series",-79,"50:65:f3:ea:39:ac",4,30,0)
+CWLAP:(3,"MLJK",-72,"e4:f4:c6:19:ab:0c",4,21,0)
+CWLAP:(4,"SHAW-EB53F2",-65,"74:85:2a:70:b6:a8",6,8,0)
+CWLAP:(3,"RQNSQMDI",-74,"a0:63:91:68:43:f2",6,10,0)
+CWLAP:(4,"SHAW-70C250",-76,"a8:4e:3f:70:c2:58",6,21,0)
+CWLAP:(4,"SHAW-629C60",-79,"90:50:ca:62:9c:68",6,26,0)
+CWLAP:(4,"VBE",-81,"c4:12:f5:67:16:08",6,5,0)
+CWLAP:(4,"JAC521G",-84,"c0:7c:d1:ba:90:59",6,15,0)
+CWLAP:(3,"4i1WLTwF",-80,"08:02:8e:95:8e:1e",6,3,0)
+CWLAP:(3,"SHAW-65C6F0",-79,"a8:4e:3f:65:c6:f8",6,23,0)
+CWLAP:(4,"SHAW-2155A0",-83,"ac:20:2e:21:55:a8",6,16,0)
+CWLAP:(4,"JAC521",-81,"c0:7c:d1:ba:90:58",6,13,0)
+CWLAP:(4,"SHAW-44C170",-74,"00:fc:8d:44:c1:78",9,16,0)
+CWLAP:(1,"ralphgonzo",-77,"00:23:69:60:49:6d",9,-19,0)
+CWLAP:(4,"41B42D",-71,"70:54:d2:15:5d:d7",11,25,0)
+CWLAP:(3,"dd-wrt",-72,"a8:4e:3f:83:0d:78",11,28,0)
+CWLAP:(3,"tla73210",-72,"00:25:f0:75:65:08",11,32767,0)
+CWLAP:(4,"D7C9CC",-70,"7c:05:07:6f:a9:e3",11,15,0)
+CWLAP:(3,"HP-Print-9C-Officejet Pro 8620",-67,"6c:c2:17:1e:da:9c",11,15,0)
+CWLAP:(3,"Coopernet",-75,"b8:8d:12:63:d8:7b",11,11,0)
+CWLAP:(3,"Lannon's Guest Network",-76,"ba:8d:12:63:d8:7c",11,13,0)
+CWLAP:(4,"SHAW-E6B9C0",-76,"bc:4d:fb:e6:b9:c8",11,8,0)
+CWLAP:(3,"SHAW-6F6F30",-76,"a8:4e:3f:6f:6f:38",11,28,0)

OK

Flashing

To flash the stock firmware (NON-OS), get the SDK and the flashing tools from:

Source code can be found at:

Reading Flash

From the 35c3 Smart Home - Smart Hack talk, you can see that the esp8266 can be dumped using the esptool.py script:

$ esptool.py --port /dev/cu.usbserial-A50285BI --baud 115200 read_flash 0 0x100000 output.bin

The flash layout appears to be:

Content Address
Bootloader 0x0
User 1 0x1000
Configuration 0x7c000
User 2 0x81000

SSID and WLAN password is located at 0x7c000.

Analog to Digital Converter

The ESP8266 contains a 10-bit successive approximation register (SAR) ADC on pin 6 (TOUT). It can be used to measure the power supply voltage on pin 3 and 4 or measure an input voltage.

The input voltage range must be between 0 and 1.0 volts.

If using a development board, such as the WeMos D1 Mini compatible modules, the board will have a built-in voltage divider using a 100 KΩ and 220 KΩ resistor, allowing the A0 pin to accept an input voltage between 0 and 3.3v (but really it should be 3.2v?).

Troubleshooting

Constantly Crashing

If your ESP is constantly crashing with a stack trace for no apparent reason, it might be caused by:

  1. An unstable power supply and not having decoupling capacitors. The initial power-on current draw might be enough to drop the voltage and cause the microprocessor to crash. When this happens, you will see a stack printout over and over over the serial console similar to:
    ets Jan  8 2013,rst cause:2, boot mode:(3,0)
    
    load 0x4010f000, len 1384, room 16 
    tail 8
    chksum 0x2d
    csum 0x2d
    v8b899c12
    ~ld
    
    Soft WDT reset
    
    >>>stack>>>
    
    ctx: cont
    sp: 3ffffc20 end: 3fffffc0 offset: 01b0
    3ffffdd0:  00000000 4000420c 60000200 3ffef00c  
    3ffffde0:  00000100 40004ac0 00000100 003fe000  
    3ffffdf0:  00000100 3ffeefcc 3fffc718 003fe000  
    3ffffe00:  0000049c 00e8a101 40105584 0000049c  
    3ffffe10:  3ffeefcc 0000049c 003fe000 0000049c  
    3ffffe20:  3fffc718 3ffeefcc 000003fe 401001f0  
    3ffffe30:  003fe000 4022e2e6 000003fe 4023a800  
    3ffffe40:  3ffef46c 4022e39f 3ffeefcc 0000049c  
    3ffffe50:  000003fd 3fffff20 3ffeefcc 4022e382  
    3ffffe60:  ffffff01 55aa55aa 00000003 00000020  
    3ffffe70:  00000020 000000c2 000000c2 aa55aa55  
    3ffffe80:  000003ff 4022e86c 3ffeefcc 3ffeefcc  
    3ffffe90:  00000001 feefeffe feefeffe feefeffe  
    3ffffea0:  40105789 00000001 3ffeefdc 4022ea64  
    3ffffeb0:  3ffedf30 3ffeefcc 00000001 3fffff20  
    3ffffec0:  3fffff40 3ffef003 00000003 00000020  
    3ffffed0:  3ffef08c 3fffff81 00000001 4022eb36  
    3ffffee0:  3fffff20 4023a460 3fffdad0 3ffee348  
    3ffffef0:  3ffef3cc 3fffff40 3ffeefcc 4022eb05  
    3fffff00:  3ffeefcc 4022eb6c 3ffee2e0 00000000  
    3fffff10:  402013a8 feefeffe 3ffeefcc 4022e48a  
    3fffff20:  3ffee300 000000db 000000db 40203440  
    ...
    
  1. A damaged ESP8266. I had inadvertently connected the ADC to inputs higher than 1V and after a while, the ESP started to randomly reboot. Eventually, the device stopped booting to the sketch. The ESP was still programmable and Arduino did not complain when I upload a sketch, however it simply won't run the sketch without crashing.

Extremely High Latency

An ESP8266 module and also one of the Tuya WiFi Smart Plug flashed with Tasmota exhibited very high latency shortly after power on. The first few seconds after the Wifi connection was established had sub 10ms latency, but shortly after, all traffic appear to 'buffer' on the ESP8266 resulting in latencies ranging from 1 second to 15 seconds.

Here's an example ping output. Notice how the response times are 'buffered' up until they are all sent back at the same time.

64 bytes from 192.168.1.105: icmp_seq=112 ttl=254 time=7225 ms
64 bytes from 192.168.1.105: icmp_seq=113 ttl=254 time=6178 ms
64 bytes from 192.168.1.105: icmp_seq=114 ttl=254 time=5156 ms
64 bytes from 192.168.1.105: icmp_seq=115 ttl=254 time=4138 ms
64 bytes from 192.168.1.105: icmp_seq=116 ttl=254 time=3114 ms
64 bytes from 192.168.1.105: icmp_seq=117 ttl=254 time=2090 ms
64 bytes from 192.168.1.105: icmp_seq=118 ttl=254 time=1066 ms
64 bytes from 192.168.1.105: icmp_seq=119 ttl=254 time=42.7 ms

64 bytes from 192.168.1.105: icmp_seq=120 ttl=254 time=12226 ms
64 bytes from 192.168.1.105: icmp_seq=121 ttl=254 time=11203 ms
64 bytes from 192.168.1.105: icmp_seq=122 ttl=254 time=10185 ms
64 bytes from 192.168.1.105: icmp_seq=123 ttl=254 time=9167 ms
64 bytes from 192.168.1.105: icmp_seq=124 ttl=254 time=8144 ms
64 bytes from 192.168.1.105: icmp_seq=125 ttl=254 time=7137 ms
64 bytes from 192.168.1.105: icmp_seq=126 ttl=254 time=6114 ms
64 bytes from 192.168.1.105: icmp_seq=127 ttl=254 time=5131 ms
64 bytes from 192.168.1.105: icmp_seq=128 ttl=254 time=4117 ms
64 bytes from 192.168.1.105: icmp_seq=129 ttl=254 time=3106 ms
64 bytes from 192.168.1.105: icmp_seq=130 ttl=254 time=2112 ms
64 bytes from 192.168.1.105: icmp_seq=131 ttl=254 time=1089 ms
64 bytes from 192.168.1.105: icmp_seq=132 ttl=254 time=201 ms

A tcpdump on the Wifi access point showed the ICMP pings leaving for the ESP at regular 1 second interval and many replies coming back at the same time.

This issue might be a result of how the access point was set up. You see, this access point is using a Raspberry Pi 1 with a USB Wifi adapter running OpenWRT. There are about half a dozen clients connected to this access point all without this behavior.

The issue seemed to have gone away after setting the "Beacon Interval" to 20ms in OpenWRT.

See Also