Partition Tables - ESP32 - — ESP-IDF Programming Guide latest documentation (original) (raw)

[中文]

Overview

A single ESP32's flash can contain multiple apps, as well as many different kinds of data (calibration data, filesystems, parameter storage, etc). For this reason a partition table is flashed to (default offset) 0x8000 in the flash.

The partition table length is 0xC00 bytes, as we allow a maximum of 95 entries. An MD5 checksum, used for checking the integrity of the partition table at runtime, is appended after the table data. Thus, the partition table occupies an entire flash sector, which size is 0x1000 (4 KB). As a result, any partition following it must be at least located at (default offset) + 0x1000.

Each entry in the partition table has a name (label), type (app, data, or something else), subtype and the offset in flash where the partition is loaded.

The simplest way to use the partition table is to open the project configuration menu (idf.py menuconfig) and choose one of the simple predefined partition tables under CONFIG_PARTITION_TABLE_TYPE:

In both cases the factory app is flashed at offset 0x10000. If you execute idf.py partition-table then it will print a summary of the partition table.

Built-in Partition Tables

Here is the summary printed for the "Single factory app, no OTA" configuration:

ESP-IDF Partition Table

Name, Type, SubType, Offset, Size, Flags

nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 1M,

Here is the summary printed for the "Factory app, two OTA definitions" configuration:

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,

Creating Custom Tables

If you choose "Custom partition table CSV" in menuconfig, then you can also enter the name of a CSV file (in the project directory) to use for your partition table. The CSV file can describe any number of definitions for the table you need.

The CSV format is the same format as printed in the summaries shown above. However, not all fields are required in the CSV. For example, here is the "input" CSV for the OTA 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, , 1M ota_1, app, ota_1, , 1M nvs_key, data, nvs_keys, , 0x1000

Here is an example of a CSV partition table that includes bootloader and partition table partitions:

ESP-IDF Partition Table

Name, Type, SubType, Offset, Size, Flags

bootloader, bootloader, primary, N/A, N/A, partition_table, partition_table, primary, N/A, N/A, nvs, data, nvs, , 0x6000, phy_init, data, phy, , 0x1000, factory, app, factory, , 1M, recoveryBloader, bootloader, recovery, N/A, N/A,

The gen_esp32part.py tool will replace each N/A with appropriate values based on the selected Kconfig options: 0x1000 for the bootloader offset and CONFIG_PARTITION_TABLE_OFFSET for the partition table offset.

Name Field

Name field can be any meaningful name. It is not significant to the ESP32. The maximum length of names is 16 bytes, including one null terminator. Names longer than the maximum length will be truncated.

Type Field

Partition type field can be specified as a name or a number 0-254 (or as hex 0x00-0xFE). Types 0x00-0x3F are reserved for ESP-IDF core functions.

See esp_partition_type_t for the enum definitions for app and data partitions.

If writing in C++ then specifying a application-defined partition type requires casting an integer to esp_partition_type_t in order to use it with the partition API. For example:

static const esp_partition_type_t APP_PARTITION_TYPE_A = (esp_partition_type_t)0x40;

The bootloader ignores any partition types other than app (0x00) and data (0x01).

SubType

The 8-bit SubType field is specific to a given partition type. ESP-IDF currently only specifies the meaning of the subtype field for app and data partition types.

See enum esp_partition_subtype_t for the full list of subtypes defined by ESP-IDF, including the following:

Offset & Size

If you want the partitions in the partition table to work relative to any placement (CONFIG_PARTITION_TABLE_OFFSET) of the table itself, leave the offset field (in CSV file) for all partitions blank. Similarly, if changing the partition table offset then be aware that all blank partition offsets may change to match, and that any fixed offsets may now collide with the partition table (causing an error).

Flags

Two flags are currently supported, encrypted and readonly:

Note

The following type partitions will always be encrypted, regardless of whether this flag is set or not:

Note

Using C file I/O API to open a file (fopen) in any write mode (w, w+, a, a+, r+) will fail and return NULL. Using open with any other flag than O_RDONLY will fail and return -1 while errno global variable will be set to EROFS. This is also true for any other POSIX syscall function performing write or erase operations. Opening a handle in read-write mode for NVS on a read-only partition will fail and return ESP_ERR_NOT_ALLOWED error code. Using a lower level API like esp_partition, spi_flash, etc. to write to a read-only partition will result in ESP_ERR_NOT_ALLOWED error code.

You can specify multiple flags by separating them with a colon. For example, encrypted:readonly.

Generating Binary Partition Table

The partition table which is flashed to the ESP32 is in a binary format, not CSV. The tool partition_table/gen_esp32part.py is used to convert between CSV and binary formats.

If you configure the partition table CSV name in the project configuration (idf.py menuconfig) and then build the project or run idf.py partition-table, this conversion is done as part of the build process.

To convert CSV to Binary manually:

python gen_esp32part.py input_partitions.csv binary_partitions.bin

To convert binary format back to CSV manually:

python gen_esp32part.py binary_partitions.bin input_partitions.csv

To display the contents of a binary partition table on stdout (this is how the summaries displayed when running idf.py partition-table are generated:

python gen_esp32part.py binary_partitions.bin

Partition Size Checks

The ESP-IDF build system will automatically check if generated binaries fit in the available partition space, and will fail with an error if a binary is too large.

Currently these checks are performed for the following binaries:

Note

Although the build process will fail if the size check returns an error, the binary files are still generated and can be flashed (although they may not work if they are too large for the available space.)

MD5 Checksum

The binary format of the partition table contains an MD5 checksum computed based on the partition table. This checksum is used for checking the integrity of the partition table during the boot.

The MD5 checksum generation can be disabled by the --disable-md5sum option of gen_esp32part.py or by the CONFIG_PARTITION_TABLE_MD5 option. This is useful for example when one uses a bootloader from ESP-IDF before v3.1 which cannot process MD5 checksums and the boot fails with the error message invalid magic number 0xebeb.

Flashing the Partition Table

A manual flashing command is also printed as part of idf.py partition-table output.

Note

Note that updating the partition table does not erase data that may have been stored according to the old partition table. You can use idf.py erase-flash (or esptool.py erase_flash) to erase the entire flash contents.

Partition Tool (parttool.py)

The component partition_table provides a tool parttool.py for performing partition-related operations on a target device. The following operations can be performed using the tool:

The tool can either be imported and used from another Python script or invoked from shell script for users wanting to perform operation programmatically. This is facilitated by the tool's Python API and command-line interface, respectively.

Python API

Before anything else, make sure that the parttool module is imported.

import sys import os

idf_path = os.environ["IDF_PATH"] # get value of IDF_PATH from environment parttool_dir = os.path.join(idf_path, "components", "partition_table") # parttool.py lives in $IDF_PATH/components/partition_table

sys.path.append(parttool_dir) # this enables Python to find parttool module from parttool import * # import all names inside parttool module

The starting point for using the tool's Python API to do is create a ParttoolTarget object:

Create a parttool.py target device connected on serial port /dev/ttyUSB1

target = ParttoolTarget("/dev/ttyUSB1")

The created object can now be used to perform operations on the target device:

Erase partition with name 'storage'

target.erase_partition(PartitionName("storage"))

Read partition with type 'data' and subtype 'spiffs' and save to file 'spiffs.bin'

target.read_partition(PartitionType("data", "spiffs"), "spiffs.bin")

Write to partition 'factory' the contents of a file named 'factory.bin'

target.write_partition(PartitionName("factory"), "factory.bin")

Print the size of default boot partition

storage = target.get_partition_info(PARTITION_BOOT_DEFAULT) print(storage.size)

The partition to operate on is specified using PartitionName or PartitionType or PARTITION_BOOT_DEFAULT. As the name implies, these can be used to refer to partitions of a particular name, type-subtype combination, or the default boot partition.

More information on the Python API is available in the docstrings for the tool.

Command-line Interface

The command-line interface of parttool.py has the following structure:

parttool.py [command-args] [subcommand] [subcommand-args]

Erase partition with name 'storage'

parttool.py --port "/dev/ttyUSB1" erase_partition --partition-name=storage

Read partition with type 'data' and subtype 'spiffs' and save to file 'spiffs.bin'

parttool.py --port "/dev/ttyUSB1" read_partition --partition-type=data --partition-subtype=spiffs --output "spiffs.bin"

Write to partition 'factory' the contents of a file named 'factory.bin'

parttool.py --port "/dev/ttyUSB1" write_partition --partition-name=factory --input "factory.bin"

Print the size of default boot partition

parttool.py --port "/dev/ttyUSB1" get_partition_info --partition-boot-default --info size

Note

If the device has already enabled Flash Encryption or Secure Boot, attempting to use commands that modify the flash content, such as erase_partition or write_partition, will result in an error. This error is generated by the erase command of esptool.py, which is called first before writing. This error is done as a safety measure to prevent bricking your device.

A fatal error occurred: Active security features detected, erasing flash is disabled as a safety measure. Use --force to override, please use with caution, otherwise it may brick your device!

To work around this, you need use the --force flag with esptool.py. Specifically, the parttool.py provides the --esptool-erase-args argument that help to pass this flag to esptool.py.

Erase partition with name 'storage'

If Flash Encryption or Secure Boot are enabled then add "--esptool-erase-args=force"

parttool.py --port "/dev/ttyUSB1" --esptool-erase-args=force erase_partition --partition-name=storage

Write to partition 'factory' the contents of a file named 'factory.bin'

If Flash Encryption or Secure Boot are enabled then add "--esptool-erase-args=force"

parttool.py --port "/dev/ttyUSB1" --esptool-erase-args=force write_partition --partition-name=factory --input "factory.bin"

More information can be obtained by specifying --help as argument:

Display possible subcommands and show main command argument descriptions

parttool.py --help

Show descriptions for specific subcommand arguments

parttool.py [subcommand] --help