Skip to main content

Getting Started with NuttX and ESP32

·8 mins·
NuttX Apache ESP32 POSIX Linux
Author
Tiago Medicci
Embedded Software Engineer at Espressif
Author
Eren Terzioğlu
Junior Software Engineer at Espressif
Author
Filipe Cavalcanti
Embedded Software Engineer at Espressif
Table of Contents

Introduction to Apache NuttX RTOS
#

In this tutorial, we will do a quick overview of NuttX and its compatibility with Espressfi SoCs. After that, we will build and flash NuttX onto the ESP32-DevKitC board and connect to a Wi-Fi network. Along the way, we will also install the required dependencies for NuttX, set up the toolchains to build applications for Espressif SoCs, get NuttX’s source code, and configure the project before building.

According to the Apache NuttX website: NuttX is a real-time operating system (RTOS) with an emphasis on standards compliance and small footprint. Scalable from 8-bit to 64-bit microcontroller environments, the primary governing standards in NuttX are Posix and ANSI standards.

NuttX is the 2nd most popular community-based RTOS (along with Zephyr in the 1st position):

Operating systemFirst commitGovernanceLicenseContributorsPulse (jun10/2024)
Zephyr2014communityApache 2.0100+942
NuttX2007communityApache 2.0100+135
RT-Thread2009communityApache 2.0100+67
RIOT2010communityLGPL2.1100+71
Tyzen RT2015SamsungApache 2.0100+36
myNewt2015CommunityApache 2.0100+25
mbed OS2013ARMApache 2.0 or BSD-3 Clause100+7
FreeRTOS2004Richard BarryMIT100+6
Contiki-NG2016communityBSD-3 Clause100+4
CMSIS-52016ARMApache 2.0100+0
Azure-RTOS2020MicrosoftMicrosoft Software License10+archived

Table by Alin Jerpelea, presented on NuttX Workshop 2024

Its standards conformance (POSIX and ANSI, mostly) allows software developed under other OSes (under the same standards, such as software developed for Linux) to be easily ported to NuttX, enabling embedded applications to reuse tested applications. In such a sense, NuttX can be seen as the closest alternative to Linux for embedded software, providing interfaces similar to the ones used by Embedded Linux applications to SoCs that do not require running Linux directly.

NuttX supports more than 300 boards from different architectures and its active community keeps providing support for newer devices and boards.Espressif SoCs are supported on NuttX!

NuttX Documentation
#

The primary source of information for NuttX is its documentation, which is accessible at https://nuttx.apache.org/docs/.

Supported Espressif SoCs in NuttX
#

NuttX currently supports Espressif’s ESP32, ESP32-C and ESP32-S series. Peripheral support is increasing constantly. Those include but are not limited to GPIO, DAC, DMA, SPI, I2C, I2S, Wi-Fi, Bluetooth and many more.

Currently, Espressif SoCs supported on NuttX are divided into two different architectures: RISC-V and Xtensa.

RISC-V
#

Xtensa
#

Getting started with NuttX and ESP32
#

The following steps use Ubuntu 22.04 as an example. Please check the official documentation for other Operating Systems.

Installing System Dependencies
#

Install the system dependencies required to build NuttX:

sudo apt install \
automake binutils-dev bison build-essential flex g++-multilib gcc-multilib \
genromfs gettext git gperf kconfig-frontends libelf-dev libexpat-dev \
libgmp-dev libisl-dev libmpc-dev libmpfr-dev libncurses5-dev libncursesw5-dev xxd \
libtool picocom pkg-config python3-pip texinfo u-boot-tools util-linux

Also, please install some python packages:

pip install kconfiglib

Espressif Tools and Toolchains
#

Once the NuttX dependencies are available, it’s time to install the compilation tools for Espressif SoCs.

Install esptool:

pip install esptool==4.8.dev4

Finally, install the toolchains to build the Espressif SoCs. It can be installed depending on the SoC being used, but it is highly recommended to keep all of them installed.

RISC-V SoCs (ESP32-C3, ESP32-C6, ESP32-H2)
#

All RISC-V SoCs use the same toolchain. Currently (Jun 2024), NuttX uses the xPack’s prebuilt toolchain based on GCC 13.2.0-2 for RISC-V devices. Please, visit the ESP32-C3’s Toolchain section in the NuttX documentation to check for the newest recommended RISC-V toolchain.

Create a directory to install the toolchain. It can be on your home directory:

mkdir -p ~/riscv-none-elf-gcc

Download and extract the toolchain on the new directory:

cd ~/riscv-none-elf-gcc
wget https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v13.2.0-2/xpack-riscv-none-elf-gcc-13.2.0-2-linux-x64.tar.gz
tar -zxf xpack-riscv-none-elf-gcc-13.2.0-2-linux-x64.tar.gz

Once extracted, add the location of the binaries to the user’s PATH and reload the terminal:

echo "export PATH=$HOME/riscv-none-elf-gcc/xpack-riscv-none-elf-gcc-13.2.0-2/bin:\$PATH" >> ~/.bashrc

This last step is optional and applicable only if you want to make the toolchain available automatically, even after a restart. On the other hand, exporting it to the PATH variable before using it is sufficient. Please also note that the ~.bashrc is automatically sourced after a logout/login or after restarting the machine.

Make sure to either 1) export the PATH with the toolchain or 2) source the ~.bashrc or 3) logout and login or 4) restart the machine.

Xtensa SoCs (ESP32, ESP32-S2, ESP32-S3)
#

Each Xtensa-based device has its own toolchain, which needs to be downloaded and configured separately. Please, double-check ESP32, ESP32-S2 and ESP32-S3 toolchain sections to get the link for the recommended toolchain for each SoC.

ESP32:
#

Although ESP32, ESP32-S2 and ESP32-S3 have their own toolchain, the process of downloading and installing is very similar:

First of all, export a variable to identify the toolchain being installed:

export CHIPNAME=esp32

Create a directory to install the toolchain. It can be on your home directory:

mkdir -p ~/xtensa-$CHIPNAME-elf-gcc

Download and extract the toolchain on the new directory:

cd ~/xtensa-$CHIPNAME-elf-gcc
wget https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-$CHIPNAME-elf-12.2.0_20230208-x86_64-linux-gnu.tar.xz
tar -xf xtensa-$CHIPNAME-elf-12.2.0_20230208-x86_64-linux-gnu.tar.xz

Once extracted, add the location of the binaries to the user’s PATH and reload the terminal:

echo "export PATH=$HOME/xtensa-$CHIPNAME-elf-gcc/xtensa-$CHIPNAME-elf/bin:\$PATH" >> ~/.bashrc

To check if the toolchain is properly installed:

xtensa-esp32-elf-gcc --version
ESP32-S2:
#

Similarly, for ESP32-S2:

export CHIPNAME=esp32s2

And run the same steps to create the directory to install the toolchain, download and extract the toolchain and export it to the PATH, as it was done for ESP32.

ESP32-S3:
#

Similarly, for ESP32-S3:

export CHIPNAME=esp32s3

And run the same steps to create the directory to install the toolchain, download and extract the toolchain and export it to the PATH, as it was done for ESP32.

Getting NuttX
#

Clone the NuttX repository and the NuttX Apps repository in a directory called nuttxspace. The Apps repository is optional, as it contains mostly example applications.

mkdir nuttxspace
cd nuttxspace
git clone https://github.com/apache/nuttx.git nuttx
git clone https://github.com/apache/nuttx-apps apps

Building an App to Connect to a Wi-Fi network
#

NuttX provides ready-to-use board default configurations that enable the required config (from Kconfig) for a use scenario, such as Wi-Fi or I2C. You can list all available configurations for the ESP32 DevKitC V4 board using the following command, inside the NuttX directory:

./tools/configure.sh -L | grep esp32-devkitc

This command lists all available configurations for the ESP32-DevKitC board. These pre-defined configurations can be modified before building to better suit your application.

More information about this board can be found here. It embeds a USB-to-UART bridge chip to enable accessing the device’s UART0 through a micro-USB port. The board is also powered up through the USB.

Connect the board to your computer and check if the associated USB port is available. In Linux:

ls /dev/tty*

The currently logged user should have read and write access to the serial port over USB. This is done by adding the user to dialout group with the following command:

sudo usermod -a -G dialout $USER

Connecting to a Wi-Fi Access Point
#

As an example, let’s use the Wi-Fi configuration for the ESP32 DevKitC board with the following command:

./tools/configure.sh esp32-devkitc:wifi

To change some configuration in the default configuration that was just loaded, use menuconfig:

make menuconfig

The menuconfig utility allows you, for instance, to enable peripherals, modify the NuttX kernel settings, enable support for device drivers, configure the NuttShell and the file system, enable example programs and set up the Wi-Fi credentials.

To quickly connect to a known Wi-Fi network, navigate to Application Configuration -> Network Utilities -> Network Initialization -> WAPI Configuration and set the SSID (the name of the Wi-Fi Access Point) and the passphrase to connect to it.

It is also necessary to set how to get a valid IP address after connecting to the Wi-Fi network. In this example, DHCP will be used to receive it from the network automatically. In Application Configuration -> Network Utilities -> Network Initialization -> IP Address Configuration, select Use DHCP to get IP address.

Navigate to the Exit and, when prompted, save the current settings.

Before building and flashing the firmware, it is necessary to build the bootloader to boot NuttX:

make bootloader

To build and flash the ESP32 board, use the following command (modifying the USB port accordingly):

make flash ESPTOOL_PORT=/dev/ttyUSB0 ESPTOOL_BINDIR=./

When flashing is complete, you can use picocom to open a serial console by running:

picocom -b115200 /dev/ttyUSB0

Please check the following example that shows the device connecting to the Wi-Fi network and other commands that can be used in the NuttShell, like ifconfig:

It’s worth noting that there is no need to pre-define the SSID/passphrase of the Wi-Fi network in menuconfig. NuttX provides the wapi application that manages the Wi-Fi subsystem. More information about wapi can be found in NuttX documentation. Experiment with wapi for scanning available access points, for instance:

wapi scan wlan0

Conclusion
#

NuttX is one of the most preferred RTOS for developers familiar with Linux interfaces (including the so-called “Embedded Linux”) because of its POSIX-compliant interface. Most of the features covered by this introductory article rely on usual applications, like the NuttShell (or NSH: the shell system used in NuttX, similar to bash) and usual built-in commands, like ping. Stay tuned for more articles about NuttX (in special, for the question “Why using NuttX”?).

Useful Links#

Related

Simplify Your Embedded Projects with ESP-BSP
·5 mins
Embedded Systems ESP32 ESP32-S3 Espressif BSP
Simplified Embedded Rust: A Comprehensive Guide to Embedded Rust Development
·3 mins
Rust Embedded Systems ESP32 ESP32-C3 Espressif Wokwi Book Review
Espresso Machine PID controller using ESP32 and RainMaker
·9 mins
ESP32 ESP-IDF RainMaker