Microcontroller projects

ESP8266 tips and tricks

last updated: 2022-11-11

Quick links

PWM resolution change in core >= 3.0

From this link: https://arduino-esp8266.readthedocs.io/en/3.0.2/:

NOTE: The default analogWrite range was 1023 in releases before 3.0, but this lead to incompatibility with external libraries which depended on the Arduino core default of 256. Existing applications which rely on the prior 1023 value may add a call to analogWriteRange(1023) to their setup() routine to return to their old behaviour.

New boards (10/21) workaround

Newer Wemos D1 mini pro boards V1.1 from China have a CH9102F IC instead of the old CP2104 for USB to serial bridge. You have to add the following line to your udev file in linux:

    # Wemos D1 mini pro with CH9102
    SUBSYSTEMS=="usb", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="55d4", GROUP="plugdev", MODE="0666"

Now we get a serial port (but ttyACM instead of ttyUSB!).

But the chip can not be programmed in Arduino because GPIO0 is not properly pulled down by RTS (more infos: http://weigu.lu/microcontroller/esp_programmer/index.html) as the following oscilloscope screen shows (right image, blue signal):

wemos ch9102 osci     wemos ch9102 osci

In the left image we see the signal as it should be. A workaround is to connect GPIO0 (D3) shortly to GND while programming with Arduino (thanks Daniel :)).

I found the culprit. If I'm not mistaken, they soldered a dual transistor SOT363 from LRC (MUN531DW1T1, marking 12) with a 22 k resistor between emitter and base (measured) and a 22 k resistor to the base. The original UMH3N from Rohm (right picture, marking H3) have only a 4.7 k to the base. These transistors are needed to tie down GPIO0 to GND.

I de-soldered an UMH3N from a bricked Wemos and exchanged the chips. This solved the problem!


MUN531DW1T1<em>LRC     UMH3N</em>ROHM
Click for a better view.


Connect GPIO0 (IO0) shortly to GND, just after the programming in Arduino starts.

As this is tedious if you have to program your chip multiple times, here a little helper program. Connect pin 33 of a a working ESP32 to GPIO0 (D3, IO0) of your ESP32 or ESP8266 with the false dual transistor chip, and interconnect the two grounds. Start the helper program and after this the programming of the problematic chip. The program detects the begin of the programming and pulls GPIO0 to GND at the needed moment for the needed time.

    /* workaround_no_UHM3N.ino
    * weigu.lu
    * connect ESP32 pin 33 or Uno pin A0 to GPIO0 (D3 or IO0) and 
    * GND ESP32 (Uno) to GND ESP32 or ESP8266 with false chip

    const byte PIN = A0;                //Arduino Uno A0, ESP32 GPIO 33 
    const unsigned int THRESHOLD = 500; // 500 for Uno 3500 for ESP32
    unsigned int GPIO0_VALUE;

    void setup() {

    void loop() {
      GPIO0_VALUE = analogRead(PIN);
      while (GPIO0_VALUE > THRESHOLD) {
        GPIO0_VALUE = analogRead(PIN);
      GPIO0_VALUE = analogRead(PIN);
      while (GPIO0_VALUE > THRESHOLD) {
        GPIO0_VALUE = analogRead(PIN);
      Serial.println("Tie it to GND");
      Serial.println("Do it again");

Configure Arduino

Copy the following line:


to "File > Preferences > Additional Boards Manager URLs:".

Go to "Tools > Board:".." > Boards Manager..." and scroll down. Then click install.

In Linux you have to use udev rules! if you don't want to work as root. See here


It is important to use the right pins, to avoid conflicts. A really good tutorial can be found here: https://randomnerdtutorials.com/esp8266-pinout-reference-gpios/.

5 V pin

On the V1.1 boards the 5 V pin should be considered as an output pin, because it's powered through a diode from VBUS (5 V from USB). The diode prevents destroying the USB host if a higher voltage is applied, but reduces the voltage to 4.7 V.

If you want to power the chip from this pin it's better to bypass the diode with a wire, because reboot is not always functioning. Another possibility is to unsolder the diode and short circuit the pins.


On the newer V2.0 boards (green) there is no diode but a 0.5 A fuse, so there should be no problem.

Wifi password

The wifi password must be 8 or more for the Access Point to work (WiFi.softAP(ssid, password) function)! To be shure check the return value :).


Hardware serial (opened with Serial.begin(9600)) on Wemos D1 mini pro uses UART0 of ESP8266, which is mapped to pins TX (GPIO1) and RX (GPIO3).

Serial1 (opened with Serial1.begin(115200)) uses UART1 which is a transmit-only UART. UART1 TX pin is D4 (GPIO2, LED!!).

If you use serial (UART0) to communicate with hardware, you can't use the Arduino Serial Monitor at the same time to debug your program! The best way to debug is to use Serial1.println() and connect RX of an USB2Serial adapter (FTDI, Profilic, CP210, ch340/341) to D4 and use a terminal program like CuteCom or CleverTerm to listen to D4.


Serial (UART0) may be remapped to D8 (TX, GPIO15, 10k Pull-down?) and D7 (RX,GPIO13) by calling Serial.swap(); after Serial.begin();. Calling swap again maps UART0 back to TX and RX.


The SPI Flash Filing System is designed for SPI flash devices on micro-controller systems with little RAM. It uses statically sized ram buffers (independent of number of files), posix-like API (open, close, read, write, ...) and implements static wear leveling to prolong the life of system flash.

SPIFFS uses a flat structure (no directories). Creating a file with path homie/config.json will create a file called homie/config.json instead of a config.json under directory homie. Write operation might be slow, so it is best used at start up, shut down or when time critical activities are not scheduled.

Here some info on the Wemos boards. Arduino lets you chose the amount of SPIFFS for some boards (newest Arduino and ESP8266 core (2.4!)).

Wemos D1 mini lite v1.0.0 1M bytes (0-512kB SPIFFS)
Wemos D1 mini v3.0 4MB FLASH (1MB or 3MB SPIFFs
Wemos D1 mini pro v1.1.0 16MB FLASH (15MB SPIFFS)
Wemos LOLIN32 Pro v1.0.0 4MB FLASH & 4MB PSRAM
Wemos LOLIN32 lite v1.0.0 4MB FLASH
Wemos LOLIN32 v1.0.0 4MB FLASH

Flash layout

Programming a new sketch will not modify the file system contents. This allows to use file system to store sketch data, configuration files, or content for Web server.

The following diagram illustrates flash layout used in Arduino environment:

^              ^       ^               ^     ^
Sketch    OTA update   File system   EEPROM  WiFi config (SDK)

Test size of FLASH

The following example sketch CheckFlashConfig.ino can be found in your core examples (File-Examples-ESP8266-CheckFlashConfig). You see the size in your serial monitor.

Arduino ESP8266 filesystem uploader

Download the plugin from here and unzip the file. Create a folder ESP8266FS in the Arduino tools directory and in this folder a new folder tool. Copy the esp8266fs.jar file into the tool folder (Arduino\tools\ESP8266FS\tool\esp8266fs.jar). If there is only a .java file you have to compile it first sudo ./make.sh. After a restart you find a menu item ESP8266_Sketch_Data_Upload in the Arduino Tools menu.

Go to sketch directory Sketch > Show Sketch Folder and create a directory named data. Load all your files you want to be in SPIFFS to that folder. After this make sure you have selected your board, port, and closed the serial monitor.

Select Tools > ESP8266 Sketch Data Upload. This starts uploading the files into ESP8266 flash file system (be patient; its done when the IDE status bar displays SPIFFS Image Uploaded).


Here is a code snippet lend from Steve Quinn to read a SPIFFS file (first load up your file (e.g. /homie/config.json) to SPIFFS as described below):

#include <string.h>
#include "FS.h"

bool    spiffsActive = false;
#define TESTFILE "/homie/config.json"

void setup() {
  if (SPIFFS.begin()) {    // Start filing subsystem
      Serial.println("SPIFFS Active");
      spiffsActive = true;
  } else {
      Serial.println("Unable to activate SPIFFS");

void loop() {
  if (spiffsActive) {
    if (SPIFFS.exists(TESTFILE)) {
      File f = SPIFFS.open(TESTFILE, "r");
      if (!f) {
        Serial.print("Unable to open ");
      } else {
        String s;
        Serial.print("Contents of file ");
        while (f.position()<f.size()) {
    } else {
      Serial.print("Unable to find ");
  while (true){

More infos here http://www.instructables.com/id/Using-ESP8266-SPIFFS/ and here http://esp8266.github.io/Arduino/versions/2.3.0/doc/filesystem.html

Backup and restore ESP8266 flash

Wee need the python esp tools for this. You find them in /packages/esp8266/hardware/esp8266/2.5.2/tools/esptool/. With the following command we read the flash:

    sudo python ./esptool.py -p /dev/ttyUSB0 -b 460800 read_flash 0 0x400000 flash_contents.img

The parameter are the port (-p), the bitrate (-b), the beginning and ending address and the name of the file. esptool

Uploading to the ESP8266 is done with:

sudo python ./esptool.py -p /dev/ttyUSB0 -b 460800 write_flash -fm qio 0x00000 flash_contents.img

After this we need to reset the chip. We specified the flash-mode qio (-fm qio). If this doesn't work, try the dout method instead (-fm dout).

Delete flash

After uploading a sketch using WiFi your SSID and Wifi password are stored in cleartext in the flash. So it's a good idea to erase the flash if you want to give the board to other persons.

sudo python ./esptool.py -p COM5 erase_flash

External Antenna on Wemos D1 mini pro

To connect an external antenna you have to unsolder the 0Ω resistance near the ceramic antenna and resolder it direction the miniature RF connector (U.FL).

Link to video:

Sending NTP time over hardware serial

Look here.

Using Interrupt Service Routines

We need to use the linker attribute ICACHE_RAM_ATTR for our Interrupt Service Routines. With this attribute we say that the function should be stored in RAM instead in Flash. As the entire flash is used for the program and storage, reading and writing to the flash can be done only over 1 thread. Accessing the flash simultaneously over 2 different threads will crash the ESP and trigger a watchdog reset.

    ICACHE_RAM_ATTR void ISR() {
      flag = true;