Electronics project notes/ESP notes

From Helpful
(Redirected from ESP32)
Jump to: navigation, search
This is for beginners and very much by a beginner / hobbyist.

It's intended to get an intuitive overview for hobbyist needs. It may get you started, but to be able to do anything remotely clever, follow a proper course or read a good book.

Some basics and reference: Volts, amps, energy, power · Ground · batteries · resistors · changing voltage · transistors · fuses · diodes · varistors · capacitors · inductors · transformers · baluns · amplifier notes · frequency generation · skin effect

And some more applied stuff:

IO: Input and output pins · wired local IO · wired local-ish IO · ·  Various wireless · 802.11 (WiFi) · cell phone

Sensors: General sensor notes, voltage and current sensing · Knobs and dials · Pressure sensing · Temperature sensing · humidity sensing · Light sensing · Movement sensing · Capacitive sensing · Touch screen notes

Actuators: General actuator notes, circuit protection · Motors and servos · Solenoids

Noise stuff: Stray signals and noise · sound-related noise names · electronic non-coupled noise names · electronic coupled noise · ground loop · strategies to avoid coupled noise · Sampling, reproduction, and transmission distortions

Audio notes: See avnotes

Platform specific

Arduino and AVR notes · (Ethernet)
Microcontroller and computer platforms ·
ESP series notes
STM32 series notes

Less sorted: Ground · device voltage and impedance, audio and otherwise · electricity and humans · power supply considerations · Common terms, useful basics, soldering · PLL · pulse modulation · signal reflection · resource metering · SDR · Project boxes · vacuum tubes · Unsorted stuff

Some stuff I've messed with: Avrusb500v2 · GPS · Hilo GPRS · JY-MCU · DMX · Thermal printer ·

See also Category:Electronics.

See also Electronics project notes/Microcontroller and computer platforms

Hardware, and the minimal boards

WiFi-capable microcontrollers.

You can run code on the microconroller, alongside the wifi code.

It is also sometimes used standalone, with another microcontroller using it for the wifi.

See Electronics_project_notes/Microcontroller_and_computer_platforms#ESP_series for wider context.



  • Based on Xtensa LX106 microprocessor (a 32-bit RISC CPU)
  • ~160KB SRAM
often at 80 MHz (can be run faster at 160MHz though people report this breaks code that didn't expect that)
  • WiFi b/g/n (no bluetooth)
apparently people have got it to send on the order of ~10mbit/s but don't count on that
When using the given SDK, you effectively share the CPU cooperative-multitasking style, and must yield time to the wifi code at least every few hundred ms and preferably rather more often(verify).
  • 17 GPIO, 2 SPI, 2 I2S, 2 UART, 1 I2C, and a 10-bit ADC (pin overlap)
  • no hardware PWM (though you get a decent rate out of via timers)

ESP8266 itself is a SMD IC and you probably want to get it on a board helping you along, (see e.g. http://esp8266.net/ for details), because at the least you'll want it connected to flash. It's hard to get it without unless you buy just the chip in bulk, though.

Initially from espressif, who had board variants called ESP-WROOM-something.

More common are the Ai-Thinker ones, and derivatives, often one of:

  • ESP-01 - exposes little useful IO, used mostly as a wifi slave board
  • ESP-05 - also exposes little IO. Allows better antenna than 01. Discontinued?(verify)
  • ESP-12 - exposes more things, making it more useful as a standalone uC, though physically it's not so easy to use
  • ESP-201 - easier to use on a breadboard
...and yeah, a bunch more of these exist.

You now may prefer more complete prototyping boards, such as the NodeMCU or WeMOS or HUZZAH

Most build on the ESP-12, and add things like USB-to-serial and voltage regulation. (see below)

The size of flash will vary.


Compatible with ESP8266, but smaller because it has flash integrated (1MiB for ESP8285N08, 2MiB for ESP8285H16).

There seem to be some variant boards here too, at least:(verify)

ESP-M1 - antenna connector
ESP-M2 - onboard antenna
ESP-M3 - onboard antenna



This article/section is a stub — probably a pile of half-sorted notes, is not well-checked so may have incorrect bits. (Feel free to ignore, fix, or tell me)

The earlier variant we saw(verify)

but note: pin overlap, and not all may be broken out

But note that there are varying boards, which may not expose everything, and also makes finding pinouts slightly interesting.


CPU: single-core Tensilica Xtensa LX7 (verify)
no Bluetooth (verify)


CPU: single-core RISC-V
Bluetooth 5 LE


CPU: dual-core Tensilica Xtensa LX7 (verify)
Bluetooth 5 LE

See also:

see also

Some DIYer-geared ESP8266 boards

May add

  • breakout into something easier to solder
exceptions include the Huzzah
  • Regulator from 5V input -- particularly if it has USB, to be powered off it
  • Reset button, GPIO (boot related) button


A Huzzah, and some poor soldering skills

Adafruit huzzah:

Based on ESP-12


  • The board has a 500mA LDO regulator that you should feed 4-6V
V+ and Vbat both go to it, separated via Schottky diodes
and V+ is also on FTDI header, so that you stably can power the chip while programming it (...from a powered hub / port)
if you have your own regulation, you can bypass the LDO regulator by connecting the LDO pin to ground


  • TX and RX are used for bootloading, and for serial control (exposed in two places on this board, to make FTDI plug easier)
RX is 5V safe (and Vcc goes to the regulator) so you can use a generic 5V serial cable

Note: no USB


Wemos D1 (where I removed the barrel jack for some reason)
and size of the D1 mini (this might be a ripoff?)

WeMos D1 is a Arduino-sized board, partially compatible

and a revision "D1 R2", with minor difference in pins between the two.

Wemos D1 Mini are smaller boards, specifically:

D1 Mini Lite
ESP-8285 based,
1MB Flash
PCB antenna
D1 Mini
ESP-8266EX based
4MB Flash
PCB antenna
D1 Mini Pro
ESP-8266EX based
16MB Flash
Lithium battery pin, charger chip
PCB antenna + Antenna connector

D32, based on ESP32

Lithium battery pin, charger chip
D32 Pro
Lithium battery pin, charger chip
MicroSD socket

(with some revisions)


NodeMCU devkit

NodeMCU itself refers to the firmware. It'll run on any ESP based board, really.


For clarification, there is also a breadboardable piece of hardware called the The 'NodeMCU Devkit' is the name of a specific board [1],

There seem to be three board that carry this name. Image on the right from this post: [2].(verify)


Some DIYer-geared ESP32 boards



ESP32 DevKit-C



There's a bunch of ebay/aliexpress boards that are perhaps best distinguished by some physical things like pin count, (lack of) antenna overhang, and such

Consider e.g. these: https://www.studiopieters.nl/esp32-pinout/



D1 Mini ESP32




On firmware

Flashing new firmware

This article/section is a stub — probably a pile of half-sorted notes, is not well-checked so may have incorrect bits. (Feel free to ignore, fix, or tell me)

nodemcu pyflasher

basic GUI that is a wrapper around esptool.py
easier to use
you need to install wxpython and pyserial (e.g. through
pip install wxpython pyserial


came from the community, now also adopted by espressif
you need to install python

ESP Flash Download tool

in theory more flexible, but the interface is hard to understand

See also:

On flash mode

Apparently [3]

ESP8266 ESP-12 boards uses DIO
most other ESP8266 board (e.g. ESP-01 and ESP-07) use QIO
ESP8285 uses DOUT
ESP32 uses DIO

Since this is about wiring, you can't be entirely use until something fails to flash.

Is this just about upload speed or also about execution speed?(verify)

On some bare-bones boards you may need to manually get it into programming mode.

e.g. on ESP8266-01 you need to tie GPIO0 to Gnd (verify) at reset time. Various boards will have two buttons to make this easier.

What's this address stuff?

In basic cases you put the firmware at the start of flash (0x0),

If you have distinct blocks to go to specific addresses, you'll probably get instructions for it.

Firmware alternatives

This article/section is a stub — probably a pile of half-sorted notes, is not well-checked so may have incorrect bits. (Feel free to ignore, fix, or tell me)

Everything shares the same SDK underneath, but what is added on top, and the thing you interact with, varies.

AT commands firmware

The AT commands firmware (Espressif?) is useful if you want to add WiFi to an existing microcontroller with just the RX and TX serial pins, and controlling how it communicates.



https://bbs.espressif.com/viewtopic.php?f=10&t=362 - for espressif firmware?

NodeMCU firmware (Lua)

The NodeMCU firmware wraps Espressif's SDK (and primarily for the ESP8266) with a Lua interpreter, which hooks into a bunch of C libraries and pure-lua libraries.

There is now also an RTOS variant for the ESP32 (and not ESP8266, because of the higher memory use) which

There are a whole bunch of C libraries you can add.

A little more controlled, but more work, is https://github.com/nodemcu/nodemcu-firmware
The easier way for tinkerers is to use the online build service: https://nodemcu-build.com/

Including more modules will increase the flash size (you usually don't care) but often also the RAM size

Lua coding for that firmware

You can use one of various tools to upload lua files, which itself is (relatively basic) serial-port stuff. Options include:


java based IDE, fiddly but it works

luatool [4]

uploads Lua files to ESP8266 modules running nodemcu firmware


up/down lua files, manage filesystem

esp8266 lualoader [5]

...and various other tools people have built.

See also:

Other interpreters people have built onto the SDK

this page lists variants on idea of the interpreting firmware but for other languages, like python, JS, Basic, Forth, Lisp, and support from some other embedded platforms.

The idea ends up being the same - flash its firmware, later upload code via the serial port (and possibly over the air)



Some notes

Lua firmware notes

Some lowish level notes

Keep in mind that some standard Lua modules (e.g.
) are removed, and others provide similar function (e.g. , ).

So some Lua code you find around (e.g. for raspberry Pi) will need changes, with some specific knowledge of the argument differences.

And since
is missing, debug mostly consists of print statements. There are other practical differences, like that
is mainly just
uart.write(0, string)

Running code off flash is done with cached memory mapping, which is basically why there is one SPI interface you cannot use

The event/tasking system is roughly three queues, a high priority one (for hardware related tasks), medium (for timer and event stuff), and low (everything else)

no task can pre-empt others, so ideally no task should run longer than a dozen ms, so that things like wifi work smoothly, and sometimes less so that your own tasks work smoothly but this can be less critical
if a task takes over 500ms it'll trigger the watchdog (unless you explicitly feed it, but in most cases that is bad design)

(there are also ISRs in C for time-critical stuff but you probably don't want to touch that. They can interrupt tasks, but only up to ~10usec)

Calling various functions in net, tmr, wifi, and some others will (in part because they are C) amount to queueing their code as tasks, which will not happen immediately but after the task running that calling chunk of lua is done

being in that queue uses a little RAM until they actually execute
which is a few reasons why event/callback style coding is recommended

Errors will trigger a panic, which triggers the watchdog, and reboot

this is useful for recovery
but not always for debugging because even just typos may cause a reboot rather than print an error

Flash not used for firmware is provided via
classically SPIFFS, now moving to LittleFS
(Confusingly, LFS, Lua Flash System, is a different thing https://nodemcu.readthedocs.io/en/release/lfs/ )
note that
can also be used to read/write SD cards

The float versus int builds:

working in float is more to specs, and generally recommended
working in integers is faster but breaks the specs a little, so also some code.

The SDK triggers startup code,

which initializes lua,
runs init.lua
listens interactively to UART0
defaults to 9600 baud. ESPlorer changes speed by sending a uart.setup() command, then attempting to reconnect (verify)

Coding using events, timers, and coroutines

This article/section is a stub — probably a pile of half-sorted notes, is not well-checked so may have incorrect bits. (Feel free to ignore, fix, or tell me)

Tasks run to completion and cannot be pre-empted.

Running too long will trigger the watchdog, and before that will make wifi code break or be choppier.

So it's suggested to try keeping tasks under 10ms, also for the responsiveness of responding to events.

In general, try to do things event-based, using callbacks.

It's generally useful to put code in a timer, or use a timer as an event loop checker

Note that since timers and callbacks are tasks that don't pre-empt (and that timers are software timers), they may get scheduled later than you think. Also, don't set timers faster than they'll take.

Longer calculations are probably best done in smaller chunks

Can you use coroutines?(verify)

Keep ISRs under 10us, or wifi will break.

I2S canbe DMA'd, no other peripherals can(verify)

"Waiting answer from ESP - Timeout reached. Command aborted"

(in ESPlorer)

This can be

  • a bug related to use of CR-style newlines[6] (where the firmware expects CRLF(verify)), but only on specific commands.
It's particularly file transfers that will be broken.
This could be fixed on both sides, but the easier may be to get a newer firmware build (verify)

  • the serial connection crapping out for some reason (verify)
I seemed to have it one one board, possibly power problems?

modules, packages, and compilation

On reboots

boot/reset cause

If you catch enough of the next boot's output, you'll see something like:

rst cause:2, boot mode:(3,6)

The boot mode is rarely very interesting. It indicates

  • where we booted from (which is based on GPIO pin state at boot), and
  • how exactly.

The first will typically be 3 (Flash), and if not, and it's not booting as expected, chances are the relevant GPIO pins (GPIO15, GPIO0, GPIO2) are not in the state they should be. (If you put hardware on these pins, this needs extra care to not affect boot)

...or it's the first watchdog reset after a firmware download and soft reboot(verify), which can trigger it trying to do a firmware download again (e.g. 1,7) (verify), once.(verify)

While the rst cause is one of: [7](verify)

0  Unidentified
1  Power reboot or normal boot ?
2  External reset using reset pin, or wake up from deep sleep
3  Software reset
4  Hardware watchdog (WDT) reset

...there is a slightly more informative value you get via node.bootreason(). It returns two values, the first as above(verify), the second is the extended reset cause, which is one of:

0  power-on
1  hardware watchdog reset
2  exception reset
3  software watchdog reset
4  software restart
5  wake from deep sleep
6  external reset
I mostly run into
2 4
where 4, software reset, which seems to include the software watchdog(verify) (confusingly enough).
4 1
is the hardware watchdog


Solving and avoiding reboot loops

This article/section is a stub — probably a pile of half-sorted notes, is not well-checked so may have incorrect bits. (Feel free to ignore, fix, or tell me)

If you manage to get an exception in early code, or trigger the hardware watchdog fairly early, then you may not be able to get the control you need to fix that.

There's always flashing the firmware again, and then wiping the flash. But that's a bunch of work, annoying during coding/debugging.

One way around that I like is to have init.lua contain something like:

abort = 0
function load_main()
   if abort ~= 0 then
      print("aborting startup")
      if file.exists('main.lua') then
        print("main.lua does not exist")
print("send  abort=1  to stop boot")
_start_timer = tmr.create()
_start_timer:register(1500, tmr.ALARM_SINGLE, load_main)

...and put your real code in main.lua.

That way, you have a little over a second before anything happens, in which time you can stop startup by sending


On watchdogs

This article/section is a stub — probably a pile of half-sorted notes, is not well-checked so may have incorrect bits. (Feel free to ignore, fix, or tell me)

There is both a

  • hardware watchdog
on by default, can be disabled (but there is rarely good reason to disable it)
part of the ESP's hardware
configured at approximately 6 seconds(verify)

  • software watchdog
on by default
C code that digs into the SDK, and amounts to a timer that decrements a counter and, if that counter reaches zero, calls system_restart()
accessible in Lua via tmr.softwd() to set a time, and tmr.wdclr() to feed it
apparently a value like 0.5 sec [8], 1.5 sec, or 3.2 sec (reports are mixed; TODO: figure out)

It seems that the SDK's system_soft_wdt_feed() feeds both.

tmr.wdclr() in Lua, and ESP.wdtFeed() in arduino(verify), mostly call system_soft_wdt_feed()
tmr.delay calls system_soft_wdt_feed while it is counting down (but is otherwise a wait loop, so long ones will mess with wifi{{verify||)
some libraries will also reset the watchdog in some places

The short version is that if code does not

call tmr.wdclr(), OR
call something that implies tmr.wdclr(), OR
returns to let the ESP idle

...for a significant time (between 0.5 or 6 seconds, see above), it will cause a reset.

Which makes sense. If you have code that takes more than 500ms without yielding in any way, you are likely breaking other things, not least of which the WiFi code, which can stutter (in smaller ways) if any task takes longer than approx 15ms.

If you do need to do a lot of processing, just make sure you yield occasionally so that that housekeeping can happen. This may mean rewriting to do small chunks at a time.

In Lua this is sometimes simple, because when you code in an event/callback style the idle task gets control regularly (and its feeds the dog(verify) and does the necessary housekeeping(verify)).

Keep in mind that it's not too hard to defeated the watchdog (e.g. feed it each loop but get into your own infinite loop) and can make things hang forever, and/or break wifi and other library code.

The likeliest problems that trigger the watchdog seem to be

  • an exception in the code
if you're me, largely variable typos and nil values you should be checking
presumably stops the current task so the watchdog
to avoid hanging forever, this is cause for reset (via watchdog?)
  • triggering a watchdog by having code hang, or take too long to complete
  • running out of heap space

Your own watchdogs

I have found reasons to have code like "if we didn't manage to do a HTTP fetch in a minute, for any reason, we probably want to reset"

...just because there are more reasons for that (that I can't easily check), and most of them will be rare enough that a reset is an easy clean slate.

You will want to decide which method of reset you prefer.

manual reset

If you have an ESP with USB, it probably has its DTR/RTS wired to GPIO0 and RST, there so you can get it into flash programming mode. [9], but you could also self-reset by wiring a GPIO pin to RST and do the same.

In some ways it's the cleanest, because apparently there are a few issues around some internal registers not being reset unless it's a hardware reset.(verify). But check that you don't get stray signals.

If you're not bothered by said register problems, then software resets probably using node.restart() is also an option.


TCP server

UDP server

HTTP requests

This article/section is a stub — probably a pile of half-sorted notes, is not well-checked so may have incorrect bits. (Feel free to ignore, fix, or tell me)

The http module is quite convenient.


          "", -- headers
          function(code, data)
            if (code < 0) then
              print("HTTP request failed")
              print(code, data)

Note that concurrent requests are not supported.

(I think an issue of mine (reported as HTTP client: DNS error code -1, I think) was that I was effectively doing this.)


The http module can use the tls module which is basically mbed TLS.

That means you can give it https links and it'll do the TLS part too. (Alternatively, you can do a TLS connection, and e.g. do a bare HTTP 1.0 request over it. See examples using tls.createConnection())

However, you basically don't have enough RAM to guarantee that large certificates, or large chains, can be processed properly - the process may easily need 30KByte or 40KByte of heap, which is usually most of what you have. Also, there is no real SNI support.

So you cannot guarantee all HTTPS requests to arbitrary servers will work, and the best workaround is to only ever send to a server you have precise control over the certificates being send, and possibly self-sign.

Arduino firmware notes

Current draw and sleep

This article/section is a stub — probably a pile of half-sorted notes, is not well-checked so may have incorrect bits. (Feel free to ignore, fix, or tell me)


~75mA with wifi on and idle-ish CPU
down to ~15mA with modem-sleep (WiFi radio waking up only occasionally)
~1mA with light-sleep (modem sleeping/off, CPU off between wifi(verify)),
~0.1mA with deep-sleep (which is roughly 'waiting to be rebooted from a pulse on RST pin')

Powering considerations:

Startup seems to include ~400mA for ~40ms[10] (RF calibration maybe?). Which is is just once and short
RF transmission peaks (connection, sends) may be ~200mA

(both shouldn't matter if there's any noticeable capacitance there)

On the sleep modes:

  • no sleep / active mode
ESP32: ~200mA if transmitting, ~100mA if not
  • modem sleep
keeps the CPU on, sleeps the wifi circuitry only
Since it times the sleep between AP beacons, this applies only once connected to an AP
should average ~15mA when not transmitting
seems to often be the default
NodeMCU: seems to apply automatically once we're connected to an AP(verify)
  • light sleep - pauses modem, system clock, CPU
~1mA ? (verify)
cannot enter light sleep if wifi suspended
woken via configured GPIO or timer(verify)
ESP32 can wake up via touch sensitive GPIO(verify)
wakeup takes takes ~3ms
NodeMCU: node.sleep() but NodeMCU apparently disables light sleep by default
  • deep sleep leaves on the RTC and almost nothing else
~0.01mA or 0.2mA ? (verify)
can apply when not maintaining a WiFi connection.
woken up a pulse on RST, which can come from our own RTC (if GPIO16/WAKE/D0 is wired to RST)
apparently there's a maximum to each interval[11]
there are flags controlling
whether wifi will be initialised after such a sleep (you can avoid a current spike if you don't need it)
whether a calibration will be done (which you want after longer sleeps(verify))
NodeMCU: node.dsleep()
  • hibernation (ESP32)
~3uA ? (verify)
deep sleep on the ESP32 leaves on a low-power coprocessor and the oscillator it needs, hibernation does not.

Note that

  • I need to look up the difference between ESP8266, ESP32
  • these currents are the ratings of the ESP itself, things like regulators will add to this.




Voltage and damage

This article/section is a stub — probably a pile of half-sorted notes, is not well-checked so may have incorrect bits. (Feel free to ignore, fix, or tell me)

Power should be 3.3V. (Powering from 5V power won't fry it immediately, but is likely to shorten lifespan, some people report sooner rather than later (and seemingly it's the flash that often fails first)

The ADC gets damaged by voltages above 1V, so you probably always want a voltage divider. And possibly a protection diode.

GPIO pins: Can I put 5V on GPIO pins ("are they 5V tolerant?") is a more interesting question.

The datasheet says: "All digital IO pins are protected from over-voltage with a snap-back circuit connected between the pad and ground. The snap back voltage is typically about 6V, and the holding voltage is 5.8V. This provides protection from over-voltages and ESD. The output devices are also protected from reversed voltages with diodes."

That mostly means 'more than 6V will not work' as it it triggers protection.

And doesn't answer what happens when you e.g. put a continuous 5V on there.

It does seem to mean there are protection diodes in there. But also that those are primarily for ESD, and 5V tolerance is a different question, more about implying how much current/heat the entire structure can deal with.

We don't really have the ratings, meaning it's probably a bad idea to put anything more than small and/or intermittent currents on them.

At the same time, people have experimentally determined that putting 5V on these inputs only sinks a few microamps, which is probably small enough to not to cause issues. Probably.

To be safe, you might still want to add series resistors just to be safe.

(that said, with two resistors you can make a voltage divider, and when you're prepared to throw some components at it, there are also other options - see level shifting)

On WiFi

This article/section is a stub — probably a pile of half-sorted notes, is not well-checked so may have incorrect bits. (Feel free to ignore, fix, or tell me)

Having it be stable

For wifi to be stable, no task should run for longer than ~15ms (quoth the SDK(verify)).

It may often be fine with more, because it may well recover, but it will be choppier.

When you think tasks may take longer, think some more about event, timer, and corouting style programming.

I also tend to add a "can I DNS-resolve things" test, so that it can reconnect, or switch APs, when one does not work for some reason.

(...which I can still mess up by spamming the ESP with UDP packets)

How to tell it about APs

The basic way to do credentials is hardcoding one, or maybe a few that code loops through a few stored APs. This works until you move it, or replace your AP, at which point you have to put in new credentials, probably via usb-serial.

The fancier thing to do is a wifi manager that, if it can't find one of the previously configured AP's, puts the ESP into soft AP mode with a webserver, and lets you set AP via a simple web interface.

For NodeMCU: https://github.com/gfnord/lua_wifimanager

For arduino: https://github.com/tzapu/WiFiManager (slightly nicer)

Wifi current draw





serial.serialutil.SerialException: Cannot configure port, something went wrong. Original message: PermissionError(13, 'A device attached to the system is not functioning.', None, 31)

...when uploading a sketch.

For me this seemed caused by esptool not finding the device in the right state - presumably because I had selected the wrong board variant?

I did get it to work by holding the boot button.

Which is a problem and solution possibly very specific to my case.