4 minute read

If you find yourself running out of flash space for your ESP32 applications this post will give you 3 very simple ways to get some of that space back.

Assuming your project uses OTA you are probably either using a default partition table provided by Espressif or you copy and pasted an example from the internet that looks something like this.

# ESP-IDF Partition Table
# Name,   Type, SubType, Offset,  Size, Flags
nvs,      data, nvs,     0x9000,  0x4000,
otadata,  data, ota,     0xd000,  0x2000,
phy_init, data, phy,     0xf000,  0x1000,
factory,  app,  factory, 0x10000,  1M,
ota_0,    app,  ota_0,   0x110000, 1M,
ota_1,    app,  ota_1,   0x210000, 1M,

Because your application uses OTA you can easily reclaim over a meg of flash space with these simple changes.

Remove the factory Partition

Almost every OTA example partition table out there contains the factory partition in it. There’s just one problem. Not only do you not need it, but your OTA-enabled device will never actually use it. Directly from the Espressif Partition docs we read:

The bootloader will execute the factory app unless there it sees a partition of type data/ota, in which case it reads this partition to determine which OTA image to boot.

It goes on to make 2 very important points.

  • “OTA never updates the factory partition”
  • “If you want to conserve flash usage in an OTA project, you can remove the factory partition”

So in an OTA project, drop the factory partition completely and in our example above you instantly regain an entire meg of flash space.

phy_init Can Go Too

Almost every partition table I’ve ever seen has a phy_init partition. First of all, what the heck is it? From the docs we learn that this partition “is for storing PHY initialisation data. This allows PHY to be configured per-device, instead of in firmware.” Essentially, this allows you to customize the initialization data for your WiFi interface. This is especially useful in cases where you need to adjust that initialization on a per device basis. However, if your project does not require that kind of customization this is yet another wasted partition. If you have to ask “Does my project require that customization?” the answer is probably “No”. Reading from the docs again:

In the default configuration, the phy partition is not used and PHY initialisation data is compiled into the app itself. As such, this partition can be removed from the partition table to save space.

So unless you know what you are doing and intentionally told IDF to do so, this partition isn’t used by default and is therefore wasting 4K (0x1000) of flash space that you could be using for other things.

Resize the nvs Partition

The default nvs partition without OTA is 24K (0x6000) and with OTA is 16K (0x4000). The system does store things here like your wifi credentials but certainly doesn’t use the entire thing. This is an area where you should do some testing to see exactly how much of the partition is used and whether or not you will use it in your firmware. For example, with a basic WiFi configuration, this is what is output if you loop through all the nvs keys and look at the used space.

Count: UsedEntries = (119), FreeEntries = (637), AllEntries = (756)
key 'ap.sndchan', type '1' 
key 'opmode', type '1' 
key 'sta.ssid', type '66' 
key 'sta.pswd', type '66' 
key 'bssid.set', type '1' 
key 'sta.lis_intval', type '2' 
key 'sta.scan_method', type '1' 
key 'sta.sort_method', type '1' 
key 'sta.minrssi', type '17' 
key 'sta.minauth', type '1' 
key 'sta.apsw', type '66' 
key 'sta.pmf_e', type '1' 
key 'sta.pmf_r', type '1' 
key 'sta.rrm_e', type '1' 
key 'sta.btm_e', type '1' 
key 'sta.mbo_e', type '1' 
key 'cal_data', type '66' 
key 'cal_mac', type '66' 
key 'cal_version', type '4' 
key 'sta.chan', type '1' 
key 'sta.apinfo', type '66' 

This includes WiFi credentials and PHY data. As you can see, though, it is only using 119 entries of an available 756. This is with the default nvs partition size of 24K (0x6000). Each entry in NVS storage is 32 bytes plus some page overhead (32 bytes per page). With 637 entries free we have almost 20K of unused space in the nvs partition.

So you could also ask whether you should use it. Perhaps you are storing something in a separate SPIFFS partition that you could store in the nvs partition instead. You can’t just delete this partition and reducing it’s size doesn’t necessarily get you more app partition space since the app partitions have to be aligned to 0x10000 boundaries.

So in the case of the nvs partition you may reduce it’s size to make room for another partition of your choosing or, with the removal of the phy_init partition you might consider enlarging the nvs partition and utilizing it in your code to store stuff which could allow you to drop a SPIFFS partition. The idea here is to not leave large blocks of unused flash tied up in a partition that you aren’t using.


So using our original partition example above if we make all three of these simple tweaks we will have reclaimed over 1M of flash space that could be allocated to our application partitions.