Many electronics hobbyists begin with the Arduino ecosystem. That's how I got started!
My first project was a tripod mount that could hold an iPhone for filming and pan using a motor. Early iterations used an Arduino Nano 33 BLE, a servo motor, and 4x AA batteries.
Arduino controlling a servo motor
When writing firmware for the Arduino Nano, I started with the Android IDE + SDK.
The code for communicating over Bluetooth and controlling the servo fit into a few hundred line .ino
sketch file.
The wiring was pretty straightforward and only needed a few pins connected. The Arduino Servo
library for motor control and ArduinoBLE for comms made it easy to implement.
When I finished working on that project, I moved to increasingly complex projects. The Bitclock project needed to connect to an e-ink screen, mount three I2C sensors, and fit into a tiny enclosure. At this point, I was looking to graduate from the Arduino Nano and hand soldering everything together.
Bitclock - E-ink clock + air quality monitor
To meet these requirements, I decided to design a custom PCB (printed circuit board). By designing a PCB specific to the device, Bitclock electronics could have a smaller footprint that would fit snugly into an enclosure. Additionally, manufacturing the product at scale would be simplified through PCB assembly services like π¨π³ JLCPCB, PCBWay, or πΊπΈ MacroFab.
I should disclose that one of my main goals when starting Bitclock was to learn custom PCB design, so my approach was going to end up there anyway!
Bitclock PCB assembly, featuring an ESP32-S3 microcontroller
An early question when designing Bitclock was which microcontroller to use.
I settled on the ESP32-S3 module, which you can see mounted to the top-right corner of the PCB. These ESP32 SoC (system-on-a-chip) modules are popular for a few reasons:
With the Bitclock project, my firmware grew to thousands of lines and many files. The firmware needed to render graphics for a display, communicate over bluetooth + Wi-Fi, communicate with sensors. These features needed to multi-task on a single core and meet the constrained memory & flash of the ESP32.
While you can technically write code for ESP32 using the Arduino IDE + SDK, I settled on an alternative approach for this project using Espressif's ESP-IDF framework.
Technically, you can program an ESP32 using Arduino IDE & SDK.
The generic Arduino toolchain supports different hardware platforms through Arduino Cores. Each Arduino Core implements the standard APIs like Serial and Wire. In the case of ESP32 devices, Espressif actively maintains the arduino-esp32 core implementation.
Under the hood, the arduino-esp32 core is largely implemented using the ESP-IDF framework. The ESP-IDF framework was developed specifically for ESP32 SoCs, and has many features and APIs specific to that family of devices.
arduino-esp32 is implemented using ESP-IDF
This brought about a major design decision for Bitclock. Continue using the generic and familiar Arduino SDKs, or switch to the manufacturer's ESP-IDF framework?
For the Bitclock project, hardware cross-compatibility was not a priority. Instead, hardware control was more important especially given the hardware constraints of:
On the other hand, the ESP-IDF framework offers equivalent high and low level APIs, and is very well documented.
Some of the ESP-IDF features Bitclock leverages include:
Given the above, I decided to use ESP-IDF directly and bypass the Arduino abstraction.
While I had enjoyed using the Arduino IDE previously, it no longer seemed the obvious choice given the ESP-IDF choice. VSCode was the general code editor I used the most, and has many appealing features:
In order to make the switch to VSCode, it was necessary to ensure that I would have replacements for a few crucial Arduino IDE features:
PlatformIO is a popular VSCode extension that supports all of these features, so I experimented with that before ultimately deciding not to use it and instead configure VSCode manually.
On paper, PlatformIO supported all the features I wanted for embedded development in VSCode. I'd be able to compile, flash, debug, and get static analysis of my code.
However, after installing the extension I was less enthused. I was greeted with a landing page showing news, social links, and project creation wizards. It's certainly a personal preference, but PlatformIO was delivering me an entire IDE-within-IDE when I was looking for a few basic debugging and code highlighting features.
VSCode after PlatformIO extension installed
Fortunately, there is an alternative way to get the functionality I desired using only VSCode, the C/C++ extension by Microsoft, and the ESP-IDF CLI toolchain.
The ESP-IDF toolchain includes the SDK, as well as a command line front-end for build
, flash
, and monitor
.
If you use PlatformIO it likely installs it for you, but since we're doing things manually we'll install it ourselves.
Follow the instructions from Espressif here.
On macOS, you'll need create a directory to install the SDK to and the process goes something like this:
Make sure to read the latest docs for up-to-date installation instructions.
With the toolchain now installed, create a separate directory to house the source code of your new project.
You can use ESP-IDF frontend to create a barebone project for you:
This will create a directory structure with the following:
Make sure to tell ESP-IDF what device you are building for:
With that complete, build and run is a simple via the CLI:
idf.py build
idf.py flash
idf.py monitor
The ESP-IDF CLI tool solves build + run, but for VSCode to be a real IDEβ’οΈ it needs to know where to look for ESP-IDF libraries referenced by your code.
We'd need code static analysis to get library auto-completion, CMD+click to jump to function definitions, and a red squiggly underlines when we add a bug.
Auto-completion from ESP-IDF SDK
First, make sure you have the C/C++ extension by Microsoft installed.
Then we can configure IntelliSense by adding a .vscode/c_cpp_properties.json
file to the root of the project. VSCode will read this to configure the extension.
Here's an example that worked for Bitclock's ESP32-S3 on macOS:
It does the following:
.compilerPath
to point to the GCC compiler used for the project.compileCommands
to hint to IntelliSense the specific arguments for how each file was last compiled.includePath
to include the core libraries for IntelliSense, component libraries, and your project workspace.browse.path
to include same libraries for the "Tag Parser" of VSCodeMake sure the paths match the locations of ESP-IDF's install location and ~/.espressif
workspace for your system. See the ESP-IDF tools.json to see what version you should be pointing to. For example, ESP32-S3 uses the xtensa-esp-elf
compiler while ESP32-C3 uses riscv32-esp-elf
.
To be honest, I'm not entirely sure how critical each of these fields is to IntelliSense but I do know that in its entirety the configuration worked for my project! I used the Espressif's VSCode extension as a guide (yet another VSCode extension that I opted to skip and configure manually π§).
Last but not least, we'd like to have GDB functionality within VSCode. The C/C++
extension we've already installed supports this but we need to tell it how to connect.
ESP32 interactive debugging using OpenOCD
For Bitclock, the following debugging configuration worked by this file to your project's .vscode/launch.json
:
Make sure .miDebuggerPath
points to the correct ESP-IDF toolchain for this project (see tools.json
tip from above). Also ensure .program
points to the .elf
build of your project.
Once setup, connect your ESP32 hardware, flash it with the latest version of your app, and start the local OpenOCD server. This will start a debugging connection over USB with your device:
The last step is to connect VSCode to your debugging session. Open the Run & Debug Panel (on macOS: β + Shift + D), then the click the βΆοΈ button to start debugging (F5). VSCode allows you to visually set breakpoints, inspect memory, and the usual debugging IDE features you'd expect.
For projects that grow too complex for the Arduino ecosystem, consider switching to ESP-IDF & VSCode. If you take that path, I hope this write-up proves a helpful resource in getting things going.
There is more I'd love to share from working on this project. Topics include:
If you've got feedback, or want to see anything specifically described further, don't hesitate to reach out at [email protected]!
And if you're interested in the gadget that inspired this post, consider ordering a Bitclock! Either use it as clock + air quality monitor, or write your own apps. The code is open source on GitHub.
Happy hacking...
--Brady
Β© 2024 Goat Hill Electronics LLC. All rights reserved.Β Privacy PolicyΒ π€Β Terms of Service