You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ESP32映射Flash内存后写入触发重启问题求助

问题描述

我通过partitions.csv创建了Flash分区:

# Name,   Type, SubType, Offset,  Size, Flags
nvs,      data, nvs,     36K,     20K,
factory,  app,  factory, 64K,     2M,
storage,   data, spiffs,  ,        5M,

随后通过以下代码加载该分区:

Serial.println("Acquire partition");
const esp_partition_t *partition = esp_partition_find_first(
  ESP_PARTITION_TYPE_DATA,     // Type of partition
  ESP_PARTITION_SUBTYPE_ANY,   // Subtype
  "storage"                    // Label of the partition
);

if (partition == NULL) {
  Serial.println("Partition not found");
  return false;
}

Serial.println("Map partition");
const void *mapped_memory;
spi_flash_mmap_handle_t mmap_handle;
esp_err_t err = esp_partition_mmap(
  partition,
  0,                  // Offset within the partition
  partition->size,    // Size of the mapping
  ESP_PARTITION_MMAP_DATA,
  &mapped_memory,     // Pointer to mapped memory
  &mmap_handle        // Handle to unmap later
);

if (err != ESP_OK) {
  Serial.printf("Failed to mmap flash memory: %s\n", esp_err_to_name(err));
  return false;
}

所有步骤执行正常,成功获取Flash到内存的映射。但尝试将数据缓冲区复制到该映射区域(已确认分区大小大于待写入数据量)时:

uint8_t *flash_buffer = (uint8_t *) mapped_memory;
Serial.printf("Copying... %p %d", flash_buffer, model_data_size);
for (int i = 0; i < model_data_size; i++) {
  flash_buffer[i] = model_data[i];
  if (i % 10000 == 0) {
    Serial.printf("%d\n", i);
  }
}
Serial.println("\nCopied");

程序在写入前10000字节后触发系统重启,错误信息如下:

rst:0x8 (TG1WDT_SYS_RST),boot:0xa (SPI_FAST_FLASH_BOOT)
Saved PC:0x420219ff
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce3818,len:0xf88
load:0x403c9700,len:0x4
load:0x403c9704,len:0xa14
load:0x403cc700,len:0x2d64
entry 0x403c988c
E (312) esp_core_dump_flash: No core dump partition found!
E (312) esp_core_dump_flash: No core dump partition found!

尝试将Flash模式从QIO改为DIO,问题依旧。请问故障原因是什么?如何解决?


原因分析
  1. Flash内存映射的只读属性:使用ESP_PARTITION_MMAP_DATA参数映射的Flash区域是只读的,直接对映射内存执行写入操作会触发内存访问错误,进而触发系统看门狗重启(错误信息中的TG1WDT_SYS_RST即系统看门狗复位)。
  2. SPIFFS分区的特殊性:你创建的storage分区是SPIFFS文件系统类型,这类分区需要通过SPIFFS专属API进行文件操作,而非直接内存写入——直接写入会破坏文件系统结构,且SPIFFS分区在挂载前也不允许裸写操作。
解决方法

方法一:使用官方Flash写入API替代内存映射写入

如果不需要SPIFFS,仅需裸Flash存储,可先修改分区的SubType为普通数据分区(比如0x01或自定义类型),然后使用esp_partition_writeAPI完成写入:

// 替换原内存映射及循环写入代码
esp_err_t write_err = esp_partition_write(partition, 0, model_data, model_data_size);
if (write_err != ESP_OK) {
  Serial.printf("Failed to write flash: %s\n", esp_err_to_name(write_err));
  return false;
}
Serial.println("Write completed");

方法二:正确使用SPIFFS文件系统

如果需要保留SPIFFS分区,需先挂载分区,再通过文件操作写入数据:

  1. 挂载SPIFFS(需包含SPIFFS头文件):
#include "SPIFFS.h"

// 在setup函数中执行挂载
if (!SPIFFS.begin(true)) { // true表示格式化失败的分区
  Serial.println("SPIFFS Mount Failed");
  return;
}
  1. 写入数据到SPIFFS文件:
File file = SPIFFS.open("/model_data.bin", FILE_WRITE);
if (!file) {
  Serial.println("Failed to open file for writing");
  return;
}
size_t bytes_written = file.write(model_data, model_data_size);
if (bytes_written != model_data_size) {
  Serial.println("Failed to write all data");
}
file.close();
Serial.println("Data written to SPIFFS");

额外注意事项

  • ESP32不支持直接写入映射的Flash内存,即使修改映射参数也不行,必须通过官方提供的Flash写入API操作。
  • 看门狗重启是内存访问错误触发异常后,系统挂起导致看门狗超时复位的结果。

内容的提问来源于stack exchange,提问作者gillo04

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 17:35:22