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,问题依旧。请问故障原因是什么?如何解决?
原因分析
- Flash内存映射的只读属性:使用
ESP_PARTITION_MMAP_DATA参数映射的Flash区域是只读的,直接对映射内存执行写入操作会触发内存访问错误,进而触发系统看门狗重启(错误信息中的TG1WDT_SYS_RST即系统看门狗复位)。 - 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分区,需先挂载分区,再通过文件操作写入数据:
- 挂载SPIFFS(需包含SPIFFS头文件):
#include "SPIFFS.h" // 在setup函数中执行挂载 if (!SPIFFS.begin(true)) { // true表示格式化失败的分区 Serial.println("SPIFFS Mount Failed"); return; }
- 写入数据到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
相关产品推荐
相关产品推荐

