ESP32 各型号远程 OTA 分区表建议与实战说明

1. OTA 分区表核心概念

ESP32 系列做远程 OTA,核心不是看“ESP32、ESP32-S3、ESP32-C3”这些名字,而是看 Flash 容量、固件大小、是否需要文件系统、是否需要回滚保护

ESP-IDF 的分区表默认烧录在 Flash 的 0x8000 地址,占用一个完整 4KB 扇区;普通 App 默认从 0x10000 开始。分区表每一项包含 Name、Type、SubType、Offset、Size、Flags 等字段。([Espressif Systems][1])

OTA 项目通常至少需要:

otadata, data, ota
ota_0,   app,  ota_0
ota_1,   app,  ota_1

其中 otadata 用来记录当前应该启动哪个 OTA 分区;ota_0ota_1 是两个 App 槽位,设备运行其中一个分区时,可以把新固件写入另一个分区。ESP-IDF/Arduino-ESP32 文档都说明,基础 OTA 一般需要两个 OTA App 分区和一个 OTA data 分区。([Espressif Systems][1])


2. 各型号 OTA 分区表推荐

说明:同一套分区表格式适用于 ESP32、ESP32-S2、ESP32-S3、ESP32-C3、ESP32-C6、ESP32-H2 等 ESP-IDF 支持的芯片。真正影响分区表的是 Flash 大小。

芯片型号 常见 Flash 推荐 OTA 分区方案 建议
ESP32 / ESP32-WROOM / ESP32-WROVER 4MB / 8MB / 16MB 4MB 基础 OTA 或 8MB 平衡 OTA 普通 WiFi 设备 4MB 可用;带 HTTPS、Web 配置页、日志建议 8MB
ESP32-S2 4MB / 8MB / 16MB 4MB 或 8MB OTA 只有 WiFi,无蓝牙;USB 相关项目建议 8MB 起
ESP32-S3 8MB / 16MB 常见 8MB 或 16MB OTA 摄像头、语音、LVGL、AI、Web 资源建议 16MB
ESP32-C2 2MB / 4MB 2MB 勉强 OTA,推荐 4MB 2MB 只能做极简 OTA,不建议放复杂 HTTPS 固件
ESP32-C3 4MB / 8MB 4MB 基础 OTA 小型 IoT、传感器、开关类设备很适合
ESP32-C5 8MB 常见 8MB OTA 新项目建议 ESP-IDF;多协议功能建议预留更大 App 分区
ESP32-C6 4MB / 8MB / 16MB 8MB 或 16MB OTA WiFi 6、BLE、Thread、Zigbee 项目建议 8MB 起;乐鑫模块页列出 C6 WROOM 有 4/8/16MB 规格。([Espressif Systems][2])
ESP32-H2 4MB / 8MB 4MB 或 8MB OTA H2 主要是 BLE/Thread/Zigbee,不自带 WiFi,远程 OTA 通常依赖网关
ESP32-P4 16MB / 32MB 常见外部 Flash 16MB 或 32MB OTA P4 偏 HMI、视觉、边缘计算,建议大 Flash

3. 分区表选择原则

3.1 远程 OTA 最少要两个 App 分区

OTA 的基本逻辑是:

当前运行 ota_0
下载新固件到 ota_1
校验成功
修改 otadata
重启进入 ota_1
下一次更新再写回 ota_0

所以远程 OTA 不建议只有一个 App 分区。一个 App 分区只能串口升级,或者做非常复杂的临时下载方案,不适合普通远程 OTA。


3.2 建议去掉 factory 分区

ESP-IDF 默认 OTA 表经常是:

factory
ota_0
ota_1

但是 factory 分区不会被 OTA 更新。官方文档也说明,如果想节省 Flash,可以去掉 factory 分区,直接使用 ota_0 作为默认应用分区。

推荐新项目使用:

ota_0
ota_1

而不是:

factory
ota_0
ota_1

原因是 4MB Flash 很紧张,去掉 factory 可以让两个 OTA 分区更大。


3.3 App 分区必须够大

判断方法:

单个 OTA 分区大小 > 当前 firmware.bin 大小 + 未来增长空间

例如:

当前固件 1.1MB
建议单个 OTA 分区至少 1.5MB
更推荐 2MB 以上

如果你的固件包含:

HTTPS OTA
蓝牙
WiFi 配网
WebServer
LVGL
摄像头
音频
证书
字体
图片资源

就不要用太小的 1MB App 分区。


4. 推荐分区表一:2MB Flash 极限 OTA

适合:

ESP32-C2 2MB
极简传感器
无复杂 Web
无大资源
固件小于 900KB

不推荐:

HTTPS 很复杂
BLE + WiFi + 大量库
WebServer
文件系统
LVGL
摄像头

文件名建议:

partitions_ota_2mb.csv
# ESP-IDF Partition Table
# 适用场景:2MB Flash 极限 OTA
# 注意:2MB 做 OTA 非常紧张,只适合极简固件
# Name,     Type, SubType, Offset,   Size,     Flags

# NVS:保存 WiFi、参数、设备配置
nvs,        data, nvs,     0x9000,   0x3000,

# OTA 选择信息:固定 8KB
otadata,    data, ota,     0xC000,   0x2000,

# PHY 校准数据:一般保留 4KB
phy_init,   data, phy,     0xE000,   0x1000,

# 第一个 OTA App 分区:960KB
ota_0,      app,  ota_0,   0x10000,  0xF0000,

# 第二个 OTA App 分区:960KB
ota_1,      app,  ota_1,   0x100000, 0xF0000,

# 崩溃转储,可选;如果固件太大,可以删除
coredump,   data, coredump,0x1F0000, 0x10000,

5. 推荐分区表二:4MB Flash 基础 OTA

适合:

ESP32-WROOM-32 4MB
ESP32-C3 4MB
ESP32-S2 4MB
ESP32-C6 4MB
普通 WiFi 远程升级项目

特点:

两个 App 分区接近 1.8MB
适合普通 OTA
不放 SPIFFS / LittleFS

文件名建议:

partitions_ota_4mb_basic.csv
# ESP-IDF Partition Table
# 适用场景:4MB Flash,最大化 App 空间
# Name,     Type, SubType, Offset,   Size,     Flags

# NVS:保存 WiFi、设备配置、Token 等
nvs,        data, nvs,     0x9000,   0x5000,

# OTA 选择信息:必须有,固定 8KB
otadata,    data, ota,     0xE000,   0x2000,

# 第一个 OTA App 分区,约 1.8125MB
ota_0,      app,  ota_0,   0x10000,  0x1D0000,

# 第二个 OTA App 分区,约 1.8125MB
ota_1,      app,  ota_1,   0x1E0000, 0x1D0000,

# 崩溃转储:用于保存 panic 信息,调试阶段建议保留
coredump,   data, coredump,0x3B0000, 0x10000,

# 预留参数区:可以保存设备 SN、出厂参数、校准数据
factory_param,data,nvs,    0x3C0000, 0x40000,

如果你的固件超过 1.8MB,这个方案就不够了,建议换 8MB Flash。


6. 推荐分区表三:4MB Flash 带文件系统 OTA

适合:

需要少量网页资源
需要存日志
需要 LittleFS / SPIFFS
固件控制在 1.5MB 以内

文件名建议:

partitions_ota_4mb_storage.csv
# ESP-IDF Partition Table
# 适用场景:4MB Flash,同时需要 OTA 和文件系统
# 缺点:App 分区比 basic 方案小
# Name,     Type, SubType, Offset,   Size,     Flags

nvs,        data, nvs,     0x9000,   0x5000,
otadata,    data, ota,     0xE000,   0x2000,

# 每个 App 分区 1.5MB
ota_0,      app,  ota_0,   0x10000,  0x180000,
ota_1,      app,  ota_1,   0x190000, 0x180000,

# 文件系统区,约 896KB
spiffs,     data, spiffs,  0x310000, 0xE0000,

# 崩溃转储,64KB
coredump,   data, coredump,0x3F0000, 0x10000,

如果是 ESP-IDF 新项目,也可以把 spiffs 改成 fat,具体看你用 SPIFFS、LittleFS 还是 FATFS。


7. 推荐分区表四:8MB Flash 平衡 OTA

适合:

ESP32-S3 8MB
ESP32-C6 8MB
ESP32-C5 8MB
ESP32-WROVER 8MB
需要 HTTPS OTA
需要 Web 配置页
需要日志、图片、证书、资源文件

Arduino-ESP32 官方示例中也给出了 8MB OTA + Storage 的常见布局,例如两个约 2MB App 分区加文件系统。([Espressif Systems][3])

这里给一个更偏向 ESP-IDF 项目的 8MB 平衡方案:

文件名建议:

partitions_ota_8mb.csv
# ESP-IDF Partition Table
# 适用场景:8MB Flash,推荐大多数正式 OTA 项目使用
# Name,     Type, SubType, Offset,   Size,     Flags

# NVS:32KB,用于 WiFi、配置、Token
nvs,        data, nvs,     0x9000,   0x5000,

# OTA 选择信息:8KB
otadata,    data, ota,     0xE000,   0x2000,

# App0:3.1875MB
ota_0,      app,  ota_0,   0x10000,  0x330000,

# App1:3.1875MB
ota_1,      app,  ota_1,   0x340000, 0x330000,

# 文件系统:约 1.5625MB
spiffs,     data, spiffs,  0x670000, 0x180000,

# 崩溃转储:64KB
coredump,   data, coredump,0x7F0000, 0x10000,

这个方案比较适合:

WiFi + MQTT
HTTPS OTA
BLE 配网
WebServer
传感器数据缓存
小型 UI 资源

8. 推荐分区表五:16MB Flash 大型 OTA

适合:

ESP32-S3-N16R8
ESP32-S3 摄像头项目
LVGL 项目
大字体
图片资源
离线网页
音频提示
复杂 Web 面板

文件名建议:

partitions_ota_16mb.csv
# ESP-IDF Partition Table
# 适用场景:16MB Flash,大型 OTA 项目
# Name,     Type, SubType, Offset,   Size,     Flags

# NVS:64KB
nvs,        data, nvs,     0x9000,   0x7000,

# OTA 选择信息:8KB
otadata,    data, ota,     0x10000,  0x2000,

# 为了 App 分区 64KB 对齐,这里预留一小段
reserved,   data, 0x40,    0x12000,  0xE000,

# App0:6MB
ota_0,      app,  ota_0,   0x20000,  0x600000,

# App1:6MB
ota_1,      app,  ota_1,   0x620000, 0x600000,

# 文件系统:约 3.75MB
spiffs,     data, spiffs,  0xC20000, 0x3D0000,

# 崩溃转储:64KB
coredump,   data, coredump,0xFF0000, 0x10000,

注意:如果你不想手动计算偏移,也可以把 App 之后的 Offset 留空,让工具自动对齐。ESP-IDF 文档说明,CSV 中 Offset 留空时,gen_esp32part.py 会根据前一个分区和对齐要求自动计算;App 分区偏移需要 64KB 对齐。


9. 推荐分区表六:16MB 自动偏移写法

这种写法更安全,不容易算错地址。

# ESP-IDF Partition Table
# 自动偏移版本:推荐给不想手算地址的项目
# 注意:第一个分区建议保留 0x9000
# Name,     Type, SubType, Offset,   Size,     Flags

nvs,        data, nvs,     0x9000,   0x7000,
otadata,    data, ota,     ,         0x2000,
phy_init,   data, phy,     ,         0x1000,

# App 分区 Offset 留空,工具会自动 64KB 对齐
ota_0,      app,  ota_0,   ,         6M,
ota_1,      app,  ota_1,   ,         6M,

# 文件系统区
spiffs,     data, spiffs,  ,         0x3C0000,

# 崩溃转储
coredump,   data, coredump,,         0x10000,

10. 为什么不建议 1MB + 1MB OTA?

ESP-IDF 默认示例中常见:

factory, 1M
ota_0,   1M
ota_1,   1M

这个表适合早期简单项目,但现在很多项目很容易超过 1MB,例如:

WiFi
BLE
HTTPS
MQTT
JSON
证书
NVS
WebServer
日志
OTA 回滚

如果固件超过分区大小,编译时会报类似:

app partition is too small

或者烧录后无法正常启动。

所以实际项目建议:

4MB Flash:每个 OTA App 至少 1.5MB
8MB Flash:每个 OTA App 建议 2MB ~ 3.2MB
16MB Flash:每个 OTA App 建议 4MB ~ 6MB

11. ESP-IDF 具体怎么配置 OTA 分区表

11.1 创建 CSV 文件

在项目根目录创建:

partitions_ota.csv

例如:

your_project/
├── CMakeLists.txt
├── main/
│   └── main.c
├── partitions_ota.csv
└── sdkconfig

11.2 menuconfig 配置

执行:

idf.py menuconfig

进入:

Partition Table

选择:

Custom partition table CSV

然后填写:

partitions_ota.csv

再进入:

Serial flasher config

确认 Flash 大小:

4MB / 8MB / 16MB

Flash 大小必须和你的开发板真实 Flash 一致,否则会出现分区超出 Flash 的问题。


11.3 查看分区表

执行:

idf.py partition-table

它会输出最终生成的分区布局。

ESP-IDF 构建系统会检查 App 是否能放入可用 App 分区,如果固件太大,会在构建阶段报错或警告。([Espressif Systems][1])


11.4 第一次烧录

如果你改过分区表,建议先擦除整片 Flash:

idf.py -p COM3 erase-flash

然后烧录:

idf.py -p COM3 flash monitor

Linux / macOS 示例:

idf.py -p /dev/ttyUSB0 erase-flash
idf.py -p /dev/ttyUSB0 flash monitor

12. ESP-IDF 远程 HTTPS OTA 代码框架

12.1 CMakeLists.txt 加依赖

idf_component_register(
    SRCS "main.c"
    INCLUDE_DIRS "."
    REQUIRES esp_https_ota esp_http_client app_update
)

12.2 简化 OTA 代码

#include "esp_https_ota.h"
#include "esp_log.h"
#include "esp_system.h"

#define OTA_URL "https://your-server.com/firmware.bin"

static const char *TAG = "OTA";

extern const char server_cert_pem_start[] asm("_binary_server_cert_pem_start");

void start_https_ota(void)
{
    esp_http_client_config_t http_config = {
        .url = OTA_URL,
        .cert_pem = server_cert_pem_start,
    };

    esp_https_ota_config_t ota_config = {
        .http_config = &http_config,
    };

    ESP_LOGI(TAG, "Starting OTA from: %s", OTA_URL);

    esp_err_t ret = esp_https_ota(&ota_config);

    if (ret == ESP_OK) {
        ESP_LOGI(TAG, "OTA success, restarting...");
        esp_restart();
    } else {
        ESP_LOGE(TAG, "OTA failed: %s", esp_err_to_name(ret));
    }
}

esp_https_ota() 会建立 HTTPS 连接、读取固件、写入 OTA 分区并完成 OTA 流程;成功后需要调用 esp_restart() 重启进入新固件。


13. OTA 回滚建议

正式产品建议开启:

CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE

开启后,新固件第一次启动时需要主动确认自己可用:

#include "esp_ota_ops.h"

void app_confirm_if_pending(void)
{
    const esp_partition_t *running = esp_ota_get_running_partition();
    esp_ota_img_states_t ota_state;

    if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK) {
        if (ota_state == ESP_OTA_IMG_PENDING_VERIFY) {
            // 这里可以检查 WiFi、传感器、配置、任务是否正常
            bool ok = true;

            if (ok) {
                esp_ota_mark_app_valid_cancel_rollback();
            } else {
                esp_ota_mark_app_invalid_rollback_and_reboot();
            }
        }
    }
}

ESP-IDF 的回滚机制会在新 App 第一次启动后等待确认;如果没有确认且发生重启,Bootloader 会把它标记为失败并回滚到上一个可用 OTA 分区。

建议在 app_main() 前期调用:

void app_main(void)
{
    app_confirm_if_pending();

    // 后续初始化 WiFi、MQTT、业务逻辑
}

14. Arduino / PlatformIO 怎么用自定义 OTA 分区表

14.1 Arduino IDE

.ino 同级目录放:

partitions.csv

Arduino-ESP32 文档说明,可以在草图同目录创建 partitions.csv,构建系统会使用这个自定义分区表。

示例目录:

MyOtaProject/
├── MyOtaProject.ino
└── partitions.csv

4MB OTA 示例:

# Name,   Type, SubType, Offset,  Size,     Flags
nvs,      data, nvs,     0x9000,  0x5000,
otadata,  data, ota,     0xE000,  0x2000,
app0,     app,  ota_0,   0x10000, 0x1D0000,
app1,     app,  ota_1,   0x1E0000,0x1D0000,
spiffs,   data, spiffs,  0x3B0000,0x50000,

14.2 PlatformIO

在项目根目录放:

partitions_ota.csv

然后修改:

[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino

board_build.partitions = partitions_ota.csv
board_upload.flash_size = 4MB

ESP32-S3 示例:

[env:esp32-s3-devkitc-1]
platform = espressif32
board = esp32-s3-devkitc-1
framework = arduino

board_build.partitions = partitions_ota_8mb.csv
board_upload.flash_size = 8MB

15. 分区表注释写法建议

CSV 文件中推荐这样写注释:

# 这是注释
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,

不建议这样写:

nvs, data, nvs, 0x9000, 0x5000,  # 保存 WiFi

原因是不同构建环境对行尾中文注释兼容性不一定一致。最稳妥的方式是:

# NVS:保存 WiFi、Token、设备参数
nvs, data, nvs, 0x9000, 0x5000,

16. 常见错误和解决办法

16.1 固件太大

错误现象:

app partition is too small

解决:

1. 换 8MB 或 16MB Flash
2. 增大 ota_0 / ota_1
3. 删除 factory 分区
4. 减少 SPIFFS / LittleFS 空间
5. 关闭不必要组件

16.2 OTA 成功但重启后还是旧版本

可能原因:

1. 没有 otadata 分区
2. OTA 写入后没有设置 boot partition
3. 没有 esp_restart()
4. 分区表不是 OTA 分区表
5. 实际运行的是 factory 分区

如果用 esp_https_ota(),成功后它会处理切换逻辑,但仍然需要你调用:

esp_restart();

16.3 改了分区表后运行异常

解决:

idf.py erase-flash
idf.py flash monitor

原因是旧分区数据还残留在 Flash 里。ESP-IDF 文档也提醒,更新分区表不会自动擦除旧数据,必要时要整片擦除。


16.4 4MB Flash 放不下 HTTPS OTA

HTTPS OTA 需要 TLS、证书、HTTP Client、OTA 组件,固件会明显变大。

建议:

ESP32-C3 / ESP32 普通项目:4MB 勉强够
ESP32-S3 / C6 / 复杂项目:建议 8MB 起
带 UI / 摄像头 / Web 资源:建议 16MB

16.5 开启 Flash Encryption 后 OTA 失败

注意事项:

1. app 分区会被自动加密
2. otadata 也会被加密
3. OTA 写入必须走 ESP-IDF OTA API
4. 不要自己乱写 Flash 偏移

ESP-IDF 文档说明,开启 Flash Encryption 后,Bootloader、分区表、otadata、所有 app 分区等会默认加密。


17. 我的实际推荐

17.1 新手 / 普通项目

ESP32 / ESP32-C3 / ESP32-S2
Flash:4MB
分区表:4MB basic OTA

推荐:

partitions_ota_4mb_basic.csv

17.2 正式联网产品

ESP32 / ESP32-S3 / ESP32-C3 / ESP32-C6
Flash:8MB
分区表:8MB balanced OTA

推荐:

partitions_ota_8mb.csv

17.3 摄像头 / 屏幕 / LVGL / 复杂项目

ESP32-S3
Flash:16MB
PSRAM:8MB
分区表:16MB large OTA

推荐:

partitions_ota_16mb.csv

17.4 ESP32-H2 / Zigbee / Thread 设备

ESP32-H2
Flash:4MB 或 8MB
OTA 方式:通常通过网关或 BLE / Thread 传输
分区表:4MB basic OTA 或 8MB OTA

注意:ESP32-H2 不适合直接做 WiFi HTTPS OTA,因为它本身不是 WiFi 芯片。


18. 最终建议总结

如果你不知道怎么选,直接按下面来:

2MB Flash:不建议 OTA,除非极简固件
4MB Flash:可以 OTA,但不要放太多资源
8MB Flash:最推荐,正式项目够用
16MB Flash:ESP32-S3 / UI / 摄像头 / 大资源项目首选

最推荐的通用方案:

ESP32-C3 / ESP32:4MB basic OTA
ESP32-S3 / ESP32-C6:8MB OTA 起步
ESP32-S3 + 屏幕 / 摄像头:16MB OTA

不要盲目使用默认:

factory + ota_0 + ota_1

更推荐:

ota_0 + ota_1

这样 OTA 分区更大,后期不容易因为固件变大而爆分区。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐