The ESP32 is a dual-core microcontroller that has both WiFi and Bluetooth. The ESP32 is the next generation of the older single-core microcontroller ESP8266 that only had WiFi. You can perform most tasks that you did with the various Arduinos but with the ESP32 (or ESP8266) and you also have WiFi embedded into the microcontroller. You can even use the Arduino IDE to write programs for the ESP32 (or ESP8266).
In the following, we learn a bit more about the ESP32 and what to buy. Then, we set up our Ubuntu (or other Linux distribution) so that we develop the ESP32 inside a LXD container. That is, instead of messing our desktop Linux with the ESP32 development packages, we create a development LXD container for ESP32 and put them all inside there.
What is the ESP32?
The ESP32 is a microcontroller. It is a tiny chip, just 6mm × 6mm. That’s the dimensions of the version we are using (newer versions are even smaller). It’s so tiny for practical use, s o you can get it in a compact surface-mount PCB module such as the ESP-WROOM-32 for around $3. The ESP-WROOM-32 is still quite small, at 25.5 mm × 18 mm which makes it impractical for most uses, so you can instead get it on a development board for around $7. In this post we are using one such development board.
In the following image you can see a ESP32 development board. It is 5cm long and 3cm wide. Unfortunately, it’s a little bit too wide to fit on a single breadboard and does not fit either on two breadboards when attached together. Here we see the board placed on two breadboard that are at a distance from each other. The ESP-WROOM-32 is shown in the image and you can just see the EM shield (metallic, silver in color and has a hole on one corner) that shields the whole package. The antenna is nearby. On the other side, there is the micro USB port, used for both power and communication with the PC. There are two buttons (marked EN and BOOT) and many pins to create all sort of interesting applications. There are also 2 LEDs, and one of them is accessible through GPIO 2.
Connecting to the USB port
Let’s connect the ESP32 development board to the computer. Here are the relevant kernel messages (run dmesg). It shows that we now have the device ttyUSB0. This can be found in /dev/ttyUSB0.
[24485.247128] usb 3-9: new full-speed USB device number 11 using xhci_hcd
[24485.426129] usb 3-9: New USB device found, idVendor=10c4, idProduct=ea60
[24485.426135] usb 3-9: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[24485.426140] usb 3-9: Product: CP2102 USB to UART Bridge Controller
[24485.426143] usb 3-9: Manufacturer: Silicon Labs
[24485.426147] usb 3-9: SerialNumber: 0001
[24486.469956] usbcore: registered new interface driver usbserial_generic
[24486.470092] usbserial: USB Serial support registered for generic
[24486.472154] usbcore: registered new interface driver cp210x
[24486.472189] usbserial: USB Serial support registered for cp210x
[24486.472210] cp210x 3-9:1.0: cp210x converter detected
[24486.474497] usb 3-9: cp210x converter now attached to ttyUSB0
Here is the device file.
$ ls -l /dev/ttyUSB0
crw-rw-rw- 1 root dialout 188, 0 Sep 28 00:00 /dev/ttyUSB0
Testing the ESP32
You have connected the ESP32 board to your computer and the red LED is on. That red LED means that the ESP32 is on. There is also another LED, a blue one, that can be accessed by user programs. When I first powered on my ESP32 board, it already had installed some blink program and the blue LED was blinking. Probably they install that application during quality control at the factory.
Let’s get some feedback that the ESP32 board is really working. Run the following command. You will get a blank terminal window.
$ screen /dev/ttyUSB0 115200
Now, press the EN button on the ESP32 board. You will get output similar to the following. The ESP32 rebooted, and you can see the boot messages.
ets Jun 8 2016 00:22:57
rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
mode:DIO, clock div:2
ho 0 tail 12 room 4
I (30) boot: ESP-IDF v3.2-dev-1145-g66fd7e9cc 2nd stage bootloader
I (30) boot: compile time 10:53:21
I (31) boot: Enabling RNG early entropy source…
I (36) boot: SPI Speed : 40MHz
I (41) boot: SPI Mode : DIO
I (45) boot: SPI Flash Size : 4MB
I (49) boot: Partition Table:
I (52) boot: ## Label Usage Type ST Offset Length
I (60) boot: 0 nvs WiFi data 01 02 00009000 00006000
I (67) boot: 1 phy_init RF data 01 01 0000f000 00001000
I (75) boot: 2 factory factory app 00 00 00010000 00100000
I (82) boot: End of partition table
I (86) esp_image: segment 0: paddr=0x00010020 vaddr=0x3f400020 size=0x08af4 ( 35572) map
I (108) esp_image: segment 1: paddr=0x00018b1c vaddr=0x3ffb0000 size=0x02110 ( 8464) load
I (111) esp_image: segment 2: paddr=0x0001ac34 vaddr=0x3ffb2110 size=0x00000 ( 0) load
I (115) esp_image: segment 3: paddr=0x0001ac3c vaddr=0x40080000 size=0x00400 ( 1024) load
I (124) esp_image: segment 4: paddr=0x0001b044 vaddr=0x40080400 size=0x04fcc ( 20428) load
I (141) esp_image: segment 5: paddr=0x00020018 vaddr=0x400d0018 size=0x1284c ( 75852) map
I (168) esp_image: segment 6: paddr=0x0003286c vaddr=0x400853cc size=0x03c5c ( 15452) load
I (175) esp_image: segment 7: paddr=0x000364d0 vaddr=0x400c0000 size=0x00000 ( 0) load
I (175) esp_image: segment 8: paddr=0x000364d8 vaddr=0x50000000 size=0x00000 ( 0) load
I (190) boot: Loaded app from partition at offset 0x10000
I (190) boot: Disabling RNG early entropy source…
I (196) cpu_start: Pro cpu up.
I (199) cpu_start: Starting app cpu, entry point is 0x40080eb4
I (0) cpu_start: App cpu up.
I (210) heap_init: Initializing. RAM available for dynamic allocation:
I (217) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (223) heap_init: At 3FFB3150 len 0002CEB0 (179 KiB): DRAM
I (229) heap_init: At 3FFE0440 len 00003BC0 (14 KiB): D/IRAM
I (235) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (242) heap_init: At 40089028 len 00016FD8 (91 KiB): IRAM
I (248) cpu_start: Pro cpu start user code
I (266) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
The ESP32 board works and we can see interesting information. To exit the screen program, press Ctrl+A and then press k (kill). You will be prompted whether you are sure; press y (for Yes). You can get help for the various screen options if you type Ctrl+A ?.
The next step is to create a LXD container and set it up so that the container can access the device /dev/ttyUSB0.
Creating the LXD container
Let’s create the container and name it esp32.
$ lxc launch ubuntu:18.04 esp32
Then, share the device /dev/ttyUSB0 into the container. The command creates a Unix character file into the container and links it to the one on the host.
$ lxc config device add esp32 ttyUSB0 unix-char source=/dev/ttyUSB0 path=/dev/ttyUSB0 major=188 minor=0 uid=0 gid=20 mode=666
Device ttyUSB0 added to esp32
We are ready to enter the container and do stuff.
Setting up the esp32 LXD container
Let’s get a shell into the LXD container.
$ lxc exec esp32 -- sudo --user ubuntu --login
Run again the screen command as before, to test that the ESP32 board is accessible in the LXD container.
After you have done that, you can compile the ESP-IDF toolchain that can be used to compile ESP32 programs without a particular GUI. To do so, run the following script that sets up the environment for you. Save it as build-esp32-toolchain.sh If you saved it on the host, you can transfer it to the container with lxc file push build-esp32-toolchain.sh esp32/home/ubuntu/
Finally, run the script in the LXD container. The script creates a directory esp/ and adds in there the ESP32 toolchain and the ESP-IDF development framework. Additional, the script adds the appropriate environment variables to help use the installed software.
$ bash build-esp32-toolchain.sh
This command will be completed successfully as soon as you see the following output.
Base directory: /home/ubuntu/esp
ESP-Toolchain directory: /home/ubuntu/esp/xtensa-esp32-elf/bin
ESP-IDF directory: /home/ubuntu/esp/esp-idf
We are ready to compile our first ESP32 software. But first, log out and log in again to the container in order for the environment variables to get updated.
$ lxc exec esp32 -- sudo --user ubuntu --login
And we are back into the container.
Compiling the blink sample ESP-IDF program
Let’s compile some of the samples of the ESP-IDF development framework. First, we try the blink sample that makes the blue LED blink.
ubuntu@esp32:~$ cd esp/esp-idf/examples/get-started/blink/
During the compilation, you will be presented with the SDK configuration for ESP-IDF. The SDK configuration has the generic configuration but also any additional configuration for the specific program. In the case of the blink sample, there is a configuration here, called Example Configuration. Use the arrow keys to move to Example Configuration and press Enter.
You are presented with the following menu that shows the default GPIO of 5. This ESP32 board uses 2 instead. Press Enter to change the 5 into a 2.
Here we changed to 2 and we press Enter.
Then, click on Exit multiple times until you exit the SDK configuration environment. You will be prompted to save the configuration. Click on Yes to continue.
When the compilation is completed successfully, you will get the following output.
To flash all build output, run 'make flash' or:
python /home/ubuntu/esp/esp-idf/components/esptool_py/esptool/esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 115200 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect 0x1000 /home/ubuntu/esp/esp-idf/examples/get-started/blink/build/bootloader/bootloader.bin 0x10000 /home/ubuntu/esp/esp-idf/examples/get-started/blink/build/blink.bin 0x8000 /home/ubuntu/esp/esp-idf/examples/get-started/blink/build/partitions_singleapp.bin
The process of writing the program onto the ESP32 board is called flashing. We are prompted to flash the program with make flash. We oblige.
ubuntu@esp32:~/esp/esp-idf/examples/get-started/blink$ make flash
Toolchain path: /home/ubuntu/esp/xtensa-esp32-elf/bin/xtensa-esp32-elf-gcc
Toolchain version: crosstool-ng-1.22.0-80-g6c4433a
Compiler version: 5.2.0
Python requirements from /home/ubuntu/esp/esp-idf/requirements.txt are satisfied.
Flashing binaries to serial port /dev/ttyUSB0 (app at offset 0x10000)…
Serial port /dev/ttyUSB0
Chip is ESP32D0WDQ6 (revision 1)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse
Configuring flash size…
Auto-detected Flash size: 4MB
Flash params set to 0x0220
Compressed 22752 bytes to 13481…
Wrote 22752 bytes (13481 compressed) at 0x00001000 in 1.2 seconds (effective 152.7 kbit/s)…
Hash of data verified.
Compressed 157024 bytes to 74122…
Wrote 157024 bytes (74122 compressed) at 0x00010000 in 6.6 seconds (effective 191.3 kbit/s)…
Hash of data verified.
Compressed 3072 bytes to 103…
Wrote 3072 bytes (103 compressed) at 0x00008000 in 0.0 seconds (effective 1751.1 kbit/s)…
Hash of data verified.
Hard resetting via RTS pin…
And, that’s it. Now the ESP32 board is blinking.
Compiling the helloworld sample
Now it is the turn of the hello_world sample. Run the following commands. If you are prompted to edit the configuration, simply click on Exit, then Save to continue the compilation.
ubuntu@esp32:~$ cd esp/esp-idf/examples/get-started/hello_world/
ubuntu@esp32:~/esp/esp-idf/examples/get-started/hello_world$ make flash
The sample has been flashed on the ESP32 board but nothing happens. What is this sample supposed to do?
Let’s get access to the serial console as before.
ubuntu@esp32:~/esp/esp-idf/examples/get-started/hello_world$ screen /dev/ttyUSB0 115200
The serial console shows that the ESP32 board indeed prints “Hello world!”, then prints some package features (dual core, WiFi/BT/BLE, revision 1 and 4MB external flash). Finally, it performs a countdown before it restarts again.
At the end, you can exit the screen command as shown earlier in this post.
We have seen how to set up a LXD container in order to run the ESP-IDF development environment. You can then try some more samples, including those about WiFi (you can get the ESP32 board to scan for available networks) and Bluetooth.
The next step would be to install the Arduino IDE into the container. See the post on how to set up a GUI LXD container. As a hint, you can easily install the Arduino IDE using Ubuntu Make. A future post will show how to do this.