第七章 ESP32S3 分区表
ESP32的分区表(Partition Table)是管理片上Flash存储空间的核心机制,其作用相当于Flash存储空间的"地图",决定了不同功能模块在Flash中的布局和访问规则。分区表部分的介绍可以参考乐鑫ESP-IDF编程指南中的分区表部分。ESP32 的分区表中,地址范围是系统关键区域的保留空间,包含 Bootloader 和分区表等核心组件。地址描述大小作用注意事项0x0000Boot
分区表,主要是用来对 ESP32 外挂的 SPI FLASH 进行区域划分的一个表格,通过一个表格,可以根据多个不同的功能,将 SPI Flash 划分为不同的区域,方便开发者存储数据。本章,来了解一下 ESP32 分区表。
本章将分为如下几个小节:
1、什么是分区表
2、分区表作用
3、分区表结构
4、分区表类型
5、分区表API函数
1、什么是分区表?
ESP32的分区表(Partition Table)是管理片上Flash存储空间的核心机制,其作用相当于Flash存储空间的"地图",决定了不同功能模块在Flash中的布局和访问规则。
分区表部分的介绍可以参考乐鑫ESP-IDF编程指南中的分区表部分。
2、分区表作用
2.1 物理存储空间划分
- 定义存储布局:将Flash划分为多个逻辑分区(如bootloader、应用程序、数据区等);
- 地址分配:明确每个分区的起始地址(offset)和大小(size),避免空间冲突;
- 示例:
# Name, Type, SubType, Offset, Size
bootloader, 0x00, 0x00, 0x1000, 0x7000 # Bootloader区
nvs, data, nvs, 0x9000, 0x4000 # NVS存储区
app, app, factory,0x10000, 1M # 主应用程序区
2.2 多应用程序管理
支持OTA升级:通过定义多个OTA分区(如ota_0/ota_1)实现:
const esp_partition_t *update_part = esp_ota_get_next_update_partition(NULL);
-
版本回滚:当新版本出现问题时,可切换回旧版本分区;
-
A/B测试:同时部署不同版本固件进行测试。
2.3 数据安全与隔离
- 加密分区:通过
encrypted标志指定需要加密的分区。
nvs, data, nvs, 0x9000, 0x4000, encrypted
-
访问控制:限制不同分区读写权限(如只读工厂分区);
-
关键数据保护:隔离系统数据(NVS)和用户数据(FATFS)。
2.4 系统功能扩展
- 文件系统支持:为SPIFFS/FATFS分配专用存储空间。
storage, data, fat, , 512K
2.5 启动流程控制
-
引导加载程序:Bootloader根据分区表决定加载哪个应用程序;
-
启动验证:通过校验分区MD5确保完整性;
-
故障恢复:定义工厂恢复分区作为保底启动选项。
2.6 资源优化
-
动态调整:根据不同型号ESP32的Flash大小灵活调整分区;
-
空间复用:OTA分区可临时作为数据缓存区使用;
-
内存映射:支持将分区映射到内存直接访问(MMAP)。
esp_partition_mmap(part, 0, size, ESP_PARTITION_MMAP_DATA, &ptr, &handle);
典型应用场景示例:
OTA升级系统:
otadata, data, ota, 0xd000, 0x2000 # 记录OTA状态
ota_0, app, ota_0, 0x10000, 1M # 版本A
ota_1, app, ota_1, 0x110000,1M # 版本B
数据采集设备:
sensor_cfg, data, 0x40, 0x10000, 16K # 传感器配置
log_data, data, 0x41, 0x14000, 64K # 日志存储
注意事项
-
地址对齐:分区起始地址和大小必须4KB对齐
-
空间预留:建议保留≥10%的未分配空间
-
安全设计:关键分区应启用加密和写保护
3、分区表的结构
3.1 分区表地址介绍
ESP32 的分区表中,0x0000 - 0x9000地址范围是系统关键区域的保留空间,包含 Bootloader 和分区表等核心组件。以下是该地址范围的详细说明:
| 地址 | 描述 | 大小 | 作用 | 注意事项 |
|---|---|---|---|---|
| 0x0000 | Bootloader 头部信息 | 4KB | 存储 Bootloader 的元数据,包括 Flash 加密密钥、芯片兼容性标志等。 |
1. 该区域由 ESP-IDF 自动管理,开发者无需手动修改; 2. 若启用 Flash 加密,此区域会被加密,但 Bootloader 会先解密再执行。 |
| 0x1000 | Bootloader 代码区 | 28KB |
存储 Bootloader 的可执行代码,负责: 1. 初始化硬件(CPU 时钟、SPI Flash、串口等); 2. 从 3. 根据分区表加载应用程序或进入 OTA 流程。 |
若自定义 Bootloader 超过 28KB,需调整分区表偏移,但需确保与 ESP-IDF 兼容。 |
| 0x8000 | 分区表(Partition Table)区域 | 4KB |
存储二进制格式的分区表,定义 Flash 的逻辑划分(如应用程序、数据分区的偏移和大小)。 内容: 1. 每个分区条目占 32 字节,包含名称、类型、子类型、偏移、大小和标志; 2. 可通过 |
1. 固定 4KB(即使实际内容不足 4KB 也会占用完整 Sector); 2. 分区表默认由 |
| 0x9000 | 用户分区起始地址 | - | 标记第一个用户自定义分区的开始(如 nvs分区) |
后续分区的偏移地址必须从 0x9000开始,且按 4KB 对齐 |
关键注意事项:
- 禁止手动修改:
0x0000 - 0x9000的内容由系统自动管理,错误写入可能导致设备无法启动(需重新烧录 Bootloader 和分区表); - 地址冲突风险:若扩展 Bootloader 或调整分区表偏移,需确保不与后续分区重叠;
- 加密影响:启用 Flash 加密后,
0x0000 - 0x9000的内容会被加密,但 Bootloader 能自动解密。
典型配置示例:
下面配置示例中,0x9000之后的地址由开发者根据需求灵活分配,但需遵循 4KB 对齐规则:
# 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,
通过下图展示每一部分在FALSH中分布:

3.2 分区表(0x8000 - 0x9000)介绍
地址(0x8000 - 0x9000)保存的是文件partitions.csv的内容,是用户自定义的各分区配置的大小和位置;
ESP32的分区表主要有两种格式,一种是.csv格式,它方便开发人员进行更改和设置各个子
分区的偏移与空间大小,;另一种则是用于烧录设备的.bin 文件格式。在系统编译时,系统会将.csv 文件转化为.bin 文件格式的分区表。下面展示了基础例程的分区表文件的内容。
# 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, 0x1F0000, ,
vfs, data, fat, 0x200000, 0xA00000, ,
storage, data, spiffs, 0xc00000, 0x400000, ,
以上基础例程展示了 ESP32的多个子分区及其功能。其中:
-
nvs:子分区是专为开发者设计的非易失性存储(NVS)设备区域;
-
phy_init :子分区用于存放 PHY 初始化数据,确保每个设备都能单独配置其 PHY;
-
factory:子分区则专门用于存储应用程序区域;
-
vfs:子分区作为虚拟文件系统的存储区域;
-
storage :子分区则是自定义的 SPIFFS 文件系统区域。这些子分区共同构成了 ESP32 的分区结构,满足了不同功能的需求。
字段说明:
每一个子分区都由以下几个部分组成:
-
name:子分区名称。 该字段对 ESP32-S3 并不是特别重要。
-
Type:子分区的存储类型。 设置子分区的存储格式, app (0x00) 和 data (0x01);
-
SubType: 进一步描述或分类分区表的条目。 如果这个子分区 Type 为 app,则 SubType只能设置 factory、 ota_0、 ota_15 和 test;如果这个子分区 Type 为 data,则 SubType 只能设置 ota、 phy、 nvs 和 nvs_keys;
-
Offset:偏移地址。 编译地址必须是 4KB 的倍数;
-
Size:大小。 子分区的大小;
-
Flags:标志位, 一般不设置该字段。
注意:二进制格式的分区表中含有一个 MD5 校验和。这个 MD5 校验和是根据分区表内容计算的,可在设备启动阶段,用于验证分区表的完整性。
3.3 分区表查看方法
3.3.1 执行环境要求
-
硬件连接:ESP32 需通过 USB 与电脑连接(如 CP2102/CH340 串口芯片)。
-
软件依赖:
-
已安装 Python(建议 3.7+)
-
已安装
esptool.py(ESP-IDF 自带或通过pip install esptool安装) -
串口驱动已正确安装(可在设备管理器中确认端口号,如
COM3或/dev/ttyUSB0)
-
3.3.2 执行命令详解
esptool.py --port <PORT> read_flash 0x8000 0x1000 partitions.bin
参数说明:
-
--port <PORT>:替换为 ESP32 的实际串口号(如COM3或/dev/ttyUSB0)。 -
read_flash:读取 Flash 数据的子命令。 -
0x8000:起始地址(分区表固定位置)。 -
0x1000:读取大小(4KB,覆盖整个分区表区域)。 -
partitions.bin:输出的二进制文件名(可自定义)。
3.3.3 操作步骤
Windows 示例(以 COM4为例,具体以自己实验环境分的为准):
-
打开 命令提示符(CMD) 或 PowerShell,进入到安装路径D:\D\SoftWareInstall\Espressif\frameworks\esp-idf-v5.4.2,注意这个路径以自己安装为准,执行脚本export.bat。
- 执行上面脚本后就进入 ESP-IDF 环境:
进入路径及执行脚本:
D:\D\SoftWareInstall\Espressif\frameworks\esp-idf-v5.4.2
export.bat
脚本执行结果:

使用 esptool.py 读取并解析:
esptool.py --port COM4 read_flash 0x8000 0x1000 partitions.bin
执行成功会显示如下:

生成的文件 partitions.bin可用工具解析:
python ./components/partition_table/gen_esp32part.py partitions.bin
输出如下:

4、分区表的类型
分区表(partitions.csv文件结构)的类型具有四种,如下表所示:
| 分区表类型 | 描述 |
|---|---|
| Single factory app no OTA | 小型的应用程序,但没有 OTA 升级区域 |
| Single factory app (large) no OTA | 大型的应用程序,但没有 OTA 升级区域 |
| Factory app two OTA definitions | 大型的应用程序,且具备两个OTA升级区域 |
| Two large size OTA partitions | Flash划分为两个主要用于OTA(空中升级)的分区。常见于支持双分区OTA的场景。 |
| Custom partition table CSV | 自定义分区表 |
4.1 分区表类型配置
具体是在menuconfig中配置:

4.2 分区表5种模式介绍
下面介绍ESP32 分区表配置中5 种模式:
1)Single factory app, no OTA
特点:最简单的分区布局,仅包含一个不可更新的出厂应用,适用于不需要 OTA 升级的稳定设备。
适用场景:量产固件、一次性烧录设备(如工业控制器)。
# Name, Type, SubType, Offset, Size
nvs, data, nvs, 0x9000, 0x4000
phy_init, data, phy, 0xd000, 0x1000
factory, app, factory, 0x10000, 1M # 固定应用分区
关键点:
-
无 OTA 分区,无法远程更新固件
-
所有空间分配给
factory分区(1MB) -
需通过串口重新烧录更新固件、
2)Single factory app (large), no OTA
特点:扩大应用分区占用空间,适合需要更多 Flash 资源的应用。
适用场景:图形界面(LVGL)、音视频处理等大容量固件。
# Name, Type, SubType, Offset, Size
nvs, data, nvs, 0x9000, 0x4000
phy_init, data, phy, 0xd000, 0x1000
factory, app, factory, 0x10000, 2M # 更大的应用分区
关键点:
-
应用分区扩展至 2MB(需 Flash ≥ 4MB)
-
牺牲了未来 OTA 的可能性
3)Factory app, two OTA definitions
特点:标准 OTA 升级方案,保留出厂备份和双 OTA 分区。
适用场景:需要可靠远程更新的设备(如智能家居设备)。
# Name, Type, SubType, Offset, Size
nvs, data, nvs, 0x9000, 0x4000
otadata, data, ota, 0xd000, 0x2000 # OTA 状态存储
phy_init, data, phy, 0xf000, 0x1000
factory, app, factory, 0x10000, 1M # 出厂备份
ota_0, app, ota_0, 0x110000,1M # OTA 分区 A
ota_1, app, ota_1, 0x210000,1M # OTA 分区 B
关键点:
-
otadata分区记录当前激活的 OTA 分区 -
更新流程:
esp_ota_set_boot_partition(ota_1); // 切换至 ota_1
-
保留
factory分区作为恢复手段
4)Two large size OTA partitions
特点:为 OTA 分区分配更大空间,适合资源密集型应用。
适用场景:需要 OTA 且固件较大的场景(如 AI 模型更新)。
# Name, Type, SubType, Offset, Size
nvs, data, nvs, 0x9000, 0x4000
otadata, data, ota, 0xd000, 0x2000
phy_init, data, phy, 0xf000, 0x1000
ota_0, app, ota_0, 0x10000, 2M # 大容量 OTA A
ota_1, app, ota_1, 0x210000,2M # 大容量 OTA B
关键点:
-
每个 OTA 分区 2MB,需 Flash ≥ 4MB
-
删除了
factory分区以腾出空间 -
需确保 OTA 包压缩率(如 LZMA)以适配网络传输
5)Custom partition table CSV
特点:完全自定义分区,支持特殊需求(如多文件系统、加密分区)。
适用场景:复杂存储需求的设备(如数据记录仪)。
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x4000
cfg, data, 0x99, 0xd000, 0x2000, encrypted # 自定义加密配置区
audio, data, fat, 0xf000, 0x50000 # SPIFFS 文件系统
main_app, app, factory, 0x5f000, 1M
ota_0, app, ota_0, , 1M # 自动计算偏移
关键点:
-
自定义
SubType(如0x99)需在代码中通过esp_partition_find_first访问 -
encrypted标志需启用 Flash 加密 -
未指定
Offset的分区会自动接续前一分区
如何选择分区方案?
|
方案 |
Flash 需求 |
OTA 支持 |
适用阶段 |
|---|---|---|---|
|
Single factory |
≥ 2MB |
❌ |
量产稳定固件 |
|
Large factory |
≥ 4MB |
❌ |
资源密集型固件 |
|
Two OTA |
≥ 4MB |
✅ |
常规产品 |
|
Large OTA |
≥ 8MB |
✅ |
大固件 OTA |
|
Custom CSV |
按需分配 |
可选 |
特殊存储需求 |
注意:所有方案均需保证分区 不重叠 且 4KB 对齐。实际开发中建议优先测试 OTA 流程的可靠性。
5、分区表 API 函数
esp_partition 组件是 ESP-IDF 中用于管理 ESP32 及其系列芯片上 flash 分区的一个关键组件。它提供了一组高层次的 API 函数,允许开发者方便地访问和操作定义在分区表中的各个分区。这些高层次的 API 函数为开发者提供了简洁和易用的接口,以进行诸如读取、写入、擦除分区内容等操作。 这些函数可在 components/esp_partition/include/esp_partition.h 路径下找到这些分区表 API 函数。
- esp_partition_find 函数
该函数查找子分区,该函数原型如下所示:
const esp_partition_t *esp_partition_find_first(esp_partition_type_t type,
esp_partition_subtype_t subtype,
const char *label)
该函数的形参描述如下表所示:
| 参数 | 子分区类型 | 描述 |
|---|---|---|
| type | ESP_PARTITION_TYPE_APP | 应用程序分区类型 |
| ESP_PARTITION_TYPE_DATA | 数据分区类型 | |
| ESP_PARTITION_TYPE_ANY | 搜索随意类型分区 | |
| subtype | 子类型(请看 esp_partition_subtype_t 结构体) | |
| label | 子分区名称 | |
该函数返回值如下:
NULL:未找到子分区。 esp_partition_t 指针:返回子分区。
- esp_partition_read 函数
该函数用于读取子分区的某个地址的数据,该函数原型如下所示:
esp_err_t esp_partition_read( const esp_partition_t* partition,
size_t src_offset, void* dst, size_t size)
该函数的形参描述如下表所示:
| 参数 | 描述 |
|---|---|
| partition | 分区结构指针 |
| src_offset | 读取数据的地址 |
| dst | 存储数据的指针 |
| size | 读取数据大小 |
该函数返回值如下:
ESP_OK: 读取成功。其他: 失败。
- esp_partition_write 函数
该函数用于写入子分区的某个地址的数据,该函数原型如下所示:
esp_err_t esp_partition_write( const esp_partition_t* partition,
size_t dst_offset,
void* src, size_t size)
该函数的形参描述如下表所示:
| 参数 | 描述 |
|---|---|
| partition | 分区结构指针 |
| dst_offset | 写入数据的地址 |
| src | 写入数据 |
| size | 写入数据大小 |
该函数返回值如下:
ESP_OK:读取成功。其他:失败。
- esp_partition_range 函数
该函数用于擦除子分区的某个地址的数据,该函数原型如下所示:
esp_err_t esp_partition_erase_range(const esp_partition_t *partition,
size_t offset, size_t size)
该函数的形参描述如下表所示:
| 参数 | 描述 |
|---|---|
| partition | 分区结构指针 |
| offset | 擦除数据的地址 |
| size | 擦除数据大小 |
该函数返回值如下:
ESP_OK:读取成功。其他:失败。
上述列举的函数是访问和操作分区表时较为常用的 API 函数。若需进一步了解或学习其他剩余的分区表 API 函数,可查阅 esp_partition.h 头文件。
更多推荐



所有评论(0)