Docker-based ESP32 Development Environment

Aug 27, 2023·

5 min read

Play this article

In the previous article, I discussed the benefits of using Docker containers for building and managing development environments. In this post, I would like to describe how I use the Docker Dev Environment to create a development environment for building ESP32 applications. Additionally, it is also possible to flash the application directly to an ESP board from within the container.

Luckily for us, Espressif has provided a Docker image (espressif/idf) for building applications and libraries with specific versions of ESP-IDF. It appears that the image is regularly, making it reasonably safe to employ it for our setup.

Setup

  • For this setup, you are using a host system running Windows OS with WSL2 enabled. The WSL2 will be used so that we can access the ESP development board from within the container.
  • Docker Desktop installed

  • The IDE used here is VSCode with the Dev Containers installed. It lets you use a Docker container as a full-featured development environment.

Constructing compose-dev.yaml

To use the Docker Dev Environment, we need to create the compose-dev.yaml file. It is quite simple with a few additions.

services:
  build-env:
    image: espressif/idf
    command: sleep infinity
    devices:
      - '/dev:/dev'
    init: true
    volumes:
      - ..:/workspaces

I added devices: '/dev:/dev' to map /dev directory from the WSL2 environment to the Docker container. This is useful for the next step when we want to communicate with the ESP board from inside the container.

Open Docker Desktop and go to Dev Environments. Simply click on the Create button and create the new environment. The container will stay running and you will see the following results.

Flashing and Monitoring ESP32

The ESP-IDF Programming Guide page outlines a method to communicate with the development boards from within the container. The idea is to use the remote serial port protocol (RFC2217). So I tried to follow the method described in the document, but it was not successful for me. Luckily there is another way to achieve this.

An alternative way for accessing the ESP development board from inside the container is using WSL2. By default, WSL2 does not support USB devices. Fortunately, there is a project officially supported by Microsoft that enables WSL2 to be able to access connected USB devices on Windows OS via a USB/IP mechanism. The project is called usbipd-win.

Setting up usbipd-win

  1. Firstly we need to install usbipd-win. We just need to follow the installation instructions described on its Github repository page. It is pretty straightforward.

  2. Open the WSL2 terminal and execute uname -a. If it reports a kernel version of 5.10.60.1 or later, then you don't need to do anything. Otherwise, follow the instructions on installing USB/IP client tools on WSL2 here.

  3. Run Powershell as Administrator and execute the following command.

     ### Powershell
     PS C:\Windows\system32> usbipd wsl list
     BUSID  VID:PID    DEVICE                                                        STATE
     2-1    303a:1001  USB Serial Device (COM3), USB JTAG/serial debug unit          Not attached
     2-2    046d:c534  USB Input Device                                              Not attached
     2-3    0bda:4853  Realtek Bluetooth Adapter                                     Not attached
     3-1    04f2:b758  Integrated Camera, Integrated IR Camera, Camera DFU Device    Not attached
    

    Find the USB device of your ESP development board connected. In this example, it is assigned BUSID 2-1

  4. Attach the USB device to WSL2 by running this command.

     ### Powershell
     PS C:\Windows\system32> usbipd wsl attach --busid 2-1
     usbipd: info: Using default WSL distribution 'Ubuntu-22.04'; specify the '--distribution' option to select a different one.
    
  5. Go back to the WSL2 terminal and run lsusb to see that the ESP32 development can be accessed from WSL2 now via /dev/ttyACM0 (or /dev/ttyUSB0).

     ### WSL2
     > lsusb
     Bus 001 Device 014: ID 303a:1001 Espressif USB JTAG/serial debug unit
    
     > ls -al /dev/tty*
     ...
     crw------- 1 root root 166,  0 Aug 26 17:27 /dev/ttyACM0
     ...
    
  6. Now we need to change the permission so that the device can be accessed by non-root users.

     ### WSL2
     > sudo chmod 666 /dev/ttyACM0
    

If you remember, we added an extra field in the compose-dev.yaml file. With this option, we map the /dev directory of WSL2 into the Docker container. Hence, it is possible to access your development board from inside the container.

...
    devices:
      - '/dev:/dev'
...

Automating usbipd

Attaching USB devices using usbipd requires manual steps that need to be executed whenever we plug or re-plug our ESP development board. It can be quite annoying over time. Luckily, there is a convenient GUI that can automate all these steps. This project was created by Andrew Leech. You can just download the package from here and install it.

The GUI is quite self-explanatory. You just need to find your ESP development board and click on 'Auto-Attach'. With this feature enabled, your ESP development board will be attached automatically.

udev

On WSL2, we have to configure the attached USB device so that non-root users can access it. We can use the chmod command to configure it manually, but then we have to do it every time the USB device is re-attached. To avoid all the hassles, we can create a udev rule.

Create a new file called 99-usbftdi.rules on /etc/udev/rules.d/ and add the following information to the file. The {idVendor} and {idProduct} values can be obtained from lsusb

> lsusb
Bus 001 Device 014: ID 303a:1001 Espressif USB JTAG/serial debug unit

> cat /etc/udev/rules.d/99-usbftdi.rules
SUBSYSTEM=='usb', ATTRS{idVendor}=="303a", ATTRS{idProduct}=="1001", MODE="0666"

# Then reload udevadm and restart the udev service
> udevadm control --reload
> sudo service udev restart

Now, every time the development board is plugged in, it will be automatically attached to your WSL2 environment and can be readily accessed from the container.

Final Result

Upon the successful creation of the development environment, the container can be opened in VSCode. The VSCode extensions, such as CMake and C++, will also be automatically installed.

If everything is correctly configured, it is possible to build the application inside the container

Since the container can access the USB device via WSL2, we are also able to directly flash the image to the ESP development board.


In this article, we discuss creating a Docker container using the Docker Dev Environment for building ESP32 applications and flashing them directly to an ESP board from within the Docker container. This streamlined workflow simplifies the development process and ensures a consistent development environment across different systems.

You can see the full setup on my Github repository.

Did you find this article valuable?

Support Aries Gun by becoming a sponsor. Any amount is appreciated!