Embedded learning log - Connecting a board and flashing an RTOS

| RSS | Edit on GitHub | Read more of my posts

This post is part of a series where I log my experience getting into embedded software development. The overarching goal is to use the ESP8266 RTOS SDK to learn how to operate my ESP8266 board using an RTOS and to learn how to integrate the Memfault real-time SDK. Disclaimer: I work for Memfault as a full-stack engineer, mostly on web stuff. Here are the other posts in the series:

Browse the accompanying repository at the first commit or at the commit in which I managed to run the hello_world project.

I’m a web developer, so this is all new to me. I hope this log turns out to be an interesting read for experienced embedded systems developers and a way to help newbies like me feel less lonely in their adventure.

Installing the ESP8266_RTOS_SDK toolchain #

Here’s the documentation.

I’m surprised that I need to download tarfiles.

A first ls in the binaries offered by the toolchain gives me this:

 ~/Development/toastboard => ls ~/.esp/xtensa-lx106-elf/bin
xtensa-lx106-elf-addr2line  xtensa-lx106-elf-c++filt       xtensa-lx106-elf-gcc         xtensa-lx106-elf-gcov       xtensa-lx106-elf-ld       xtensa-lx106-elf-ranlib
xtensa-lx106-elf-ar         xtensa-lx106-elf-cpp           xtensa-lx106-elf-gcc-8.4.0   xtensa-lx106-elf-gcov-dump  xtensa-lx106-elf-ld.bfd   xtensa-lx106-elf-readelf
xtensa-lx106-elf-as         xtensa-lx106-elf-ct-ng.config  xtensa-lx106-elf-gcc-ar      xtensa-lx106-elf-gcov-tool  xtensa-lx106-elf-nm       xtensa-lx106-elf-size
xtensa-lx106-elf-c++        xtensa-lx106-elf-elfedit       xtensa-lx106-elf-gcc-nm      xtensa-lx106-elf-gdb        xtensa-lx106-elf-objcopy  xtensa-lx106-elf-strings
xtensa-lx106-elf-cc         xtensa-lx106-elf-g++           xtensa-lx106-elf-gcc-ranlib  xtensa-lx106-elf-gprof      xtensa-lx106-elf-objdump  xtensa-lx106-elf-strip

I can only guess what some of those things are for. I haven’t read the full documentation yet. Here are my guesses:

Some of these tools are already available in my PATH but not specifically for xtensa-lx106-elf, I guess because I’ve installed build-essential: gcc, strip, objdump, objcopy… what do these binaries work on? x86_64 Linux?

The “supported” IDE is Eclipse, but the docs start with this:

We suggest building a project from the command line first, to get a feel for how that process works. You also need to use the command line to configure your ESP8266_RTOS_SDK project (via make menuconfig), this is not currently supported inside Eclipse.

That means I’ll get introduced to interacting with the project via command line, so that’s good.

Downloading ESP8266_RTOS_SDK #

Here’s the documentation.

Once again, the documentation suggests I just dump the whole RTOS into ~/esp. Should I be using submodules instead? Maybe for the toolchain, too. The next developer that works on this is inevitably going to clone master at a different commit. Let’s just follow along for now.

The toolchain programs access ESP8266_RTOS_SDK using IDF_PATH environment variable. This variable should be set up on your PC, otherwise projects will not build. Setting may be done manually, each time PC is restarted. Another option is to set up it permanently by defining IDF_PATH in user profile.

I suppose this means I need export IDF_PATH=~/esp/ESP8266_RTOS_SDK in my .zshrc.

Next up, I’m installing some Python packages globally. I think if I wanted to make these builds reproducible I’d have to go through a lot more steps than those described in the documentation. Or maybe these tools just don’t change so much?

Running the hello_world example project #

At first, I was surprised that make menuconfig is what I’m supposed to run here, because that target is not in the Makefile, but these are its contents:

PROJECT_NAME := hello-world

include $(IDF_PATH)/make/project.mk

I didn’t know you can include Makefiles from other Makefiles.

python vs python2 vs python3 #

Running make menuconfig fails because it expects python in PATH, but I have python3. I also installed the required libraries using python3, so I’m going to install python (which in Ubuntu means 2.7) and reinstall the dependencies using python. I think on Arch python points to Python 3.

After doing that, I get:

pkg_resources cannot be imported probably because the pip package is not installed and/or using a legacy Python interpreter. Please refer to the Get Started section of the ESP-IDF Programming Guide for setting up the required packages.

Apparently pip points to python3-pip in my system, so now I have to find out whether this works after installing python2-pip (I’m guessing that’s the name) or if I do need everything on Python 3 and I need to solve the python vs python3 name problem in some other way.

I ended up using alias python=python3 and running sudo apt install python-is-python3 because the SDK depends on /usr/bin/env python, making my alias useless. I guess they should have just fixed that to /usr/bin/env python3.

Back in business: finding my device #

The docs ask me to do this:

You are almost there. To be able to proceed further, connect ESP8266 board to PC, check under what serial port the board is visible and verify if serial communication works. Note the port number, as it will be required in the next step.

As if I knew how to do that! Time to DuckDuckGo.

It seems like the Internet has settled on this command:

~/Development/toastboard [2] => sudo dmesg | grep tty
[    0.183219] printk: console [tty0] enabled
[    0.784336] 0000:00:16.3: ttyS4 at I/O 0x3060 (irq = 19, base_baud = 115200) is a 16550A
[  594.954203] usb 1-1: cp210x converter now attached to ttyUSB0
[  679.763000] cp210x ttyUSB0: cp210x converter now disconnected from ttyUSB0

At first, I thought my device was connected to /dev/ttyS4 because sudo dmesg | grep tty showed it alongside a baud rate, but perhaps that’s the default for the port? As it turns out, my device is on /dev/ttyUSB0.

Part one done: my device is on /dev/ttyUSB0.

Communicating over serial #

As for verifying that serial communication works: I’ve read mentions of minicom, so I’m going to try it out. After some configuration, my chip starts to send me a dot character every second, which is the serial output of a previous Arduino program I wrote, which I had already flashed with the Arduino IDE. It’s working! Here’s the command I ran:

sudo minicom -b 115200 -o -D /dev/ttyUSB0

I run make menuconfig. The serial port is set to /dev/ttyUSB0. The generated configuration looks really specific to my laptop, so I’m going to put it in .gitignore. It seems like other developers would have to just run make menuconfig on their machines, too.

The output of make flash looked promising until I got a Permission denied: /dev/ttyUSB0 error. I suppose I can run sudo make flash, but that seems a bit excessive.

~/Development/toastboard/hello_world [2] => ls -l /dev/ttyUSB0
crw-rw---- 1 root dialout 188, 0 Feb 14 21:09 /dev/ttyUSB0

If I add myself to the dialout group, I should have access to my device. Thanks SO.

sudo usermod -a -G dialout $USER

After a reboot (surprisingly, logging out and then logging back in didn’t work), I could flash the RTOS onto the device. It’s now blinking its LED very infrequently.

The serial communication output is interesting:


It seems to then print some more rnn||bll lines, then clears itself and restarts when the LED blinks.

Baud rates #

Reading the code in hello_world_main.c I can’t find much correlation between what I get through the serial port and the code. Perhaps only that there’s a loop that resets the device every ten seconds, and that’s when the LED blinks:

for (int i = 10; i >= 0; i--) {
    printf("Restarting in %d seconds...\n", i);
    vTaskDelay(1000 / portTICK_PERIOD_MS);

I need to read into the printf function. Maybe there’s a decoding problem, or the baud rate is wrong. Time to continue reading the docs!

A make monitor target is included. Running it produces serial output at the same rate as the rnn||bll before but this time it’s completely readable, and matches what’s in the source code (go figure). I’m wondering how I could produce the same results using minicom. There’s a 74880 number in the output of make monitor that looks suspiciously like a baud rate. I was connecting with 115200.

In a digitally modulated signal or a line code, symbol rate, also known as baud rate and modulation rate, is the number of symbol changes, waveform changes, or signaling events across the transmission medium per unit of time (Wikipedia).

I thought the baud rate was the problem, but running minicom -b 74880 -o -D /dev/ttyUSB0 still gave me the rnn||bll output.

Apparently, you can specify baud rates like this: make flash ESPBAUD=9600, so I’m trying to see if the minicom output changes with this. Flashing at 9600 is so slow! Some minutes later, I run minicom -b 9600 -o -D /dev/ttyUSB0, and I get slightly different results, but still gibberish. More or less this:


Time to read the source code to figure out what’s up. The output of make monitor includes some interesting information:

Running screen /dev/ttyUSB0 74880 produces gibberish, too:


Rebuilding with baud rate 115200 makes screen /dev/ttyUSB0 115200 produce output more similar to the original output from minicom:


At this point I’m going to give up and just use make monitor, and figure this out later with the help of someone more experienced.

As it turns out, there are “standard” baud rates, blessed by most tooling around, and it seems like screen and minicom aren’t able to read at 74880bps even if configured to do so. I’m still not sure why flashing with ESPBAUD=SOMETHING_ELSE doesn’t then let me connect at speed SOMETHING_ELSE, so it seems like I’ll have to rely on make monitor for my connection.

With make monitor, the Hello, world! message shows up. Success! In the next post I’ll be trying to figure out why that sudo dmesg | grep tty pipe made sense.