ESP8266/ESP32

How to connect CHIP_PU pin on ESP32Sx

The CHIP_PU (Chip PowerUp) pin on ESP32 family processors such as the ESP32S2 is equivalent to the EN (enable) or ~RST pin on other microcontrollers.

When CHIP_PU is pulled high (i.e. to 3.3V), the ESP32 is enabled and will run the firmware.

When CHIP_PU is pulled low (i.e. to GND), the ESP32 is disabled and shut down and will not run the firmware.

In other words, in most applications you want to connect a 10kOhm resistor from CHIP_PU to 3.3V and – if needed – a reset button from the CHIP_PU pin to GNDYou can not operate the ESP32S2 without a pullup resistor . This is clearly stated in the ESP32S2 datasheet, section 2.2:

Note: Do not leave the CHIP_PU pin floating.

On the ESP32S2-WROOM-I module, the CHIP_PU is directly connected to the module’s EN pin wut

Posted by Uli Köhler in ESP8266/ESP32

How much RAM does the ESP32-C3 have?

The ESP32-C3 has 400 kBytes of integrated SRAM (16 kbytes cache).

Source: ESP32-C3 datasheet

Posted by Uli Köhler in ESP8266/ESP32

How to fix ESP32 A fatal error occurred: ESP32 ROM does not support function erase_flash.

Problem:

When running esptool erase_flash, you an error message like:

esptool.py v2.8
Found 1 serial ports
Serial port /dev/ttyUSB0
Connecting....
Detecting chip type... ESP32
Chip is ESP32D0WDQ6 (revision 1)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
WARNING: Detected crystal freq 41.01MHz is quite different to normalized freq 40MHz. Unsupported crystal in use?
Crystal is 40MHz
MAC: 7c:9e:bd:f4:60:e0
Enabling default SPI flash mode...
Erasing flash (this may take a while)...

A fatal error occurred: ESP32 ROM does not support function erase_flash.

Solution:

You are likely using an outdated version of esptoolUse the esptool from GitHub:

git clone https://github.com/espressif/esptool.git

then run it using

cd esptool
python3 esptool.py erase_flash
Posted by Uli Köhler in Electronics, ESP8266/ESP32

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

ESP32 Wireguard example with HTTP access over Wireguard (PlatformIO)

In this example we will use Wireguard-ESP32-Arduino in order to make HTTP requests over Wireguard on the ESP32.

[env:esp32-gateway]
platform = espressif32
board = esp32-gateway
framework = arduino
monitor_speed = 115200
lib_deps =
    ciniml/WireGuard-ESP32@^0.1.5
#include <WiFi.h>
#include <WireGuard-ESP32.h>

// WiFi configuration --- UPDATE this configuration for your WiFi AP
char ssid[] = "MyWifiESSID";
char password[] = "my-wifi-password";

// WireGuard configuration --- UPDATE this configuration from JSON
char private_key[] = "gH2YqDa+St6x5eFhomVQDwtV1F0YMQd3HtOElPkZgVY=";
IPAddress local_ip(10, 217, 59, 2);
char public_key[] = "X6NJW+IznvItD3B5TseUasRPjPzF0PkM5+GaLIjdBG4=";
char endpoint_address[] = "192.168.178.133"; // IP of Wireguard endpoint to connect to.
int endpoint_port = 19628;

static WireGuard wg;

void setup()
{
    Serial.begin(115200);
    Serial.println("Connecting to the AP...");
    WiFi.begin(ssid, password);
    while( !WiFi.isConnected() ) {
        delay(100);
    }
    Serial.println(WiFi.localIP());
    Serial.println("Adjusting system time...");
    configTime(9 * 60 * 60, 0, "ntp.jst.mfeed.ad.jp", "ntp.nict.jp", "time.google.com");

    Serial.println("Connected. Initializing WireGuard...");
    wg.begin(
        local_ip,
        private_key,
        endpoint_address,
        public_key,
        endpoint_port);
}

void loop()
{
    WiFiClient client;

    /**
     * Connect to
     * python3 -m http.server
     */
    if( !client.connect("10.217.59.1", 8000) ) {
        Serial.println("Failed to connect...");
        delay(1000);
        return;
    } else { // Client connected successfully. Send dummy HTTP request.
        client.write("GET /wireguard-test HTTP/1.1\r\n");
        client.write("Host: wireguard.test.com\r\n");
        client.write("\r\n\r\n");
    }

}

Remember to replace 192.168.238.133 by the IP address of the computer your ESP32 should connect to (i.e. the computer running WireGuard). You also need to enter the correct Wifi credentials.

On the computer, deploy this WireGuard config:

[Interface]
# Name = Computer
PrivateKey = ONj6Iefel47uMKtWRCSMLan2UC5eW3Fj9Gsy9bqcyEc=
Address = 10.217.59.1/24
ListenPort = 19628

[Peer]
# Name = ESP32
PublicKey = H3KaL/X94984cLDNWFsM4Hx6Rs/Ku0bW2ECkDUn7wFw=
AllowedIPs = 10.217.59.2/32
PersistentKeepalive = 60

which is auto-generated by the following GuardMyWire config:

{
    "rules": {
        "Node": {
            "connect_to": ["*"],
            "keepalive": 60
        }
    },
    "peers": [
        {
            "name": "Computer",
            "endpoint": "192.168.178.233:19628",
            "addresses": [
                "10.217.59.1/24"
            ],
            "type": "Node",
            "interface_name": "wg0"
        }, {
            "name": "ESP32",
            "addresses": [
                "10.217.59.2/24"
            ],
            "type": "Node",
            "interface_name": "wg0"
        }
    ]
}

Enable this config and start a Python HTTP server to receive the requests using

python3 -m http.server

Now flash the firmware on the ESP32.

Using wg show you should see the ESP connecting:

interface: Computer
  public key: X6NJW+IznvItD3B5TseUasRPjPzF0PkM5+GaLIjdBG4=
  private key: (hidden)
  listening port: 19628

peer: H3KaL/X94984cLDNWFsM4Hx6Rs/Ku0bW2ECkDUn7wFw=
  endpoint: 10.9.1.108:19628
  allowed ips: 10.217.59.2/32
  latest handshake: 5 seconds ago
  transfer: 11.71 MiB received, 10.43 MiB sent
  persistent keepalive: every 1 minute

Look for the

latest handshake: 5 seconds ago

line.

On the shell running python3 -m http.server you should see the dummy HTTP requests:

10.217.59.2 - - [31/Dec/2021 02:36:48] "GET /wireguard-test HTTP/1.1" 404 -
10.217.59.2 - - [31/Dec/2021 02:36:48] code 404, message File not found
10.217.59.2 - - [31/Dec/2021 02:36:48] "GET /wireguard-test HTTP/1.1" 404 -
10.217.59.2 - - [31/Dec/2021 02:36:48] code 404, message File not found
10.217.59.2 - - [31/Dec/2021 02:36:48] "GET /wireguard-test HTTP/1.1" 404 -
10.217.59.2 - - [31/Dec/2021 02:36:48] code 404, message File not found
Posted by Uli Köhler in ESP8266/ESP32, PlatformIO, Wireguard

ESPAsyncWebserver handler example with String query argument

This example is based on our basic example and shows how to use an String query parameter, e.g. http://192.168.1.112/api/test?param=abc123

server.on("/api/test", HTTP_GET, [](AsyncWebServerRequest *request) {
      String param = request->getParam("param")->value();
      // TODO: Do something with param!

      // Respond with JSON {"status": "ok"}
      AsyncResponseStream *response = request->beginResponseStream("application/json");
      DynamicJsonDocument json(1024);
      json["status"] = "ok";
      json["param"] = param;
      serializeJson(json, *response);
      request->send(response);
});

 

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

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 initialize LittleFS in PlatformIO on the ESP32 using the lorol/LittleFS library

Note: I don’t recommend using the loros/LittleFS library when using an up-to-date version of the arduino-esp32 framework such as 2.0.5 – the newer versions of this framework come with an embedded LittleFS framework. See TODO for instructions how to initialize the 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

ESPAsyncWebserver basic ArduinoJSON handler example

server.on("/api/test", HTTP_GET, [](AsyncWebServerRequest *request) {
      // Respond with JSON {"status": "ok"}
      AsyncResponseStream *response = request->beginResponseStream("application/json");
      DynamicJsonDocument json(1024);
      json["status"] = "ok";
      serializeJson(json, *response);
      request->send(response);
});

 

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

ESPAsyncWebserver handler example with int query argument

This example is based on our basic example and shows how to use an int query parameter, e.g. http://192.168.1.112/api/test?param=2

server.on("/api/test", HTTP_GET, [](AsyncWebServerRequest *request) {
      int param = request->getParam("param")->value().toInt();
      // TODO: Do something with param!

      // Respond with JSON {"status": "ok"}
      AsyncResponseStream *response = request->beginResponseStream("application/json");
      DynamicJsonDocument json(1024);
      json["status"] = "ok";
      json["param"] = param;
      serializeJson(json, *response);
      request->send(response);
});

 

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

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 pass firewall using PlatformIO espota ArduinOTA upload

ArduinoOTA’s protocol tries to connect to the host which is trying to program the device on a randomly chosen port. This often leads to the packets being filtered in a firewall since no rule exists to pass the packet and they are not related to an existing connection.

You could create a firewall rule to pass all traffic from the ESP8266/ESP32 to the programming host, but that is extremely insecure since it allows a hacked IoT device to hack your devices.

In order to fix it, add a fixed host port in platformio.ini using

upload_flags = --host_port=55910

and add these firewall rules:

allow from <programming host> to <IoT device> port 55910 TCP
allow from <IoT device> to <programming host> port 55190 TCP

Complete platformio.ini example:

[env:d1_mini_ota]
extends = env:d1_mini
upload_protocol = espota
upload_port = 192.168.178.25
upload_flags = --host_port=55910

 

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

How to use ESP32 as USB-to-UART converter in PlatformIO

The ESP32 can easily be used as USB-to-UART converter. Note that the ESP32 does not feature an USB interface by itself and ESP32 boards with an onboard USB connector just use an USB-to-UART converter (this is a separate chip on the board). Hence, from the ESP32 perspective, it

You can map UART TX and RX to any GPIO pin on the ESP32. While there are very, very slight performance advantages to using a set of predefined pins, this does not really matter in practice. In this example, we will use pin GPIO2 for UART RX and pin GPIO4 for UART TX.

Basically, the code is just copying bytes between Serial2 and Serial (connected to USB):

// Copy bytes incoming via PC serial
while (Serial.available() > 0) {
  Serial2.write(Serial.read());
}
// Copy bytes incoming via UART serial
while (Serial2.available() > 0) {
  Serial.write(Serial2.read());
}

Full example

#include <Arduino.h>

#define UART_RX_PIN 2 // GPIO2
#define UART_TX_PIN 4 // GPIO4

void setup() {
  // Serial connects to the computer
  Serial.begin(115200);
  // Serial2 is the hardware UART port that connects to external circuitry
  Serial2.begin(115200, SERIAL_8N1,
                UART_RX_PIN,
                UART_TX_PIN);
}

void loop() {
  // Copy byte incoming via PC serial
  while (Serial.available() > 0) {
    Serial2.write(Serial.read());
  }
  // Copy bytes incoming via UART serial
  while (Serial2.available() > 0) {
    Serial.write(Serial2.read());
  }
}

Regarding platformio.ini, we just need to set the monitor_speed to match the value in Serial.begin(115200);:

[env:nodemcu-32s]
platform = espressif32
board = nodemcu-32s
framework = arduino
monitor_speed = 115200

 

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