It is well known that, unlike a Raspberry Pi or old-school Arduino, the ESP8266 has some quirks which make using the broken-out pins D0-D8 non-trivial. Google/Bing/etc will easily confirm this. I have, however found lots of long winded, unclear, and conflicting information. This post is my aide memoir, shared in case anyone else might find it useful. The hardware platform is “HW-628 V1.1”, from one of the many cheap Chinese sellers on Alibaba. I’m using the Arduino libraries with PlatformIO (within VSCode), but would expect the same results using the Arduino IDE.
My baseline assumption is that inputs and outputs will normally be used in “active low” mode, with INPUT_PULLUP used as the pinMode for inputs. There are two problems which will easily be found without care: 1) [as outputs] some pins are driven low on boot, usually with quite a few pulses, which will cause an active low relay to stutter; 2) [as inputs] holding some pins low will block the booting.
Tests for the effect of booting (and flashing) on output states were undertaken using a logic analyser (an Open Bench Logic Sniffer with OLS software) with a weak pull-up on the pin under test. I am using the D0-D8 notation as marked on the NodeMCU board. The Arduino library pin numbers differ, but the mapping is widely published.
The following pins were found to be OK to use without any restrictions, as inputs or outputs: D0, D1, D2, D5, D6, D7. The only caveat for my hardware is that D0 is connected to one of the on-board LEDs (active low).
The following CANNOT be used as outputs (with the exception of LED signalling*) since they are affected on boot (and when flashing): D3, D4, D8. D8 was found to hold a low value during flashing and during and slightly after the reset pulse. D3 and D4 showed a burst of pulses. You might get away with using D8 in its “TX2” UART alter ego since the flash/boot glitch wont make a valid data frame. [* – the NodeMCU Devkit board I have does have an LED on D4 = GPIO2 and this can be used for signalling from programmes].
D3, D4, and D8 can be used as inputs but only with some care:
- D3 and D4 can be used as active low inputs only AFTER the boot sequence is completed. Push-switch inputs would be safe. Anything which would pull these pins low on boot will block it. D4 is connected to the on-board LED which is marked “COM” (and is active low).
- D8 can be used as an active high input only AFTER the boot sequence. Push-switch inputs would be safe. I would use this last as I don’t like circuits to contain a mix of active low and active high inputs; logic should normally be consistent to reduce bug risk.
- Since these GPIOs have output functions during boot and flashing, if there is a chance that a push switch input would be operated during those states, the switch should connect to ground or supply via a current limiting resistor.
An aside: when setting pins as outputs with pinMode, it is worth setting the output value to HIGH with digitalWrite() BEFORE changing the mode from its default as an input. Otherwise, assuming active low working again, you will be likely to see an output glitch due to a default low state pertaining when the pinMode() is applied.