Arduino

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 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

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

The following code demonstrates how to read a register that is 2 bytes (16 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.

Option 1: Reading the register into an uint16_t (recommended)

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, 2); // This register is 16 bits = 2 bytes long
delay(5); // Wait for data to be available
// Read directly into an uint32_t
uint16_t buf;
Wire.readBytes((uint8_t*)&buf, 2);
// Print register value
Serial.printf("Register value: %04x\r\n", __builtin_bswap16(buf));

For an explanation on why we need __builtin_bswap16(), see How to print 16-bit uint16_t as four hex digits in Arduino

Option 2: Reading the register into an uint8_t array

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, 2); // This register is 16 bits = 2 bytes long
delay(5); // Wait for data to be available
// Read into a 2-byte buffer
uint8_t buf[2];
Wire.readBytes(buf, 2);
// Print register value
Serial.printf("Register value: %02x%02x\r\n", buf[0], buf[1]);

Also see:

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

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

The following code demonstrates how to read a register that is 4 bytes (32 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.

Option 1: Reading the register into an uint32_t (recommended)

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, 4); // This register is 32 bits = 4 bytes long
delay(5); // Wait for data to be available
// Read directly into an uint32_t
uint32_t buf;
size_t actually_read = Wire.readBytes((uint8_t*)&buf, 4);
// Print register value
Serial.printf("Register value: %08lx\r\n", __builtin_bswap32(buf));

For an explanation on why we need __builtin_bswap32(), see How to print 32-bit uint32_t as eight hex digits in Arduino

Option 2: Reading the register into an uint8_t array

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, 4); // This register is 32 bits = 4 bytes long
delay(5); // Wait for data to be available
// Read into a 4-byte buffer
uint8_t buf[4];
size_t actually_read = Wire.readBytes(buf, 4);
// Print register value
Serial.printf("Register value: %02x%02x%02x%02x\r\n", buf[0], buf[1], buf[2], buf[3]);

Also see:

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

How to access LAN9303 registers over I2C using Arduino / PlatformIO

The LAN9303 has some peculiarities when accessing its registers. This post will not cover indirect register access but only access to the registers which are directly accessible over I2C. Note that the prerequisite for this is to configure the LAN9303 into a mode where management over the I2C slave interface is enabled. See How to get the LAN9303 into I2C managed mode for more info on how to do that.

The main point to take away is that you do not write the register offset from the datasheet (such as 0x50 for the Chip ID and revision register) in the I2C address byte but the address divided by 4 (0x50 >> 2 == 0x14). This is evidenced by figure 8-8 from the datasheet, copyright Microchip, listing the address byte as A[9:2] as opposed to the standard A[7:0]:

 

Example on how to access the register at offset 0x50 (Chip ID and revision register) in Arduino using the Wire library:

const uint8_t LAN9303_I2C_ADDRESS = 0b1010;
const uint16_t LAN9303_CHIPID_REV_Register = 0x50;

Wire.beginTransmission(LAN9303_I2C_ADDRESS);
Wire.write(LAN9303_CHIPID_REV_Register >> 2);
Wire.endTransmission();
Wire.requestFrom(LAN9303_I2C_ADDRESS, 4); // This register is 32 bits = 4 bytes long
delay(5); // Wait for data to be available

// Read directly into an uint8_t
uint32_t buf;
size_t actually_read = Wire.readBytes((uint8_t*)&buf, 4);
// Check if we have received all 4 bytes
if(actually_read != 4) {
    Serial.println("Did not read enough bytes");
}

// Print register value
Serial.printf("LAN9303 Chip ID and revision: %08lx\r\n", __builtin_bswap32(buf));

This will print

LAN9303 Chip ID and revision: 93030001

in other words: Chip ID = 0x9303, revision = 0x0001

 

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

How to print 64-bit uint64_t as sixteen hex digits in Arduino

When using Arduino, you often want to print the hex value of a 64-bit value such as a uint64_t, consisting of sixteen hex digits. For example, if you have uint64_t val = 169557370125;, you intend to print 000000277a68250d.

In Arduino you can do that using Serial.printf() with %08lx08lx as format specifier, splitting the uint64_t in two uint32_t instances and printing those one after another:

Serial.printf("%08lx%08lx\r\n",
    ((uint32_t)((val >> 32) & 0xFFFFFFFF)),
    ((uint32_t)(val & 0xFFFFFFFF)));

 

See How to print 32-bit uint32_t as eight hex digits in Arduino for more information on what %x means and why we need to use the 08 in %08x as a printf format specifier.

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

How to print 32-bit uint32_t as eight hex digits in Arduino

When using Arduino, you often want to print the hex value of a 32-bit value such as a uint32_t, consisting of eight hex digits. For example, if you have uint32_t val = 9177025;, you intend to print 008C07C1.

In Arduino you can do that using Serial.printf() with %08lx as format specifier. Furthermore, you typically want to invert the byte order of the uint32_t using __builtin_bswap32()since it’s more inuitive to write the hex value MSB-first (big-endian) while most hardware platforms represent the uint32_t as LSB-first (little-endian):

Serial.printf("val = %08lx\r\n", __builtin_bswap32(val));

When using printf, %x means to format the value as hex whereas l tells printf() that the argument is a long (32 bit) as opposed to an int (16 bit). 08 means to pad the value with 0s up to a length of 8 digits. If you would format 9177025 using just %x, it would print 008C07C1  instead of 008C07C1. This is why you need to use %08lx instead.

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

How to print 16-bit uint16_t as four hex digits in Arduino

When using Arduino, you often want to print the hex value of a 16-bit value such as a uint16_t, consisting of four hex digits. For example, if you have uint16_t val = 2022;, you intend to print 07E6.

In Arduino you can do that using Serial.printf() with %04x as format specifier.

Furthermore, you typically want to invert the byte order of the uint16_t using __builtin_bswap16()since it’s more inuitive to write the hex value MSB-first (big-endian) while most hardware platforms represent the uint16_t as LSB-first (little-endian):

Serial.printf("val = %04x\r\n", __builtin_bswap16(val));

When using printf, %x means to format the value as hex. 04 means to pad the value with 0s up to a length of 4 digits. If you would format 2022 using just %x, it would print 7E6  instead of 07E5. This is why you need to use %04x instead.

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

How to print byte as two hex digits in Arduino

In embedded programming, you often want to print the hex value of a byte, consisting of two hex digits. For example, if you have uint8_t val = 14;, you intend to print 0x0E.

In Arduino you can do that using Serial.printf() with %02x as format specifier:

Serial.printf("val = %02x\r\n", val);

When using printf, %x means to format the value as hex. 02 means to pad the value with 0s up to a length of 2 digits. If you would format 14 using just %x, it would print E  instead of 0E. This is why you need to use %02x.

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