31. March 2022

How to develop for ESP32-C3 with Rust on macOS with Podman using Dev Container in VS Code

Development in Dev Containers using VS Code greatly simplifies bootstrapping of the development environment. The developer does not need to install toolchains locally and spends a lot of time composing the development environment.

The default installation of VS Code is configured to work with Docker. It requires some small additional steps to switch to Podman.

Let’s begin with development using examples from Ferrous Systems training:

git clone https://github.com/ferrous-systems/espressif-trainings.git

Install Podman and check version:

brew install podman
podman --version

The version should be at least 4.0. If you have a previous version, consider an upgrade.

Following step might not be obvious to Docker users. Docker creates VM for managing containers in the background without asking the user. In the case of Podman, this is more versatile and you can define what kind of machine do you want to create. Here are a few options recommended for development, when you omit them you’ll get smaller defaults.

podman machine init --disk-size 20 --cpus 8 -m 4096 -v ${HOME}/espressif-trainings:${HOME}/espressif-trainings
podman machine start

Please, notice also -v option which mounts the development directory to Podman VM, without this mount you’ll get:

Error: statfs espressif-trainings: no such file or directory

Now the Podman VM should be ready and we can spin up containers. Go to the project directory and open Visual Studio Code:

cd ${HOME}/espressif-trainings
code .

It’s necessary to install one additional dependency for Podman: podman-compose

pip3 install podman-compose

It’s necessary to tell VS Code to use podman instead of docker commands. Go into Settings and search for keyword docker. Replace docker by podman and docker-compose by podman-compose.

VS Code is ready and click Reopen in Container.

Pulling the base image might take a while.

Open terminal and build the first ESP32-C3 example:

cd intro/hardware-check
cp cfg.toml.example cfg.toml
cargo build

Note: If VS Code is complaining about existing vscode volume, it’s possible to remove it by command

podman volume rm vscode

Note 2: If the remove is blocked by the existing terminated container, it’s possible to clean the reference by command

podman container prune

Flashing of the resulting file could be done by espflash and mounting device to Podman or using the tool like Adafruit WebSerial ESPTool. The file for flashing is located in the directory target/release.

1. December 2021

How to connect ESP32 as USB serial device to Linux in WSL2 on Windows 11

There is a nice article and video explaining how to connect USB serial to Linux in WSL2.

Just few details are missing. Here is the full list of steps necessary to flash ESP32 with FTDI from WSL2:

  • Install Windows 11, open Windows Update – join Windows Insider Program (Beta channel) – install updates, reboot machine
  • Windows Update – Advanced Options – check the option “Receive updates for other Microsoft products” – Back – Check for updates
  • Reboot or shutdown WSL2 images
  • start a new WSL2 image e.g. with Ubuntu 20 LTS, check that you have kernel 5.10: uname -a. It does not work on 4.x kernel from normal WSL2
  • install https://github.com/dorssel/usbipd-win/releases on Windows
  • in Linux – sudo apt install linux-tools-5.4.0-77-generic hwdata
  • in Linux – visudo
  • in Linux – prepend path Defaults secure_path=”/usr/lib/linux-tools/5.4.0-77-generic:
  • connect ESP device with FTDI in Windows PowerShell (administrator) type: usbipd wsl list
  • search for 5-3 USB Serial Converter A, USB Serial Converter B Not attached
  • type in Windows: usbipd wsl attach -b 5-3 -d Ubuntu
  • type in Linux:cd examples/get-started/blink; idf.py build flash monitor

Result:

I (263) example: Example configured to blink addressable LED!
I (263) example: Turning the LED OFF!
I (1273) example: Turning the LED ON!

3. September 2021

How to flash ESP32 from WSL

WSL (Windows Subsystems for Linux) is a great way how to build projects based on ESP-IDF. The problem is how to flash the image from WSL Linux to a real chip?

Right now only WSL1 supports mapping of Windows COM ports to Linux /dev/ttyS*.

First of all, make sure that your image is running WSL1 (which is slower than WSL2):

wsl -l -v

In the case of WSL2 image, you can convert it by the following command (let assume the image of Ubuntu):

wsl -t Ubuntu
wsl --set-version Ubuntu 1

Use Windows Device Manager to determine COM ports of your ESP chip. Similar could be achieved by command:

mode

The number of COM.. device will be mapped to the /dev/ttyS.. in Linux.

Start the Linux terminal (e.g. using Windows Terminal). Grant permission so that your user can read write /dev/ttyS* or add your user to dialout group if supported by distribution. Note: on Linux, the device is often mapped to /dev/ttyUSB*, notice the difference on Windows /dev/ttyS*.

chmod a+rw /dev/ttyS*

Build and flash the project. It’s necessary to specify the device name, because autodetection in idf.py is not able to find /dev/ttyS. The second important part is to set the communication speed by “-b” option.

idf.py flash --port /dev/ttyS11 -b 115200
idf.py monitor --port /dev/ttyS11

The last command should launch idf monitor, which you can terminate by CTRL+].

If you’re WSL2 user, you can try alternative approach using idfx tool.

18. July 2020

How to connect ESP8266 Wemos D1 to motor shield over I2C with MicroPython

ESP8266 Wemos D1 board has extension shield TB6612FNG which provides a connection to two motors.

The simplest way to get motors running is to connect the shield to ESP8266 and provide instructions to MicroPython repl so that ESP8266 can send instructions over I2C to TB6612FNG.

The first requirement to get the motor running is to have d1motor library.

You can download ZIP with patched d1motor library and sample code from here.

Original d1motor is available here: https://bitbucket.org/thesheep/micropython-d1motor/src/default/d1motor.py

Use rshell to copy the library on ESP8266 board.

unzip d1motor.zip
cd d1motor
rshell -p /dev/ttyUSB0
cp d1motor.py /pyboard/

Then start repl so that it’s possible to communicate with motor shield. You can exit repl by CTRL+X:

cd /pyboard/
repl

Insert following code:

import d1motor
from machine import I2C, Pin
i2c = I2C(-1, Pin(5), Pin(4), freq=100000)
m0 = d1motor.Motor(0, i2c)
m1 = d1motor.Motor(1, i2c)
m0.speed(5000)

By this moment motor should start roaring and rotating. Well, that would be the happy day scenario. There are several gotchas which you may encounter.

Gotcha #1 OSError: [Errno 19] ENODEV

The code might throw ENODEV error without further explanation of what went wrong. The error means that ESP8266 was not able to find motor board via I2C. You can verify the problem by entering code:

from machine import I2C, Pin
i2c = I2C(-1, Pin(5), Pin(4), freq=100000)
i2c.scan()

The correct result should be array with 48 which is 0x30.

[48]

If you get just empty array then the boards are not able to talk over I2C:

 [ ]

The most common reason for the problem is buggy version firmware in STM32F030. You must flash it according to instructions from hackday.io.

You will need UBS2TTL module to perform flashing.

Download patched firmware: motor_shield.bin

Connect by single wire RTS with 3V3 PIN – they’re next to each other.

Connect folling wires on main part of board (not part with RTS):

GND - GND
3V3 - 3V3 VCC on USB2TTL
D2 - TX
D1 - RX

Install stm32flash:

sudo apt-get install stm32flash

Unlock and flash the shield:

stm32flash /dev/ttyUSB0 -k
stm32flash /dev/ttyUSB0 -u
stm32flash /dev/ttyUSB0 -v -w motor_shield.bin

After flashing unplug wires and connect the shield back to ESP8266. Run I2C scan again and you should get the correct result:

from machine import I2C, Pin
i2c = I2C(-1, Pin(5), Pin(4), freq=100000)
i2c.scan()

[48]

Gotcha #2 Standby mode not controlled by I2C

Even after the first correction, the motors might not move and there is no voltage on A1-2 or B1-2. The problem is most likely caused by Standby mode.

Check your board and you should see STBY with 3 pins and with marking I2C and IO. You need to solder top and middle pin to enable I2C control of Standby mode. Solder them and plug the board again. Now motors should start to move.

Gotcha #3 Incorrect frequency

There might be a third reason why motors are not moving: Incorrect frequency of communication via I2C. Double-check the number. One missing zero might cause the problem.

Not working configuration:

i2c = I2C(-1, Pin(5), Pin(4), freq=10000)

Working configuration:

i2c = I2C(-1, Pin(5), Pin(4), freq=100000)

Does it work? Congratulations.

Big thanks to community Radomir Dopieralski for d1motor.py, aarn_a and Matrix User for hints about Standby mode.

27. June 2020

ESP32 erase_flash failed with “Invalid head of packet”

The first step before installing MicroPython to ESP32 is to erase the flash.

I’ve installed all necessary software like esptool, but the flashing was failing with error:

esptool.py --chip esp32 --port /dev/ttyUSB0 erase_flash                                                                                                         ──(Sat,Jun27)─┘
esptool.py v2.8
Serial port /dev/ttyUSB0
Connecting........_____....._____....._____....._____....._____....._____....._____

A fatal error occurred: Failed to connect to ESP32: Invalid head of packet (0x1B)

The solution to the problem is to pres and hold BOOT button. Then start erase command mentioned above.

After the initial erase I was able to flash there MicroPython:

esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 460800 write_flash -z 0x1000 esp32-idf4-20200627-unstable-v1.12-590-g9f911d822.bin

Then it was possible to connect via rshell:

rshell -p /dev/ttyUSB0                                                                                                                                          ──(Sat,Jun27)─┘
Using buffer-size of 32
Connecting to /dev/ttyUSB0 (buffer-size 32)...
Trying to connect to REPL  connected
Testing if ubinascii.unhexlify exists ... Y
Retrieving root directories ... /boot.py/
Setting time ... Jun 27, 2020 20:46:47
Evaluating board_name ... pyboard
Retrieving time epoch ... Jan 01, 2000
Welcome to rshell. Use Control-D (or the exit command) to exit rshell.

/home/georgik/projects/esp32> cd /pyboard/
/pyboard> ls
boot.py