ESP32 分区表详解:SPI Flash 配置、初始化与挂载教程

100次阅读
没有评论


  本文围绕 ESP32-S3 展开,讲解其 SPI Flash 分区表设置、与 Flash 的连接,还介绍分区表配置、各分区初始化挂载。

ESP32 分区表详解:SPI Flash 配置、初始化与挂载教程

01 简介

1.ESP32-S3 的 分区表(Partition Table)

  是一种用于划分 SPI Flash 存储空间的配置机制。它的作用类似于电脑硬盘的分区,把 Flash 划分为多个区域,每个区域用于存储不同类型的数据或程序,比如:

  • 应用程序(如 factory、ota_0、ota_1);
  • 系统数据(如 NVS、PHY 初始化数据);
  • 文件系统(如 SPIFFS、FATFS)。

2. ESP32-S3 与 SPI Flash 的连接方式

ESP32-S3 通过 SPI/QSPI/OPI 接口 与外部 SPI Flash 通信,典型连接方案如下:

SPI Flash 信号 ESP32-S3 管脚名称 管脚编号(QFN56)  备注
SCK / CLK    SPICLK            33   时钟线     
MOSI / SI  SPID               35   数据输入    
MISO / SO   SPIQ              34   数据输出    
CS#        SPICS0              32   片选      
WP#         SPIWP           31   写保护     
HOLD# / IO3 SPIHD               30   暂停 /IO3 

SPI Flash 为外部独立芯片,需通过 PCB 与 ESP32-S3 连接。ESP32-S3 芯片本身不集成 Flash,因此所有程序和数据均存储于外接的 SPI Flash 中。部分模组(如ESP32-S3-WROOM-1)虽将 Flash 与 SoC 集成在同一块 PCB 上,但本质上仍为外部组件。

ESP32 分区表详解:SPI Flash 配置、初始化与挂载教程

3. 通信协议与模式

  • 基础 SPI 模式:使用 4 线(CLK、CS、MOSI、MISO),支持标准 SPI 协议;
  • QSPI 模式 :通过 4 线同时传输地址和数据,带宽提升至 4 倍,需 Flash 芯片支持(如qioqout模式);
  • OPI 模式(Octal SPI):8 线并行传输,适用于高性能需求,但需专用 Flash 型号。

4.ESP32-S3 兼容主流厂商的 SPI Flash,以下为典型型号:

1. 华邦电子(Winbond)

  • W25Q64JV:8MB,支持 QSPI,电压 3.3V,封装 SOIC-8;
  • W25Q128JV:16MB,最高时钟频率 133MHz,适用于大容量存储需求。

2.兆易创新(GigaDevice)

  • GD25Q32C:4MB,低功耗设计(<1mW),支持 XIP(片上执行);
  • GD25Q128C:16MB,工作电压 1.7V~3.6V,兼容宽电压系统。

3. 美光(Micron)

  • MT25QL128:16MB,采用 Octal SPI 接口,适合高速数据吞吐场景。

02 如何设置分区表

分区表是一个存储在 Flash 固定位置(默认 0x8000)的二进制数据结构,记录了各分区的起始地址、大小、类型、子类型等信息。ESP32-S3 启动时,Bootloader 会先读取分区表,再根据表中信息加载对应分区的程序(如 app 分区)或访问数据(如 NVS 分区)。

分区名        谁来负责初始化   典型触发代码/ 位置  备注                     
 nvs            nvs_flash_init()   用户代码 `app_main()    必须手动调用           
 phy\_init    Wi-Fi/BT 协议栈内部        esp_wifi_init() 或 esp_bt_controller_init()    协议栈自动读取校准数据         
factory        ROM 引导程序 + CMake 链接        上电 ROM 直接映射到地址 0x10000           无需应用层初始化  
 vfs(FAT)      esp_vfs_fat_spiflash_mount()` 或 esp_vfs_fat_register()    用户代码              示例:fatfs_spiflash/main.c 
storage (SPIFFS)   esp_spiffs_mount()` 或 esp_vfs_spiffs_register()`          用户代码     示例:spiffsgen/main.c     

具体流程(以 ESP-IDF 框架为例)。

1.分区表的格式

# 名称, 类型, 子类型, 起始偏移量, 大小, 标志(可选)nvs,      data, nvs,     ,        0x40000,  # 4MB NVS 分区(存储配置)phy_init, data, phy,     ,        0x1000,   # 射频校准数据分区
factory,  app,  factory, ,        0x100000, # 1MB factory app 分区(默认程序)ota_0,    app,  ota_0,   ,        0x100000, # 1MB OTA 分区 0
ota_1,    app,  ota_1,   ,        0x100000, # 1MB OTA 分区 1
vfs,      data, fat,     ,        0x200000, # 2MB 文件系统分区

类型(Type):app(应用程序)或 data(数据);

子类型(SubType):app 类型下有 factory(默认程序)、ota_0~ota_15(OTA 分区);data 类型下有 nvs、phy(射频数据)、fat(文件系统)等;

偏移量(Offset):可省略(自动按顺序分配),但需确保不重叠;

大小:支持 KB(如 64KB)、MB(如 2MB)或十六进制(如 0x10000)。

2.手动创建分区表

创建步骤:

1)创建分区表文件:在项目根目录下新建 partitions.csv,按上述格式填写分区信息。

2)指定分区表路径:

  • 在项目的 CMakeLists.txt 中添加:
set(PARTITION_TABLE_CSV partitions.csv)  # 指向自定义分区表文件
  • 或通过 ESP-IDF 配置工具(menuconfig)设置:

3)进入 Partition Table → Partition Table (Custom partition table CSV) → 输入自定义 CSV 文件路径(如 partitions.csv)。

3.VSCode ESP-IDF 工程自动创建分区表

大多数情况下,使用 VSCode ESP-IDF 自动创建的分区表。VSCode ESP-IDF 工程会使用框架自带的默认分区表(default_partitions.csv),适用于大多数基础场景(包含 factory app、nvs、phy_init 等必要分区)。

若使用默认分区表:无需额外操作,正常编译(Build)和烧录(Flash)即可,VSCode 会自动处理分区表的生成和烧录。

4. 需要修改分区表的场景

1)需要支持 OTA 升级

默认分区表不含 OTA 分区,若需实现无线升级功能,必须添加至少两个 OTA 分区(如 ota_0 和 ota_1),示例:

csvota_0, app, ota_0, , 1M,ota_1, app, ota_1, , 1M,

2)默认分区大小不足

若 NVS 分区(默认 5KB)存储不下设备配置(如多个 WiFi 密码、传感器校准数据),需扩大其容量(如 0x40000 即 256KB);

若使用 FAT 文件系统存储大量日志或文件,需新增或扩大 fat 类型分区(如 2M)。

3)自定义数据分区需求

需独立存储特定数据(如固件备份、加密密钥)时,可新增自定义数据分区,例如:

csvfirmware_backup, data, 0x80, , 512KB,  # 子类型 0x80 为自定义

4)Flash 容量超过默认分区表支持范围

默认分区表适用于 4MB 及以下 Flash,若使用 8MB/16MB Flash 且需充分利用空间,需重新规划分区大小(如扩大 app 分区至 4MB)。

5)多应用程序切换

需在设备中运行多个独立应用(如主程序 + 调试程序)时,需为每个应用分配独立的 app 分区。

03 各分区的“初始化 / 挂载

1.nvs

只要打算使用 NVS(非易失性存储)保存 / 读取键值数据,就必须在初始化阶段调用 nvs_flash_init()。没有它,任何 nvs_open、nvs_set_*、nvs_get_* 都会直接返回 ESP_ERR_NVS_NOT_INITIALIZED。

esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES ||
    ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {                
    ESP_ERROR_CHECK(nvs_flash_erase());    
    ESP_ERROR_CHECK(nvs_flash_init());
}

2.phy_init(Wi-Fi/BT 协议栈内部,开发者只需启动协议栈)

/* Wi-Fi 例:协议栈会自动读取 0xF000 处的校准数据 */
esp_netif_init();
esp_event_loop_create_default();
esp_netif_create_default_wifi_sta();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));   // 内部会加载 phy_init

3. factory(ROM 引导加载器直接运行,应用层无需代码)

4. vfs (FAT) —— 把 0x200000 起的 10 MB 分区挂载为 /vfs

#include "esp_vfs_fat.h"
#include "wear_levelling.h"
#define FAT_PARTITION_LABEL    "vfs"
wl_handle_t wl_handle;
void mount_fat(void){
    esp_vfs_fat_mount_config_t mount_config = {
        .max_files              = 8,
        .format_if_mount_failed = true,
        .allocation_unit_size   = 512
    };
    ESP_ERROR_CHECK(esp_vfs_fat_spiflash_mount_rw_wl(    "/vfs", FAT_PARTITION_LABEL, &mount_config, &wl_handle));
}

5. storage (SPIFFS) —— 把 0xC00000 起的 4 MB 分区挂载为 /spiffs

#include "esp_spiffs.h"
#define SPIFFS_PARTITION_LABEL "storage"
void mount_spiffs(void){
    esp_vfs_spiffs_conf_t conf = {
        .base_path        = "/spiffs",
        .partition_label  = SPIFFS_PARTITION_LABEL,
        .max_files        = 5,
        .format_if_mount_failed = true
    };
    ESP_ERROR_CHECK(esp_vfs_spiffs_register(&conf));
}

6. app_main() 模板

void app_main(void){
    /* 1. NVS 初始化 */
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES ||
        ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {        ESP_ERROR_CHECK(nvs_flash_erase());
        ESP_ERROR_CHECK(nvs_flash_init());
    }
    /* 2. Wi-Fi/BT → 自动使用 phy_init 分区 */
    esp_netif_init();
    esp_event_loop_create_default();
    esp_netif_create_default_wifi_sta();
    wifi_init_config_t wifi_cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&wifi_cfg));
    /* 3. 挂载 FAT 文件系统 */
    mount_fat();
    /* 4. 挂载 SPIFFS 文件系统 */
    mount_spiffs();
    /* 5. 主循环或其它业务逻辑 */
    for (;;) {        vTaskDelay(pdMS_TO_TICKS(1000));
    }}
正文完
 0
Pa2sw0rd
版权声明:本站原创文章,由 Pa2sw0rd 于2025-09-05发表,共计5128字。
转载说明:Unless otherwise specified, all articles are published by cc-4.0 protocol. Please indicate the source of reprint.
评论(没有评论)