de1ux

ESP-IDF for Arduino Users

8/18/2022

Why switch from Arduino to ESP-IDF?

If you’re like me, you love all the cheap, WiFi-y goodness of Espressif MCU’s, but hate the complexity of the Espressif IoT Development Framework (esp-idf). So you decide to go with the Arduino framework, and all is well and there is much rejoicing.

For a time. Enter the watchdog.

The idea is to reap long-running, unresponsive tasks. If a thread doesn’t yield, doesn’t ask the watchdog for more time, it gets reaped. This works well inside the esp-idf: but in the Arduino framework, watchdog behavior is unmodifiable. Tasks must complete in the default 5s, or else killed.

And then there’s the 800+ esp-idf project configuration options. That’s a lot of settings that don’t come with Arduino.

pio run -t menuconfig to see all the options

pio run -t menuconfig to see all the options

You can have it all

The good news is you can have the best of both: esp-idf AND Arduino frameworks, by embedding Arduino as a esp-idf component.

If you’re using PlatformIO, this is as simple as updating the platform.ini with framework = espidf, arduino

[env:nodemcu-32s]
board = nodemcu-32s
platform = espressif32
framework = espidf, arduino
...

There’s even a config option to allow loop() / setup() handlers within esp-idf.

If you switch to esp-idf’s app_main() entrypoint, simply call initArduino at the start and all your old Arduino code (Wire, ArduinoJson, etc) is up and running.

#include "Arduino.h"

void app_main()
{
    initArduino();

    ...
}

Gotchas

Writing C++ inside the ESP-IDF framework

By default, PlatformIO generates main.c boilerplate to use with the C esp-idf library. But you can write C++ that calls esp-idf C code (and vice versa) by renaming main.c to main.cpp and wrapping app_main() in an extern "C"

// main.cpp
#include "Arduino.h"

extern "C"
{
  void app_main()
  {
      initArduino();

      ...
  }
}

You might also add build_flags = -std=c++11 to platform.ini for good measure: without it, I got outdated warnings and errors in the build log.

Partitions

The esp32 comes with a default partition table, for carving up that precious 4MB integrated flash. While it’s possible to change how space is allocated with Arduino, esp-idf makes it so much easier. Simply steal a layout CSV from these examples and reference it in the platform.ini board_build.partitions section

[env:nodemcu-32s]
board = nodemcu-32s
platform = espressif32
framework = espidf, arduino
board_build.partitions = partitions_two_ota.csv

Or, write your own layout CSV – it’ll work (example) so long as it’s in the root project dir, and named correctly,

After changing partitions, clear flash with pio run -t erase. Otherwise weird behavior happens when trying to write to the new partitions (ex. ota).