PlatformIO Community

Why is the firmware for ESP32-WROOM-32(NodeMCU-32s) so big?

Hi there!

I wrote a small code for NodeMCU-32S allowing to use OTA:

/* WebOTA.ino
 *  
 * by Roland Pelayo 
 * 
 * Update ESP32 firmware via external web server
 */


#include <Arduino.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <Update.h>

// location of firmware file on external web server
// change to your actual .bin location
#define HOST "https://tsecret-github.github.io/ideal-octo-umbrella/firmware.bin"

const char *CA = R"EOF(
-----BEGIN CERTIFICATE-----
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
-----END CERTIFICATE-----
)EOF";

HTTPClient client;
// Your WiFi credentials
const char* ssid = "SSID";
const char* password = "Password";
// Global variables
int totalLength;       //total size of firmware
int currentLength = 0; //current size of written firmware

// Function to update firmware incrementally
// Buffer is declared to be 128 so chunks of 128 bytes
// from firmware is written to device until server closes
void updateFirmware(uint8_t *data, size_t len){
  Update.write(data, len);
  currentLength += len;
  // Print dots while waiting for update to finish
  Serial.print('.');
  // if current length of written firmware is not equal to total firmware size, repeat
  if(currentLength != totalLength) return;
  Update.end(true);
  Serial.printf("\nUpdate Success, Total Size: %u\nRebooting...\n", currentLength);
  // Restart ESP32 to see changes 
  ESP.restart();
}

void setup() {
  Serial.begin(115200);
  // Start WiFi connection
  WiFi.mode(WIFI_MODE_STA);        
  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
  }
  delay(10000);

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  // Connect to external web server
  if (!client.begin(HOST, CA)) {
    digitalWrite(2, HIGH);
    return;
  }
  // Get file, just to check if each reachable
  int resp = client.GET();
  Serial.print("Response: ");
  Serial.println(resp);
  // If file is reachable, start downloading
  if(resp == 200){
      // get length of document (is -1 when Server sends no Content-Length header)
      totalLength = client.getSize();
      // transfer to local variable
      int len = totalLength;
      // this is required to start firmware update process
      Update.begin(UPDATE_SIZE_UNKNOWN);
      Serial.printf("FW Size: %u\n",totalLength);
      // create buffer for read
      uint8_t buff[128] = { 0 };
      // get tcp stream
      WiFiClient * stream = client.getStreamPtr();
      // read all data from server
      Serial.println("Updating firmware...");
      while(client.connected() && (len > 0 || len == -1)) {
           // get available data size
           size_t size = stream->available();
           if(size) {
              // read up to 128 byte
              int c = stream->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size));
              // pass to function
              updateFirmware(buff, c);
              if(len > 0) {
                 len -= c;
              }
           }
           delay(1);
      }
  }else{
    Serial.println("Cannot download firmware file. Only HTTP response 200: OK is supported. Double check firmware location #defined in HOST.");
  }
  client.end();
  
}

void loop() {}

The problem is that the firmware is too big (823633 bytes or 823,633 KB).
I looked in Inspect and found out this information:

Home contains the following files(?):

  1. That is, what is it?
  2. Why does it contain ESP-IDF components?
  3. And can I make it smaller?

Here is the whole project for experimentation:

It also seems to me that the framework-arduinoespressif32 takes up too much space (30.6 KB) can it be made smaller?

Thanks!

With the hope of the help of the great people of this forum

Do you mean generally too big or too big for OTA? You’re using a non-standard partition table for that.

The .elf file also shows the info on contained sub libraries, some of which come for runner/ etc as their path.

Arduino-ESP32 is a component on top of ESP-IDF. More precisely, it contains a precompiled ESP-IDF v4.4 version and its headers. As such, Arduino-ESP32 is at least as big ESP-IDF.

PlatformIO already default-builds with -Os (optimize for size) and the linker should strip out unused symbols. I’m not sure if LTO (link time optimization) is used though, it could shave off a few kilobytes. But all in all, not a lot of savings are to be had I think. ESP-IDF is a gigantic framework with tons of components and stacks built into that, and putting stuff on top of that only makes it worse. The only sensible approach would be to use ESP-IDF directly instead of with the Arduino layer.

Well thank you. Can you recommend anything for learning ESP-IDF?

And yet, where can I find libraries for ESP-IDF?

You should first get a baseline on ESP-IDF by using platform-espressif32/examples/espidf-blink at develop · platformio/platform-espressif32 · GitHub. PlatformIO supports it too.

General ESP-IDF documentation is at esp-idf.readthedocs.io/. Note when using PlatformIO, the used ESP-IDF version is 4.3.2. When copying code from the ESP-IDF repos you should be on that version branch.

ESP-IDF is very feature rich on its own, see

And third-party repos like GitHub - UncleRus/esp-idf-lib: Component library for ESP32, ESP32-S2, ESP32-C3 and ESP8266.

Over a year ago I made a minimal project that tried to do a printf() with the least amount of code possible: GitHub - maxgerhardt/minimal-esp32-sdk: Implements a no-dependencies (e.g. to ESP-IDF or Arduino-ESP32) SDK for the ESP32.. That is a 368 Byte firmware using functions from the ESP32 mask-rom (aka not flash) achieving a printf(“Hello world”). Of course it can’t do anything else, like other peripherals, WiFi, etc. Adding in Espressif’s FreeRTOS version, the lwIP stack and everything would blow up the size immediately again.

1 Like