Using Raspberry Pi for Embedded Systems Development — Part 3

<rawat.s>
8 min readSep 10, 2021

.

In summary, this article describes how to build the xtensa-esp32 toolchains and openocd-esp32 for arm64 / aarch64 from scratch, using Raspberry Pi 4 (64-bit) and Debian-based Raspberry Pi OS. In addition, it provides instructions on how to use the xtensa-esp32 toolchains with the Arduino ESP32 v2.0.0.

.

The Arduino-ESP32 package of the version 2.0.0 is not yet available for 64-bit ARM architecture. However, for other platforms such as armhf (32-bit ARM), win32, win64, linux-x86_64, and mac-os, there are prebuilt files available for downloading. You can check the contents of the package_esp32_index.json file.

The Arduino-esp32 version 2.0.0 is based on the ESP-IDF version 4.4 (Dev) and has added support for ESP32-S2 and ESP-C3.

The article is organized into sections as follow:

  • Getting System Information
  • Building Xtensa-ESP32 Toolchain for ARM64
  • Building binutils-esp32ulp for ARM64
  • Building openocd-esp32 for ARM64
  • Installing Arduino-esp32 v2.0.0 for ARM64
  • Basic Arduino Sketch Demo for ESP32

Getting System Information

.

We will use a 64-bit Raspberry Pi 4 SBC to build the software from sourcecode. The following commands are used to show information about the system.

$ uname -a
Linux raspberrypi 5.10.60-v8+ #1449 SMP PREEMPT Wed Aug 25 15:01:33 BST 2021 aarch64 GNU/Linux
$ cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 10 (buster)"
NAME="Debian GNU/Linux"
VERSION_ID="10"
VERSION="10 (buster)"
VERSION_CODENAME=buster
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
$ hostnamectl
Static hostname: raspberrypi
Icon name: computer
Machine ID: 683ec8367b5e45b0be13dad7xxxxxxxx
Boot ID: 4ae010bd0bf149cd8637208cxxxxxxxx
Operating System: Debian GNU/Linux 10 (buster)
Kernel: Linux 5.10.60-v8+
Architecture: arm64
# check version of python/gcc/g++$ python -V
Python 3.7.3
$ gcc --version
gcc (Debian 8.3.0-6) 8.3.0
$ g++ --version
g++ (Debian 8.3.0-6) 8.3.0

Building Xtensa-ESP32 Toolchain for ARM64

.

  1. Install necessary software packages:
$ sudo apt-get install gawk gperf grep gettext python python-dev automake bison flex texinfo help2man libtool libtool-bin make

2. Download the crosstool-NG for ESP32 repository (esp-2021r1) from github:

$ mkdir -p $HOME/src
$ mkdir -p ~/esp && cd ~/esp
$ git clone https://github.com/espressif/crosstool-NG.git
$ cd crosstool-NG
$ git checkout esp-2021r1
$ git submodule update --init
$ ./bootstrap && ./configure --enable-local && make

3. Choose xtensa-esp32-elf as target:

# select xtensa-esp32-elf as target
$ ./ct-ng xtensa-esp32-elf
# edit the configuration and save change to the .config file
$ ./ct-ng menuconfig
# show all the steps of the build process
$ ./ct-ng list-steps
Available build steps, in order:
- companion_tools_for_build
- companion_libs_for_build
- companion_tools_for_host
- companion_libs_for_host
- binutils_for_build
- binutils_for_host
- cc_core_pass_1
- kernel_headers
- libc_start_files
- cc_core_pass_2
- libc
- cc_for_build
- cc_for_host
- libc_post_cc
- companion_libs_for_target
- binutils_for_target
- debug
- test_suite
- finish

4. Start the build process:

# increase the max. of open files to 2048
$ ulimit -n 2048
# remove all toolchain components under ./build/tarballs
$ rm -fr .build/tarballs/*
$ TARGET=xtensa-esp32-elf
$ ./ct-ng ${TARGET}
$ ./ct-ng menuconfig
# start the build process
$ ./ct-ng build
# change permissions of built files for user (writable)
$ chmod -R u+w builds/${TARGET}
# make an archive file (.tar.gz) for the built files
$ cd ./builds
$ FILENAME=${TARGET}-gcc8_4_0-esp-2021r1-linux-arm64
$ tar -cvf ${FILENAME}.tar ./xtensa-esp32-elf
$ gzip -9 ${FILENAME}.tar
# calculate and show the SHA256 checksum
$ sha256sum ${FILENAME}.tar.gz
076455e9b96b8944d1f200fa42d47054faac70b88e0bce2b2f663d4ec48991c3 xtensa-esp32-elf-gcc8_4_0-esp-2021r1-linux-arm64.tar.gz
# get the file size in bytes
$ ls -l ${FILENAME}.tar.gz | awk '{print $5}'
85469631

Bug: You have to edit the .config file and change the version of expat-lib from 2.2.9 to 2.4.1.

You can use the sed command to replace string:

$ sed -i 's/2.2.9/2.4.1/g' .config

For the xtensa-esp32s2-elf or xtensa-esp32s3-elf or riscv32-esp-elf target:

$ TARGET=xtensa-esp32s2-elf
$ ./ct-ng ${TARGET}
$ ./ct-ng menuconfig
$ ./ct-ng build
$ chmod -R u+w builds/${TARGET}
# make an archive file (.tar.gz) for the built files
$ cd ./builds
$ FILENAME=${TARGET}-gcc8_4_0-esp-2021r1-linux-arm64
$ tar -cvf ${FILENAME}.tar ./${TARGET}
$ gzip -9 ${FILENAME}.tar
# calculate and show the SHA256 checksum
$ sha256sum ${FILENAME}.tar.gz
# get the file size in bytes
$ ls -l ${FILENAME}.tar.gz | awk '{print $5}'

Warning: the complete build process can take up to 180 minutes (~3hrs) on Raspberry Pi 4.

Building binutils-esp32ulp for ARM64

.

  1. Download the binutils-esp32ulp repository from github:
$ git clone --recursive https://github.com/espressif/binutils-esp32ulp
$ cd binutils-esp32ulp

2. Choose gcc and g++ version 7 and python 2.7:

# install gcc and g++ version 7 
$ sudo apt -y install gcc-7 g++-7
$ sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 7
$ sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-7 7
# select the version of gcc and g++ to be used by default
$ sudo update-alternatives --config gcc
$ sudo update-alternatives --config g++
# select the version of python to be used by default
$ sudo update-alternatives --config python
# check version
$ python -V
Python 2.7.16
$ gcc --version
gcc (Debian 7.4.0-6) 7.4.0
$ g++ --version
g++ (Debian 7.4.0-6) 7.4.0

3. Configure for esp32ulp-elf or esp32s2ulp-elf target and start the build process:

$ TARGET=esp32ulp-elf
$ mkdir -p ./${TARGET}-binutils
$ find -name "config.status" -exec rm -f {} \;
$ find -name "config.cache" -exec rm -f {} \;
$ CC=gcc ./configure --target=${TARGET} --prefix=`pwd`/${TARGET}-binutils
$ make -j4
$ make install
$ make distclean

4. Make an archive file (.tar.gz)

$ FILE=binutils-${TARGET}-linux-arm64-2.28.51-esp-20191205
$ tar -cvf ${FILE}.tar ./${TARGET}-binutils
$ gzip -9 ${FILE}.tar
$ sha256sum ${FILE}.tar.gz

When finished, you can change back the configuration for gcc and g++ to version 8.

Building openocd-esp32 for ARM64

.

  1. Download the openocd-esp32 repository (v0.10.0-esp32–20210902) from github:
$ git clone --recursive https://github.com/espressif/openocd-esp32

2. Install necessary software packages:

$ sudo apt install -y git gcc binutils make libtool pkg-config autoconf automake texinfo libgpiod-dev libusb-1.0 libudev-dev  libusb-1.0-0-dev 

3. Run the following commands to configure the build files:

$ cd openocd-esp32
$ ./bootstrap
$ ./configure --prefix=`pwd`/openocd-esp32/

4. Start the build process:

$ make && make install

5. Make an archive file (.tar.gz):

$ FILE=openocd-esp32-arm64-0.10.0-esp32-20210902
$ tar -cvf ${FILE}.tar ./openocd-esp32
$ gzip -9 ${FILE}.tar
$ sha256sum ${FILE}.tar.gz
$ ls -l ${FILE}.tar.gz | awk '{print $5}'

Installing Arduino-esp32 v2.0.0 for ARM64

1. Download the package_esp32_index.json (v2.0.0) file from github:

$ wget https://github.com/espressif/arduino-esp32/releases/download/2.0.0/package_esp32_index.json

.

2. Put all necessary archive files (tar.gz) under /home/pi/esp-2021r1. as listed below.

$ tree -L 1 ~/esp-2021r1/
/home/pi/esp-2021r1/
├── package_esp32_index.json
├── riscv32-esp-elf-gcc8_4_0-esp-2021r1-linux-arm64.tar.gz
├── xtensa-esp32-elf-gcc8_4_0-esp-2021r1-linux-arm64.tar.gz
└── xtensa-esp32s2-elf-gcc8_4_0-esp-2021r1-linux-arm64.tar.gz
0 directories, 4 files

3. Modify the package_esp32_index.json by adding options for arm64 files:

Search for:

"name": "riscv32-esp-elf-gcc", 
"version": "gcc8_4_0-esp-2021r1",

Add the following lines (JSON format):

  {
"host": "aarch64-linux-gnu",
"url": "file:///home/pi/esp-2021r1/riscv32-esp-elf-gcc8_4_0-esp-2021r1-linux-arm64.tar.gz",
"archiveFileName": "riscv32-esp-elf-gcc8_4_0-esp-2021r1-linux-arm64.tar.gz",
"checksum": "SHA-256:e8fa4c52233ba1236be81287083593913d85ea288f4b5ce5be2edfe9581d3b3d",
"size": "150926486"
},

Search for:

"name": "xtensa-esp32-elf-gcc",
"version": "gcc8_4_0-esp-2021r1",

Add the following lines (JSON format):

  {
"host": "aarch64-linux-gnu",
"url": "file:///home/pi/esp-2021r1/xtensa-esp32-elf-gcc8_4_0-esp-2021r1-linux-arm64.tar.gz",
"archiveFileName": "xtensa-esp32-elf-gcc8_4_0-esp-2021r1-linux-arm64.tar.gz",
"checksum": "SHA-256:076455e9b96b8944d1f200fa42d47054faac70b88e0bce2b2f663d4ec48991c3",
"size": "85469631"
},

Search for:

"name": "xtensa-esp32s2-elf-gcc",
"version": "gcc8_4_0-esp-2021r1",

Add the following lines (JSON format):

  {
"host": "aarch64-linux-gnu",
"url": "file:///home/pi/esp-2021r1/xtensa-esp32s2-elf-gcc8_4_0-esp-2021r1-linux-arm64.tar.gz",
"archiveFileName": "xtensa-esp32s2-elf-gcc8_4_0-esp-2021r1-linux-arm64.tar.gz",
"checksum": "SHA-256:200d569899e6172dea299669cbe1dea0766370026fac6dcc2e8e5a29666da771",
"size": "85746821"
},

4. Open the Arduino IDE, Go to Arduino> Preferences; Enter the following URL into the “Additional Board Manager URLs”. Then, click the “OK” button:

file:///home/pi/esp-2021r1/package_esp32_index.json

Open the Boards Manager. Go to Tools > Board > Boards Manager

Choose “esp32” and version 2.0.0. Then, click Install.

After installation, a new directory named esp32 under ~/.arduino15/packages/ was created with the following subdirectories:

$ tree -L 4 ~/.arduino15/packages/esp32/
/home/pi/.arduino15/packages/esp32/
├── hardware
│ └── esp32
│ └── 2.0.0
│ ├── boards.txt
│ ├── cores
│ ├── libraries
│ ├── platform.txt
│ ├── programmers.txt
│ ├── tools
│ └── variants
└── tools
├── esptool_py
│ └── 3.1.0
│ └── esptool.py
├── mklittlefs
│ └── 3.0.0-gnu12-dc7f933
│ ├── mklittlefs
│ └── package.json
├── mkspiffs
│ └── 0.2.3
│ └── mkspiffs
├── riscv32-esp-elf-gcc
│ └── gcc8_4_0-esp-2021r1
│ └── riscv32-esp-elf
├── xtensa-esp32-elf-gcc
│ └── gcc8_4_0-esp-2021r1
│ └── xtensa-esp32-elf
└── xtensa-esp32s2-elf-gcc
└── gcc8_4_0-esp-2021r1
└── xtensa-esp32s2-elf
23 directories, 7 files

Open ~/.arduino15/packages/esp32/hardware/esp32/2.0.0/platform.txt and change the compiler.path setting from

compiler.path={runtime.tools.{build.tarch}-{build.target}-elf-gcc.path}/bin/

to

compiler.path={runtime.tools.{build.tarch}-{build.target}-elf-gcc.path}/{build.tarch}-{build.target}-elf/bin/

Then, restart the Arduino IDE.

Basic Arduino Sketch Demo

.

Create a new Arduino sketch and choose the ESP32-S2 or ESP32-C3 as the target board.

Arduino Sketch: LED Blink with Serial Output
Select Target Board: ESP32-C3

Build and upload the sketch to the target board.

After a successful upload, open the Arduino Serial Monitor to see the serial output from the ESP32 board.

Arduino Serial Monitor

--

--