Experimenting with ESP32 & ESP8266 microcontrollers

Michael K
10 min readMay 19, 2022
NodeMCU ESP-C3–32S and D1 Mini next to each other
NodeMCU ESP32-C3–32S & D1 Mini

Using a microcomputer, like the Raspberry Pi, for a dedicated small task is often overkill when that task can be done with microcontrollers in an easier and usually more cost-efficient manner. Microcontrollers also tend to be easier to find in stock versus Raspberry Pis — which is useful in the supply-chain constrained world we currently live in. Depending on your exact use case, certain microcontrollers include support for WiFi or Bluetooth as well.

An assortment of Microcontrollers and Microcomputers are arranged next to each other: Adafruit QT Py ESP32-S2, Adafruit QT Py RP2040, RPi Pico, RPi Zero W, RPi 4, D1 Mini, NodeMCU ESP-C3–32S.
Size comparison of various microcomputers and microcontrollers

My requirements

I tend to lean towards CircuitPython or MicroPython which is well supported on hundreds of boards, however, if you enjoy using C++, the number of supported boards is even higher. Right now, I tend to use a lot of Raspberry Pi Zero W’s around my house for different tasks using Wifi, LEDs, I2C, and SPI. Also, most of my tasks don’t require multithreading so I can even consider single-core solutions.

This is where the Espressif chips shine as they handle almost all of my requirements, including keeping the cost down. Two boards I picked up to play around with were the NodeMCU ESP-C3–32S Dev-Kit (ESP32) and D1 Mini (ESP8266). Both of these boards can be picked up for $3 — $10 depending on the retailer and support MicroPython but only the ESP32 board supports CircuitPython. They also both include USB to serial chips so no additional hardware is required to flash them.

NodeMCU ESP-C3–32S and D1 Mini next to each other
NodeMCU ESP32-C3–32S and D1 Mini

Flashing the firmware

To use MicroPython or CircuitPython, we’ll need to first flash the firmware onto the board. In order to do this, we’ll use esptool.py, a tool managed by Espressif themselves to interface with their chips easily. To install it, we’ll use Pip:

$ python3 -m pip install esptool

After the tool is installed, plug the board into your device. Next, we’ll need to determine which port the board is connected to so we can continue. If you are using a Linux-based system, like the Raspberry Pi, this is pretty straightforward:

$ dmesg | grep ttyUSB 
[ 5832.313400] usb 1-1.3: ch341-uart converter now connected to ttyUSB0

Based on the above message, I can see that my board is attached at /dev/ttyUSB0. If you are using Windows or Mac, the instructions here by Sparkfun are very detailed and will cover any scenarios you may run across.

Installing CircuitPython

Since the ESP32 board I picked up supported CircuitPython, I decided to install CircuitPython on this board and MicroPython on the D1 Mini. We can use esptool.py to check the size of the flash as this board comes in two sizes, 2MB and 4MB. Whenever we go to flash CircuitPython we have to know this size so we grab the right file.

$ esptool.py --port /dev/ttyUSB0 flash_id
esptool.py v3.3
Serial port /dev/ttyUSB0
Connecting....
Detecting chip type... ESP32-C3
Chip is ESP32-C3 (revision 3)
Features: Wi-Fi
Crystal is 40MHz
MAC: [redacted]
Uploading stub...
Running stub...
Stub running...
Manufacturer: 5e
Device: 6015
Detected flash size: 2MB <- Flash size
Hard resetting via RTS pin...

Based on the response, the board I have connected is 2MB. With this information, the next step is to head over to the CircuitPython Downloads page and search for this kit’s name: esp-c3-32s . Two results will be returned, one for the 4MB version and the other for the 2MB version. After selecting the correct flash size, the firmware can be downloaded for the next step.

Next, we need to erase the existing data on the board so we have a clean slate when loading CircuitPython. Using esptool.py, we can easily erase the flash and then load CircuitPython.

$ esptool.py --port /dev/ttyUSB0 erase_flash
...
Chip erase completed successfully in 8.9s
Hard resetting via RTS pin...
$ esptool.py --chip esp32c3 --port /dev/ttyUSB0 --baud 460800 write_flash -z 0x0 ~/Downloads/adafruit-circuitpython-ai_thinker_esp32-c3s-2m-en_US-7.2.5.bin
...
Wrote 1475808 bytes (877420 compressed) at 0x00000000 in 26.4 seconds (effective 447.0 kbit/s)...
Hash of data verified.
Leaving...
Hard resetting via RTS pin...

Testing CircuitPython

Now that CircuitPython has been loaded we can load up an interactive editor, like Thonny or Mu Editor, and connect to our board to run some code or upload our scripts and libraries as needed. Unlike other CircuitPython boards, an extra drive won’t appear attached to your device where you can easily drag and drop files. To connect to the board, in the bottom right corner of the editor, click the Python version being shown and select ‘CircuitPython’ instead.

Thonny’s output terminal is shown with a REPL session active. The board module was imported and then had the “dir” command ran on it to list all of it’s properties. Numerous IO pins, LED pins, and others are shown to the user with the LED pins highlighted in yellow.
CircuitPython’s board module makes our life much easier

To see what all we have available to us, we can use the board module. As shown in the output above, this developer kit contains quite a few different LEDs so as is tradition with microcontrollers, let’s create a blink script:

In our editor, open a new file and paste the code above into it and click save. When asked, we’ll want to save this code onto our CircuitPython device and name the file test.py. If you wanted to run your code as soon as the microcontroller boots, you can name it code.py, however, you typically don’t want to do this until your code is completely ready. We can then click the ‘Play’ button to run our code and watch in amazement at the flashing lights!

CircuitPython Libraries

In order to use some common libraries that are not included in CircuitPython, such as datetime or requests , you’ll have to download the library bundle provided by CircuitPython. First, navigate to the Libraries page and download the Bundle for Version 7.x . Once downloaded, unzip the archive and list the contents of the lib folder. Within this folder are all of the precompiled libraries available for your use which also includes libraries for various sensors. You can also download the Community Bundle , which contains extra libraries from the community.

The libraries included within the bundle are shown in a file explorer in list format
Some of the libraries included in the bundle

Uploading libraries

If you are using Thonny, you’ll first have to enable regular mode by clicking the text in the top right to enable normal mode, closing Thonny, and reopening it. Afterward, click ‘View’ in the top toolbar, and then click ‘Files’. This will open a new sidebar allowing you to easily manage the files on the board. In the bottom window of the File Explorer within Thonny, double-click the lib folder. In the top window, navigate to where you have extracted the CircuitPython bundle and right-click on any desired library, and click ‘Upload to /lib’.

Installing MicroPython

As the D1 Mini can come in multiple flash sizes as well, we must know which size we are using. It’s super simple to use esptool.py again to check the flash size just as we did with the ESP32 device:

$ esptool.py --chip esp8266 --port /dev/ttyUSB0 flash_id
esptool.py v3.3
Serial port /dev/ttyUSB0
Connecting....
Chip is ESP8266EX
Features: WiFi
Crystal is 26MHz
MAC: [redacted]
Uploading stub...
Running stub...
Stub running...
Manufacturer: ef
Device: 4016
Detected flash size: 4MB <- Flash size
Hard resetting via RTS pin...

Based on the response, the board I have is 4MB. Now that we know this, we can go to the MicroPython Downloads page and click on “esp8266” in the list of ports. In the list, we’ll want to select the one that corresponds with our flash size. Since my board is 4MB, I’ll pick the ESP8266 with 2MiB+ flash firmware and download the latest release.

The next step is to erase the existing data on the board so we have a clean slate when loading MicroPython. Using esptool.py, we can easily erase the flash and then load MicroPython. In the write_flash command, ensure you pass the right flash size or the board will not work correctly (ex. --flash_size=4MB).

$ esptool.py --chip esp8266 --port /dev/ttyUSB0 erase_flash
...
Chip erase completed successfully in 4.5s
Hard resetting via RTS pin...
$ esptool.py --chip esp8266 --port /dev/ttyUSB0 --baud 406800 write_flash --flash_size=4MB -fm dio 0x0 ~/Downloads/esp8266-20220117-v1.18.bin
...
Wrote 635992 bytes (418428 compressed) at 0x00000000 in 11.3 seconds (effective 451.3 kbit/s)...
Hash of data verified.
Leaving...
Hard resetting via RTS pin...

Testing MicroPython

With MicroPython loaded, we can now load up an interactive editor much like we did for CircuitPython and connect to our board to run code snippets or upload our scripts. Following tradition, we can also create a blink script as we did for the ESP32 device since the D1 Mini has an LED connected to GPIO2.

In our editor, open a new file and paste the code from above into it and click save. When prompted, we’ll want to save this code onto our MicroPython device and name it test.py. To run scripts as soon as the microcontroller boots, you can name files main.py , however, you don’t want to do this until you have your code completely ready. We can then click the Play button and watch our board blink away!

Loading libraries

Unlike CircuitPython, we do not have a lib folder where we need to upload our libraries. Instead, uploading them to the root directory with your script is fine. From there, they can be easily imported into your scripts as needed. An extensive list of great MicroPython projects can be found here, which was of much help while building some test projects.

To upload libraries to the board, much like the ESP32 device, we’ll need to use an interactive editor to upload the files to the board. The instructions mentioned in the CircuitPython section would apply here as well, minus putting the libraries into the lib folder as previously mentioned.

Quick projects

To get more hands-on experience with the boards, I figured the best way was to get my hands dirty with them and build a few projects. I purchased a pack of MPU6050 sensors for the ESP8266 project and I luckily already had an extra AHT20 sensor laying around for the ESP32 project.

ESP32 w/ CircuitPython

One of the main projects I was interested in using the Espressif devices to replace was my numerous climate sensors around my house. Currently, they run on Raspberry Pi Zero Ws which are quite overkill for the task. For the climate sensor, I’m using an AHT20 which can be picked up for $1-$5 depending on the retailer. Since the ESP-C3–32S kit I picked up runs CircuitPython it was the perfect choice to use.

In order to replicate that functionality, but instead send the data to a remote server, we’ll need to load a few libraries from the CircuitPython bundle mentioned previously:

  • adafruit_ahtx0
  • adafruit_datetime
  • adafruit_requests
The ‘Files’ UI of Thonny is shown with the three libraries mentioned in the article uploaded to the “lib” folder of the CircuitPython device.

With these libraries loaded into the lib folder, we can move on to the code. Other than setting up I2C and the sensor, we’ll need to set up the wireless connection, socket pool, and requests session for our remote requests, which wouldn’t be required if you were only doing offline work.

To hook the sensor up to the I2C bus, I used IO7 for SCL and IO8 for SDA. If everything checks out with the script, we can reupload our script with the name code.py so our script runs as soon as the board is powered. After all was said and done, I attached the sensor to the board as shown below and replaced the placeholder API used in the example. Overall, I am very satisfied with these boards as they can replicate the functionality as needed and even contain multiple LEDs which the Pi Zero doesn’t have.

NodeMCU ESP-C3–32S shown with an AHT20 sensor attached using Nylon screws
NodeMCU ESP32-C3–32S and an Adafruit AHT20 sensor attached

ESP8266 w/ MicroPython

My house has a dedicated utility room which contains my clothes washing and drying machine. A great feature, however, if my girlfriend and I are across the house and trying to do multiple loads of laundry, we may not hear one of the machines finish running so we know to add the next load. A very small problem but an easy one to solve with some code and an accelerometer.

A green perf board is shown with two buttons, a D1 Mini and an MPU6050 accelerometer attached.
D1 Mini & MPU6050 assembled on a perf board with buttons

The script I wrote samples the accelerometer every five seconds and then averages the values returned over the course of a minute. Once five minutes of data have been collected it will compare the averages to the baseline values observed while the machine was not running when first setup. If the values aren’t within 15 points of the baseline values it considers the machine still running. Once the script determines the machine is no longer running, it submits a request to a remote API to send an email using AWS SES to both of us to let us know it has finished.

Powering the project is an MPU6050 accelerometer which can be purchased online for $1-$3 depending on the retailer. To provide an easy way to start/stop the script, I added two momentary switches and wired them up to two of the additional GPIO pins available. I also used the onboard LED to provide a status update when it was running or idle, or when switching modes.

For a clean install, I used a small perf board and soldered the components onto it with all of the soldering and connections on the backside. I also used female header sockets to connect the accelerometer and D1 Mini so they could be easily removed in the future. Finally, I attached the setup to a spare ABS plastic sheet cut to size with double-sided tape on the backside for attaching to the machine itself.

Fritzing chart of the wiring. SDA: D2, SCL: D1, Button A: D5, Button B: D6. Two 10K ohm resistors are used as a pull-down for the buttons
Fritzing design of how I set up the hardware

You can find the repository for the code here, along with the additional files needed for execution such as the configuration and accelerometer class.

Conclusion

Overall, I am very impressed with the Espressif chips so far. I am very excited to get my hands on a dual-core board here soon to test some more intensive tasks as well. I also really want to experiment with displays as some of the projects I have in mind will need one.

Links

--

--

Michael K

Software Engineer with a passion for helping spread technical knowledge about my favorite hobbies from microcontrollers to automotive and much more.