Arduino

How to Serial.println() a std::string

In Arduino, if you have a std::string:

std::string str = "test";

you can’t directly print it – trying to do so leads to the following error messages:

src/main.cpp: In function 'void setup()':
src/main.cpp:122:22: error: no matching function for call to 'HardwareSerial::println(std::__cxx11::string&)'
   Serial.println(cert);
                      ^
In file included from /home/uli/.platformio/packages/[email protected]2/cores/esp32/Stream.h:26,
                 from /home/uli/.platformio/packages/[email protected]2/cores/esp32/Arduino.h:166,
                 from src/main.cpp:1:
/home/uli/.platformio/packages/[email protected]2/cores/esp32/Print.h:96:12: note: candidate: 'size_t Print::println(const __FlashStringHelper*)'
     size_t println(const __FlashStringHelper *);
            ^~~~~~~
/home/uli/.platformio/packages/[email protected]2/cores/esp32/Print.h:96:12: note:   no known conversion for argument 1 from 'std::__cxx11::string' {aka 'std::__cxx11::basic_string<char>'} to 'const __FlashStringHelper*'
/home/uli/.platformio/packages/[email protected]2/cores/esp32/Print.h:97:12: note: candidate: 'size_t Print::println(const String&)'
     size_t println(const String &s);

 

Solution:

You can use .c_str() to convert it to a NUL-terminated char* which can be printed directly:

Serial.println(str.c_str());

 

Posted by Uli Köhler in Arduino, C/C++, Embedded

How to convert Arduino String to std::string

If you have an Arduino String:

String arduinoStr = "test123";

you can easily convert it to a std::string by using:

std::string stdStr(arduinoStr.c_str(), arduinoStr.length());

The std::string constructor will copy the data, therefore you can de-allocate the Arduino String instance safely.

Posted by Uli Köhler in Arduino, C/C++

How to check if value exists in ArduinoJSON

Option 1: Use containsKey()

if(doc.containsKey("speed")) {
    float value = doc["speed"];
} else {
    // Speed does not exist
}

Option 2: Use default values

// If doc["speed"] does not exist, speed will be NaN
float speed = doc["speed"] | nanf(nullptr);
if(speed != nanf(nullptr)) {
   // TODO do something with speed
}

 

Posted by Uli Köhler in Arduino, Embedded

How to compute Ethernet CRC32 on ESP32 (0x04C11DB7)

The ESP32 ROM provides functionality for calculating CRC8, CRC16 & CRC32 checksums, but that functionality is poorly documented.

By educated trial and error and comparing with Arduino_CRC32 (which implements the Ethernet CRC32 algorithm with polynomial 0x04C11DB7 based on the pyCRC library) I found out how to compute the CRC32 checksum using the Ethernet polynomial.

First, include crc.h:

#include <esp32/rom/crc.h>

Now given a buffer with length length, use this code:

uint32_t romCRC = (~crc32_le((uint32_t)~(0xffffffff), (const uint8_t*)buffer, length))^0xffffffff;

Complete example code

This PlatformIO/Arduino code compares the result of the ESP32 ROM CRC32 functiolity by printing out both results on the serial port.

#include <Arduino.h>
#include <esp32/rom/crc.h>
#include <Arduino_CRC32.h>

void setup() {
    Serial.begin(115200);
}

void loop() {
    const char* data = "ABCDEFGHIJ";
  
    // Compute using ESP32 ROM CRC library
    uint32_t romCRC = (~crc32_le((uint32_t)~(0xffffffff), (const uint8_t*)data, 8))^0xffffffFF;

    // Compute using Arduino_CRC32 library (based on pyCRC)
    Arduino_CRC32 crc32;
    uint32_t libCRC = crc32.calc((uint8_t const *)data, 8);

    // Print out btoh v
    char crcBytes[4];
    memcpy(crcBytes, &romCRC, sizeof(uint32_t));
    Serial.printf("ROM CRC: %02X %02X %02X %02X\n", crcBytes[0], crcBytes[1], crcBytes[2], crcBytes[3]);

    memcpy(crcBytes, &libCRC, sizeof(uint32_t));
    Serial.printf("Lib CRC: %02X %02X %02X %02X\n", crcBytes[0], crcBytes[1], crcBytes[2], crcBytes[3]);
    Serial.println("\n");
    delay(500);
}
[env:esp32dev]
platform = espressif32
platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#2.0.3
board = esp32dev
framework = arduino
monitor_speed = 115200
lib_deps =
    arduino-libraries/[email protected]^1.0.0

Example output:

ROM CRC: 1C B6 DC 68
Lib CRC: 1C B6 DC 68

 

Posted by Uli Köhler in Arduino, ESP8266/ESP32

How to fix PlatformIO No such file or directory bootloader__80m.bin/bootloader__40m.bin

Problem:

While trying to upload/flash an ESP32(S2/S3) project using PlatformIO with a platformio.ini like this:

[env:esp32-s2-saola-1]
platform = espressif32
board = esp32-s2-saola-1
framework = arduino

you see an error message like

esptool write_flash: error: argument <address> <filename>: [Errno 2] No such file or directory: '/home/uli/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32s2/bin/bootloader__80m.bin'
*** [upload] Error 2

or

esptool write_flash: error: argument <address> <filename>: [Errno 2] No such file or directory: '/home/uli/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/bin/bootloader__40m.bin'

Solution:

This is a bug in version 2.0.4 of the arduino-espressif32 framework. In order to work around it, use version 2.0.3 until this bux is fixed. You can do this by appending

platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#2.0.3

to platformio.ini. Full example:

[env:esp32dev]
platform = espressif32
platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#2.0.3
board = esp32dev
framework = arduino

 

Posted by Uli Köhler in Arduino, ESP8266/ESP32, PlatformIO

Teensy 4.x timer interrupt example using TimerTree

void myTimerInterrupt() {
  // TODO Your code goes here
  // The following functions may be useful here:
  // Timer3.start(); // Start counting & clear counter
  // Timer3.stop(); // => stop counting but do not clear counter
  // Timer3.restart(); // => clear counter
  // Timer3.resume(); // => Start, without clearing counter
}

void setup()
{
  Timer3.initialize(20000);
  Timer3.attachInterrupt(myTimerInterrupt);
  Timer3.start();
}

 

Posted by Uli Köhler in Arduino, Electronics, Embedded, Teensy

How to Arduino attachInterrupt() with both RISING and FALLING edge

You can use attachInterupt() with CHANGE to trigger on both RISING and FALLING flanks.

#define INTERRUPT_PIN 13 // Choose any pin with interrupt functionality here.

void myInterrupt() {
  // TODO Your code goes here.
}

void setup() {
  attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), myInterrupt, CHANGE);
}

 

Posted by Uli Köhler in Arduino, Embedded

How to fix PlatformIO ArduinoJSON .pio/libdeps/ESP32/ArduinoJson/src/ArduinoJson/Variant/ConverterImpl.hpp:43:5: error: static assertion failed: To use 64-bit integers with ArduinoJson, you must set ARDUINOJSON_USE_LONG_LONG to 1

Problem:

While trying to compile your PlatformIO project, you see an error message like

.pio/libdeps/ESP32/ArduinoJson/src/ArduinoJson/Variant/ConverterImpl.hpp:43:5: error: static assertion failed: To use 64-bit integers with ArduinoJson, you must set ARDUINOJSON_USE_LONG_LONG to 1. See https://arduinojson.org/v6/api/config/use_long_long/
     ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T);
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from .pio/libdeps/ESP32/ArduinoJson/src/ArduinoJson.hpp:30,
                 from .pio/libdeps/ESP32/ArduinoJson/src/ArduinoJson.h:9,
                 from include/MQTT/StatusMessage.hpp:2,
                 from src/MQTT/StatusMessage.cpp:1:
.pio/libdeps/ESP32/ArduinoJson/src/ArduinoJson/Variant/ConverterImpl.hpp: In instantiation of 'static void ArduinoJson6185_1::Converter<T, Enable>::toJson(const T&, ArduinoJson6185_1::VariantRef) [with T = long long int (*)(); Enable = void]':
.pio/libdeps/ESP32/ArduinoJson/src/ArduinoJson/Variant/VariantRef.hpp:98:27:   required from 'bool ArduinoJson6185_1::VariantRef::set(T*) const [with T = long long int()]'
.pio/libdeps/ESP32/ArduinoJson/src/ArduinoJson/Object/MemberProxy.hpp:58:5:   required from 'ArduinoJson6185_1::MemberProxy<TParent, TStringRef>::this_type& ArduinoJson6185_1::MemberProxy<TParent, TStringRef>::operator=(TChar*) [with TChar = long long int(); TObject = ArduinoJson6185_1::JsonDocument&; TStringRef = const char*; ArduinoJson6185_1::MemberProxy<TParent, TStringRef>::this_type = ArduinoJson6185_1::MemberProxy<ArduinoJson6185_1::JsonDocument&, const char*>]'

Solution

Add -DARDUINOJSON_USE_LONG_LONG=1 to the build_flags in platformio.ini. If build_flags does not exist in platformio.ini, create it after [env:...]

build_flags = -DARDUINOJSON_USE_LONG_LONG=1

 

Posted by Uli Köhler in Arduino, Electronics, ESP8266/ESP32, PlatformIO

How to insert “null” value in ArduinoJSON

Just use nullptr:

json["myvalue"] = nullptr;

If nullptr is not available, use the equivalent (char*)0:

json["myvalue"] = (char*)0;

 

Posted by Uli Köhler in Arduino, Embedded

How to fix error: invalid conversion from ‘int’ to ‘esp_mqtt_event_id_t’ on the ESP8266 or ESP32

If you see an error message like

src/main.cpp: In function 'void InitMQTT()':
/home/uli/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_event/include/esp_event_base.h:37:32: error: invalid conversion from 'int' to 'esp_mqtt_event_id_t' [-fpermissive]
 #define ESP_EVENT_ANY_ID       -1               /**< register handler for any event id */

src/main.cpp:80:44: note: in expansion of macro 'ESP_EVENT_ANY_ID'
     esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, client);
                                            ^~~~~~~~~~~~~~~~

replace ESP_EVENT_ANY_ID by MQTT_EVENT_ANY and recompile. This will fix the issue. Using ESP_EVENT_ANY_ID was possible in an outdated version of the MQTT library.

 

Posted by Uli Köhler in Arduino, Embedded, ESP8266/ESP32, MQTT, Networking, PlatformIO

How to use a specific espressif32 platformio version in PlatformIO

For production projects, you often want to lock platform & library versions in order to avoid an update suddenly breaking your code:

In platformio.ini, instead of

platform = espressif32

use this syntax to refer to the git repository and a specific tag (v3.4.0 in this example) directly:

platform = https://github.com/platformio/platform-espressif32.git#v3.4.0
Posted by Uli Köhler in Arduino, Electronics, Embedded, ESP8266/ESP32, PlatformIO

What ESP-IDF version does PlatformIO with Arduino use

On Dec 17th 2021, PlatformIO with this default platformio.ini config (with platformio-espressif32 v3.4.0):

[env:ESP32]
platform = espressif32
board = esp32dev
framework = arduino

uses ESP-IDF version 3.3.5

You can find this out yourself by printing all preprocessor flags as described in our post on How to print all preprocessor flags in PlatformIO and then looking for ESP_IDF_VERSION_... definitions using:

grep ESP_IDF_VERSION .pio/build/ESP32/src/main.cpp.o

which currently results in

#define ESP_IDF_VERSION_MINOR 3
#define ESP_IDF_VERSION_MAJOR 3
#define ESP_IDF_VERSION_PATCH 5

 

Posted by Uli Köhler in Arduino, ESP8266/ESP32, PlatformIO

How to use specific arduino-esp32 version in PlatformIO

Add this line to platformio.ini in order to use a specific arduino-esp32 version – such as 1.0.6:

platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#1.0.6

Note that for some upstream versions – at Dec 17 2021 that is arduino-esp32 v2.x, you also need to use a different platform:

platform = https://github.com/platformio/platform-espressif32.git#feature/arduino-upstream
platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#2.0.1
Posted by Uli Köhler in Arduino, Embedded, ESP8266/ESP32, PlatformIO

How to fix Arduino error: ‘size_t’ has not been declared

Problem:

In Arduino, you see an error message like

src/main.cpp:7:48: error: 'size_t' has not been declared
void MyFunction(size_t size);

Solution:

Include stddef.h where size_t is declared:

#include <stddef.h>

Add this line to the top of the file where the error occured.

Posted by Uli Köhler in Arduino, C/C++, Embedded, PlatformIO

How to fix Arduino I2C Wire error: call of overloaded ‘begin(const int&, const int&, int)’ is ambiguous

Problem:

You are trying to call Wire.begin() for I2C using

Wire.begin(Pin_I2C_SDA, Pin_I2C_SCL, 400000);

but you see an error message like

src/MyI2C.cpp: In function 'void MyInitI2C()':
src/NyI2C.cpp:139:47: error: call of overloaded 'begin(const int&, const int&, int)' is ambiguous
     Wire.begin(Pin_I2C_SDA,Pin_I2C_SCL, 400000);
                                               ^
In file included from include/MyIO.hpp:2:0,
                 from src/MyI2C.cpp:2:
/home/uli/.platformio/packages/framework-arduinoespressif32/libraries/Wire/src/Wire.h:79:10: note: candidate: bool TwoWire::begin(int, int, uint32_t)
     bool begin(int sda=-1, int scl=-1, uint32_t frequency=0); // returns true, if successful init of i2c bus
          ^
/home/uli/.platformio/packages/framework-arduinoespressif32/libraries/Wire/src/Wire.h:80:10: note: candidate: bool TwoWire::begin(uint8_t, int, int, uint32_t)
     bool begin(uint8_t slaveAddr, int sda=-1, int scl=-1, uint32_t frequency=0);

Solution:

This happens with specific versions of the Arduino framework. For me it happened specifically when upgrading to arduino-esp32 version 2.0.1.

You need to explicitly cast the third argument (400000) to uint32_t in order to tell the compiler which of the two functions you want to call:

Wire.begin(Pin_I2C_SDA, Pin_I2C_SCL, 400000);
Posted by Uli Köhler in Arduino, C/C++, Embedded, PlatformIO

How to initialize LittleFS in PlatformIO on the ESP32 using the lorol/LITTLEFS library

Currently you need to add the LittleFS-ESP32 library in platformio.ini (the library is available as part of the core arduino-espressif32 bleeding edge version but you need that library in the standard version):

lib_deps =
    lorol/LittleFS_esp32 @ ^1.0.6

Now include LittleFS:

#include <LITTLEFS.h>

#define SPIFFS LITTLEFS

Initialize it using

// Initialize LittleFS
if (!LITTLEFS.begin(false /* false: Do not format if mount failed */)) {
  Serial.println("Failed to mount LittleFS");
  if (!LITTLEFS.begin(true /* true: format */)) {
    Serial.println("Failed to format LittleFS");
  } else {
    Serial.println("LittleFS formatted successfully");
  }
} else { // Initial mount success
}

 

Posted by Uli Köhler in Arduino, Embedded, ESP8266/ESP32, PlatformIO

ArduinoJSON: How to fix 1 or 0 being printed instead of true/false

volatile bool value = true;

DynamicJsonDocument json(1024);
json["ok"] = value;
serializeJson(json, Serial);

This will print {"ok": 1} instead of {"ok": true} due to value being declared volatile (it works with just bool value, it does not work with volatile bool value).

In order to force {"ok": true}, just case value to bool:

json["ok"] = (bool)value;

Full example

volatile bool value = true;

DynamicJsonDocument json(1024);
json["ok"] = (bool)value;
serializeJson(json, Serial);

 

Posted by Uli Köhler in Arduino, Embedded, PlatformIO

What is the FreeRTOS equivalent to Arduino’s delay()?

Instead of Arduino’s

delay(5); // delay for five milliseconds

use this in FreeRTOS:

vTaskDelay(5 / portTICK_PERIOD_MS);
Posted by Uli Köhler in Arduino, Electronics, Embedded, FreeRTOS

What is the value of portTICK_PERIOD_MS and configTICK_RATE_HZ on the ESP32 using PlatformIO?

When you use PlatformIO with the Arduino framework in its default configuration on the ESP32, configTICK_RATE_HZ is set to 1000. In other words, FreeRTOS has a default tick frequency of 1kHz. This is defined in sdkconfig.h:

#define CONFIG_FREERTOS_HZ 1000

Hence portTICK_PERIOD_MS is 1. In my opinion, a tick rate of 1kHz is a sane configuration for most usecases.

I found the value by using the following code on an ESP32:

Serial.println("Timing: ");
Serial.println(portTICK_PERIOD_MS);
Serial.println(configTICK_RATE_HZ);

 

Posted by Uli Köhler in Arduino, Electronics, Embedded, ESP8266/ESP32, FreeRTOS, PlatformIO

How to read 8-bit I2C register using Arduino Wire library: A minimal example

The following code demonstrates how to read a register that is 1 byte (8 bits) long over I2C. It will work with almost all I2C devices like EEPROMs, ADCs and others, provided you have the correct. Note that some devices like the LAN9303 have a slightly different addressing scheme or other peculiarities. In my opinion, it’s most efficient to just try out the standard way of reading a register and start from there.

Note that this code does not implement error handling for the sake of simplicity. Additionally, we wait for data using delay() instead of Wire.available(). This is a minimal example so it creates minimal confusion for the reader. We will provide a full example with error handling in a followup post.

const uint8_t SLAVE_I2C_ADDRESS = 0b1010;
const uint16_t SLAVE_I2C_REGISTER_ADDRESS = 0x50;

Wire.beginTransmission(SLAVE_I2C_ADDRESS);
Wire.write(SLAVE_I2C_REGISTER_ADDRESS);
Wire.endTransmission();
Wire.requestFrom(SLAVE_I2C_ADDRESS, 1); // This register is 8 bits = 1 byte long
delay(2); // Wait for data to be available
// Read directly into an uint8_t
uint8_t buf = (uint8_t)Wire.read();
// Print register value
Serial.printf("Register value: %02x\r\n", buf);

Also see:

Posted by Uli Köhler in Arduino, C/C++, Electronics, Embedded, PlatformIO