DIY Memo: ESP8266 v12 analog I/O

This is an amendment to the previous ESP8266v7 memo. More specifically, the I/O pins don’t behave exactly as described by internet sources.

A little bit of background: I was presented with a challenge to read from an analog sensor and send the reading through wifi network to the cloud. This can be accomplished easily using SIM800A GPRS module and data connection but not so using the ESP8266.

ESP8266’s I/O problems

There are two main problems with the ESP8266 in dealing with analog inputs. The chip operates on 3.3V logic instead of the common 5V. It appears to have sufficient over-voltage protection and can withstand 5V inputs without visible problems. A straightforward voltage divider circuit to linearly scale 5V down 3.3V range would have been the answer if not for the second problem…

All GPIO pins of the ESP8266 chip are digital.

ESP8266v7 and v12 have a new ADC pin which can read analog inputs from 0-1V range. That’s a far too small operation range to be useful and only one analog pin is nowhere near enough in a real application.

Possible approaches

Off the top of my head, there are three possible approaches.

The first approach is to use a voltage divider for scaling and an analog multiplexer to increase the number of analog inputs. This is done in the article here at the cost of digital pins.

The ESP8266 has TX/RX pins for serial, SCL/SDA pins for I2C and MISO/MOSI pins for SPI connection. These interfaces allow ESP8266 to communicate with an external device that has better analog I/O pinout; a device such as an Arduino or an RF transceiver. This second approach does not use ADC pin or any complicated circuitry.

The final, “least sane” method that I actually tried was software PWM. I let the Arduino read analog inputs and output the reading to one of its PWM digital pins using analogWrite() function. This “encoded” signal can then be connected to any GPIO pins of the ESP8266 and the ESP8266 can reconstruct the analog signal from the encoded PWM input using pulseIn() function. This technique uses up only one of the ESO8266’s GPIO pins and it also requires no extra circuitry.

The downside of this third approach is the fact that pulseIn() is a synchronous operation that stalls the program for 20ms in order to wait for a pulse (polling, learn more about it here). Too many of those will take up all processing time and stall the program indefinitely. Using interrupts is naturally a possible alternative but asynchronous programming is never for the faint of heart.

Pin test data

Below is the measurement data for all ESP8266 pins in the following cases:

  1. float aka not connected to pull-up/pull-down resistor by pinMode().
  2. set to HIGH by digitalWrite().
  3. set to LOW by digitalWrite().
  4. set to 300 by analogWrite().

Pin Functions

  • GPIO0: 4.57 (float), 3.4 (digital HIGH), 0.88 (digital LOW), 1.63 (analog 300)
  • GPIO1/TXD: 5 (float), 3.3 (digital HIGH), 0.00 (digital LOW), 0.98 (analog 300)
  • GPIO2: 0.97 (float), 3.3 (digital HIGH), 0.04 (digital LOW), 1 (analog 300), 1.95 (analog 600)
  • GPIO3/RXD: 5 (float), 3.3 (digital HIGH), 0.00 (digital LOW), 1.09 (analog 300)
  • GPIO4: 3.3 (float), 3.3 (digital HIGH), 0.00 (digital LOW), 0.98 (analog 300)
  • GPIO5: 0.00 (float), 3.3 (digital HIGH), 0.00 (digital LOW), 0.98 (analog 300)
  • GPIO12: 0.05 (float), 3.3 (digital HIGH), 0.00 (digital LOW), 0.98 (analog 300)
  • GPIO13: 0.05 (float), 3.3 (digital HIGH), 0.00 (digital LOW), 0.98 (analog 300)
  • GPIO14: 0.05 (float), 3.3 (digital HIGH), 0.00 (digital LOW), 0.98 (analog 300)
  • GPIO15: 0.00 (float), 3.25 (digital HIGH), 0.00 (digital LOW), 0.98 (analog 300)
  • GPIO16/XPD: 0.05 (float), 3.3 (digital HIGH), 0.00 (digital LOW), 0.98 (analog 300)
  • GPIOA0/ADC: 0.05 (float), 0.05 (digital HIGH), 0.05 (digital LOW), 0.05 (analog 300)

Additional tests for ADC pin’s analog input capability using analogRead(0) operation:

  • 9 (0.00V GND)
  • 60 (0.05V GPIO12 float)
  • 80 (0.05V ADC float)
  • 222 (3.3V GPIO4 float)
  • 1024 (3.3V GPIO5 digital HIGH)
  • 1024 (5V VCC)

Things to know

analogRead(0) and analogRead(A0) are interchangeable.

digitalRead(0) and digitalRead(A0) are not interchangeable. The first one will read from GPIO0 while the second will read from ADC pin.

All GPIOxx pins can output analog in the form of PWM signal.

GPIO4 has a float voltage of 3.3V when read by a multimeter. This is not the same as the 3.3V output by GPIOxx pins when they are set to digital HIGH. When GPIO4 (float) is read by ADC pin, it outputs a value of circa 220 instead of 1024. This suggests the floating value is not clearly defined and can vary from one observer to another.

As such, do not connect a floating pin to other devices. GPIO0, for example, has a floating value of 5V (likely connected to the power adapter) and this over-voltage can easily damage 3.3V devices.

Read more

ESP8266: Handling analog signals without an analog input, just GPIO!


2 thoughts on “DIY Memo: ESP8266 v12 analog I/O”

  1. Hi, nice article. You have to consider that the issue is not the voltage that is handled by the esp8266, but the resolution, 10 bits, so if you can work with that resolution, voltage dividers are just fine. I have several designs around that with great results. Also, if number of analog inputs is an issue and speed of reading is not, then multiplexers do the job; look at some of my products to see how this can be implemented.

    Liked by 2 people

    1. To be honest, I’m afraid of using low voltage signals because I had some bad experiences with signal losses between a 10cm and a 5cm wire, strange voltage differences between two GND terminals of the same voltage adapter, and poorly-made Chinese resistors. Still, if I understand it correctly, a 10-bit ADC still produces circa 1mV resolution (from max range 1V). I have no actual experience working with that kind of voltage but from experiences with 3.3V signals, I have a feeling electrical noise would eat up a few dozen values no matter what. Therefore, I think, 0-1V is not very useful, or accurate.

      On another note, your article made me realize that I could use the 555 for analog-to-PWM conversion. Nice idea! It’s been a few years since I last touched that thing. I’ll give it a shot later.

      Liked by 1 person

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 )

Google photo

You are commenting using your Google 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