Skip to content

External flash #8479

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
1 task done
savagerex opened this issue Aug 2, 2023 · 20 comments
Closed
1 task done

External flash #8479

savagerex opened this issue Aug 2, 2023 · 20 comments
Assignees
Labels
Resolution: Awaiting response Waiting for response of author Type: Question Only question

Comments

@savagerex
Copy link

Board

ESP32 S3

Device Description

External Flash - W25Q256JV

Hardware Configuration

NONE

Version

v2.0.9

IDE Name

Arduino

Operating System

Windows 11

Flash frequency

80M

PSRAM enabled

no

Upload speed

921600

Description

i use these lib, but these lib have problem.
these lib as below.

https://github.com/PaulStoffregen/SerialFlash
https://github.com/adafruit/Adafruit_SPIFlash/tree/master

Can ESP team do lib for external flash(W25Q256JV)???

Sketch

NONE

Debug Message

NONE

Other Steps to Reproduce

No response

I have checked existing issues, online documentation and the Troubleshooting Guide

  • I confirm I have checked existing issues, online documentation and Troubleshooting guide.
@savagerex savagerex added the Status: Awaiting triage Issue is waiting for triage label Aug 2, 2023
@VojtechBartoska VojtechBartoska added Type: Question Only question and removed Status: Awaiting triage Issue is waiting for triage labels Aug 2, 2023
@lbernstone
Copy link
Contributor

lbernstone commented Aug 2, 2023

arduino-esp32 uses the spi flash libraries from esp-idf. If you need support for a particular chip, you should ask upstream.
https://docs.espressif.com/projects/esp-idf/en/v4.4.5/esp32/api-reference/storage/spi_flash.html

@SuGlider
Copy link
Collaborator

SuGlider commented Aug 2, 2023

@savagerex - I remember that your project uses the ESP32-S3-Mini M0N8 with 8MB Flash, no PSRAM.

One possible way to solve it, would be to use EEPROM Arduino Library within the S3 module flash.
It uses NVS IDF functions. It may be possible to create a separated NVS partition with, for instance, 4MB, and modify the EEPROM library to use such partition.

By this way the Winbond external module wouldn't be necessary anymore, but it would use the S3 module flash.
It may also be more cost effective to use a S3-Mini M0N16 instead and get 16MB flash for everything the project may need.

Would it work for you?

@savagerex
Copy link
Author

i know if i esp32 s3 of flash.
if i use "SPIFFS" lib.
i have tested it, it's no problem.

but we still need external flash. because external flash(W25Q256JV) is 32M byte.

ESP32 S3 of flash only have 16MB. it's not enough.

we need external flash to store data.

@SuGlider
Copy link
Collaborator

SuGlider commented Aug 3, 2023

In that case, what is the issue that you have when using these libraries:
SerialFlash from Paul and the Adafruit_SPIFlash?
Could you describe it and give me some examples about how to reproduce the issue in each one of them?

@SuGlider
Copy link
Collaborator

SuGlider commented Aug 3, 2023

I'll also need more details about how the SPI Flash chip is connected to the ESP32-S3 (connected pins).

@savagerex
Copy link
Author

@SuGlider
below is i use lib ( https://github.com/PaulStoffregen/SerialFlash).

External Flash total is 32 M byte.
Everytime i creat file 2M. after 16 times, Write Flash Full. there is error ( "There was an error opening the file for writing")

below is the sample code.


#include "SPI.h"
#include <SerialFlash.h>

#define SensorPowerPin 17

#define MOSI 35
#define MISO 37
#define SCK 36
#define FCSPIN 34
//#define CSPIN 21 // Arduino 101 built-in SPI Flash

#define SPI_FREQUENCY 40 * 1000000 //10

#define uS_TO_S_FACTOR 1000000 /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP 3 //30
RTC_DATA_ATTR int bootCount = 0;

void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
pinMode(SensorPowerPin, OUTPUT);
digitalWrite(SensorPowerPin, HIGH);
delay(15);

esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
bootCount++;

SPI.begin(SCK, MISO, MOSI, FCSPIN);
//SPI2.begin(SCK, MISO, MOSI);
SPI.setDataMode(SPI_MODE0);
SPI.setBitOrder(MSBFIRST);
SPI.setFrequency(SPI_FREQUENCY);

if (!SerialFlash.begin(SPI , FCSPIN)) {
while (1) {
  Serial.println(F("Unable to access SPI Flash chip"));
  delay(1000);
   }
 }
  //We start by formatting the flash...
  uint8_t id[5];
  SerialFlash.readID(id);
  Serial.printf("ID: %02X %02X %02X\n", id[0], id[1], id[2]);
  delay(500);
  Serial.print("bootCount = ");
  Serial.println(bootCount);

  delay(1000);
  Serial.println("Flash Ready");

  xTaskCreatePinnedToCore(taskTwo, "TaskTwo", 30000, NULL, 2, NULL, 1);

}

void taskTwo( void * parameter ) {
disableCore1WDT();

SerialFlashFile flashFile;

while(SerialFlash.createErasable("123.txt", 2000000)) //2000000
{
Serial.println("Flash Creat Error");
delay(2000);
}

flashFile = SerialFlash.open("123.txt");

if (!flashFile) {
Serial.println("There was an error opening the file for writing"); //when when flash is full, there is error.
while(1)
{
Serial.print("Boot = ");
Serial.println(bootCount);
delay(3000);
}
return;
}

for (;;) {
Serial.println("DelayTime : 1000");
delay(1000);
flashFile.close();

        flashFile = SerialFlash.open("123.txt");
        flashFile.erase();
        delay(500);
        SerialFlash.remove("123.txt");

        Serial.println("Task2 Going to sleep now");
        delay(100);
        esp_deep_sleep_start();

}
vTaskDelete( NULL );

}

void loop() {
// put your main code here, to run repeatedly:

}

@SuGlider
Copy link
Collaborator

SuGlider commented Aug 4, 2023

@savagerex
A possible alternative could be to write the ext_flash_fatfs IDF example in order to make it compile within ESP32 Arduino.

I have created a "translation" from the IDF example to Arduino 2.0.9 (see below), please try it.
This example is in https://github.com/espressif/esp-idf/tree/release/v4.4/examples/storage/ext_flash_fatfs
This IDF example has been tested with Winbond W25Q32 SPI Flash chip.

It uses the default SPI VSPI pins. Please refer to the readme file for more information about changing it.
https://github.com/espressif/esp-idf/blob/release/v4.4/examples/storage/ext_flash_fatfs/README.md

/* Example of FAT filesystem on external Flash.
   This example code is in the Public Domain (or CC0 licensed, at your option.)

 

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.

 

   This sample shows how to store files inside a FAT filesystem.
   FAT filesystem is stored in a partition inside SPI flash, using the
   flash wear levelling library.
*/

 

#include "esp_flash.h"
#include "esp_flash_spi_init.h"
#include "esp_vfs_fat.h"

 

static const char *TAG = "example";

 

// Handle of the wear levelling library instance
static wl_handle_t s_wl_handle = WL_INVALID_HANDLE;

 

// Mount path for the partition
const char *base_path = "/extflash";

 

static esp_flash_t* example_init_ext_flash(void);
static const esp_partition_t* example_add_partition(esp_flash_t* ext_flash, const char* partition_label);
static void example_list_data_partitions(void);
static bool example_mount_fatfs(const char* partition_label);
static void example_get_fatfs_usage(size_t* out_total_bytes, size_t* out_free_bytes);

 

void setup(){
  my_app_main();
}

 

void loop() {
}

 

void my_app_main(void)
{
    // Set up SPI bus and initialize the external SPI Flash chip
    esp_flash_t* flash = example_init_ext_flash();
    if (flash == NULL) {
        return;
    }

 

    // Add the entire external flash chip as a partition
    const char *partition_label = "storage";
    example_add_partition(flash, partition_label);

 

    // List the available partitions
    example_list_data_partitions();

 

    // Initialize FAT FS in the partition
    if (!example_mount_fatfs(partition_label)) {
        return;
    }

 

    // Print FAT FS size information
    size_t bytes_total, bytes_free;
    example_get_fatfs_usage(&bytes_total, &bytes_free);
    ESP_LOGI(TAG, "FAT FS: %d kB total, %d kB free", bytes_total / 1024, bytes_free / 1024);

 

    // Create a file in FAT FS
    ESP_LOGI(TAG, "Opening file");
    FILE *f = fopen("/extflash/hello.txt", "wb");
    if (f == NULL) {
        ESP_LOGE(TAG, "Failed to open file for writing");
        return;
    }
    fprintf(f, "Written using ESP-IDF %s\n", esp_get_idf_version());
    fclose(f);
    ESP_LOGI(TAG, "File written");

 

    // Open file for reading
    ESP_LOGI(TAG, "Reading file");
    f = fopen("/extflash/hello.txt", "rb");
    if (f == NULL) {
        ESP_LOGE(TAG, "Failed to open file for reading");
        return;
    }
    char line[128];
    fgets(line, sizeof(line), f);
    fclose(f);
    // strip newline
    char *pos = strchr(line, '\n');
    if (pos) {
        *pos = '\0';
    }
    ESP_LOGI(TAG, "Read from file: '%s'", line);
}

 

static esp_flash_t* example_init_ext_flash(void)
{
    const spi_bus_config_t bus_config = {
        .mosi_io_num = VSPI_IOMUX_PIN_NUM_MOSI,
        .miso_io_num = VSPI_IOMUX_PIN_NUM_MISO,
        .sclk_io_num = VSPI_IOMUX_PIN_NUM_CLK,
        .quadwp_io_num = VSPI_IOMUX_PIN_NUM_WP,
        .quadhd_io_num = VSPI_IOMUX_PIN_NUM_HD,
    };

 

    const esp_flash_spi_device_config_t device_config = {
        .host_id = VSPI_HOST,
        .cs_io_num = VSPI_IOMUX_PIN_NUM_CS,
        .io_mode = SPI_FLASH_DIO,
        .speed = ESP_FLASH_40MHZ,
        .cs_id = 0,
    };

 

    ESP_LOGI(TAG, "Initializing external SPI Flash");
    ESP_LOGI(TAG, "Pin assignments:");
    ESP_LOGI(TAG, "MOSI: %2d   MISO: %2d   SCLK: %2d   CS: %2d",
        bus_config.mosi_io_num, bus_config.miso_io_num,
        bus_config.sclk_io_num, device_config.cs_io_num
    );

 

    // Initialize the SPI bus
    ESP_ERROR_CHECK(spi_bus_initialize(VSPI_HOST, &bus_config, 1));

 

    // Add device to the SPI bus
    esp_flash_t* ext_flash;
    ESP_ERROR_CHECK(spi_bus_add_flash_device(&ext_flash, &device_config));

 

    // Probe the Flash chip and initialize it
    esp_err_t err = esp_flash_init(ext_flash);
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Failed to initialize external Flash: %s (0x%x)", esp_err_to_name(err), err);
        return NULL;
    }

 

    // Print out the ID and size
    uint32_t id;
    ESP_ERROR_CHECK(esp_flash_read_id(ext_flash, &id));
    ESP_LOGI(TAG, "Initialized external Flash, size=%d KB, ID=0x%x", ext_flash->size / 1024, id);

 

    return ext_flash;
}

 

static const esp_partition_t* example_add_partition(esp_flash_t* ext_flash, const char* partition_label)
{
    ESP_LOGI(TAG, "Adding external Flash as a partition, label=\"%s\", size=%d KB", partition_label, ext_flash->size / 1024);
    const esp_partition_t* fat_partition;
    ESP_ERROR_CHECK(esp_partition_register_external(ext_flash, 0, ext_flash->size, partition_label, ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_FAT, &fat_partition));
    return fat_partition;
}

 

static void example_list_data_partitions(void)
{
    ESP_LOGI(TAG, "Listing data partitions:");
    esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, NULL);

 

    for (; it != NULL; it = esp_partition_next(it)) {
        const esp_partition_t *part = esp_partition_get(it);
        ESP_LOGI(TAG, "- partition '%s', subtype %d, offset 0x%x, size %d kB",
        part->label, part->subtype, part->address, part->size / 1024);
    }

 

    esp_partition_iterator_release(it);
}

 

static bool example_mount_fatfs(const char* partition_label)
{
    ESP_LOGI(TAG, "Mounting FAT filesystem");
    const esp_vfs_fat_mount_config_t mount_config = {
            .format_if_mount_failed = true,
            .max_files = 4,
            .allocation_unit_size = CONFIG_WL_SECTOR_SIZE
    };
    esp_err_t err = esp_vfs_fat_spiflash_mount(base_path, partition_label, &mount_config, &s_wl_handle);
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Failed to mount FATFS (%s)", esp_err_to_name(err));
        return false;
    }
    return true;
}

 

static void example_get_fatfs_usage(size_t* out_total_bytes, size_t* out_free_bytes)
{
    FATFS *fs;
    size_t free_clusters;
    int res = f_getfree("0:", &free_clusters, &fs);
    assert(res == FR_OK);
    size_t total_sectors = (fs->n_fatent - 2) * fs->csize;
    size_t free_sectors = free_clusters * fs->csize;

 
    // assuming the total size is < 4GiB, should be true for SPI Flash
    if (out_total_bytes != NULL) {
        *out_total_bytes = total_sectors * fs->ssize;
    }
    if (out_free_bytes != NULL) {
        *out_free_bytes = free_sectors * fs->ssize;
    }
}

@SuGlider SuGlider self-assigned this Aug 4, 2023
@lbernstone
Copy link
Contributor

Note that once you have a partition labeled, you can mount it with the arduino tools by providing that partition label to the begin call.
https://github.com/espressif/arduino-esp32/blob/master/libraries/FFat/src/FFat.h#L31
https://github.com/espressif/arduino-esp32/blob/master/libraries/SPIFFS/src/SPIFFS.h#L27

@savagerex
Copy link
Author

@SuGlider

Question 1
if i write flash , as below.

flashFile.write(DataBufWrite, 120);

how to modify in this sample code from IDF ???

Question 2
if i read flash , as below.

flashFile.read(DataBufRead, 40500);

how to modify in this sample code from IDF ???

Question 3

how to delete the file ???

@savagerex
Copy link
Author

@SuGlider

why i , Serial.println(DataBufRead[100]);
the DataBufRead[100] is 0.
it should be 1.

below is code.


#include "esp_flash.h"
#include "esp_flash_spi_init.h"
#include "esp_vfs_fat.h"

#define uS_TO_S_FACTOR 1000000 /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP 3 //30
RTC_DATA_ATTR int bootCount = 0;

static const char *TAG = "example";

// Handle of the wear levelling library instance
static wl_handle_t s_wl_handle = WL_INVALID_HANDLE;

// Mount path for the partition
const char *base_path = "/extflash";

static esp_flash_t* example_init_ext_flash(void);
static const esp_partition_t* example_add_partition(esp_flash_t* ext_flash, const char* partition_label);
static void example_list_data_partitions(void);
static bool example_mount_fatfs(const char* partition_label);
static void example_get_fatfs_usage(size_t* out_total_bytes, size_t* out_free_bytes);

uint8_t* DataBufWrite;
uint8_t* DataBufRead;

void setup(){
Serial.begin(115200);

DataBufWrite = (uint8_t*)ps_calloc(1000000, sizeof(uint8_t)); //6 * 27000 * 3 = 486000
DataBufRead = (uint8_t*)ps_calloc(1000000, sizeof(uint8_t));

esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
bootCount++;

my_app_main();

Serial.print("bootCount = ");
Serial.println(bootCount);

xTaskCreatePinnedToCore(taskTwo, "TaskTwo", 30000, NULL, 2, NULL, 1);
}

void taskTwo( void * parameter ) {
disableCore1WDT();

for (;;) {
           LoopFlash();
           Serial.println("Task2 Going to sleep now");
           delay(1000);
           esp_deep_sleep_start();
}
vTaskDelete( NULL );

}

void loop() {
}

void LoopFlash(void)
{
// Create a file in FAT FS
ESP_LOGI(TAG, "Opening file");
FILE *f = fopen("/extflash/hello.txt", "wb");
if (f == NULL) {
ESP_LOGE(TAG, "Failed to open file for writing");
return;
}

for (int i = 0; i < 1000000; i++) {
      DataBufWrite[i] = '1';
    }

//fprintf(f, "Written using ESP-IDF %s\n", esp_get_idf_version());
fwrite (DataBufWrite, sizeof(uint8_t), sizeof(DataBufWrite), f);
fclose(f);
//ESP_LOGI(TAG, "File written");
Serial.println("File written");


// Open file for reading
ESP_LOGI(TAG, "Reading file");
f = fopen("/extflash/hello.txt", "rb");
if (f == NULL) {
    ESP_LOGE(TAG, "Failed to open file for reading");
    return;
}
//char line[128];
//fgets(line, sizeof(line), f);
fread (DataBufRead, sizeof(uint8_t), sizeof(DataBufRead), f);
fclose(f);
// strip newline
//char *pos = strchr(line, '\n');
//if (pos) {
//    *pos = '\0';
//}
//ESP_LOGI(TAG, "Read from file: '%s'", line);
//Serial.println(line);
Serial.println(DataBufRead[100]);      //************************it should be 1************************************
remove("hello.txt");

}

void my_app_main(void)
{
// Set up SPI bus and initialize the external SPI Flash chip
esp_flash_t* flash = example_init_ext_flash();
if (flash == NULL) {
return;
}

// Add the entire external flash chip as a partition
const char *partition_label = "storage";
example_add_partition(flash, partition_label);



// List the available partitions
example_list_data_partitions();



// Initialize FAT FS in the partition
if (!example_mount_fatfs(partition_label)) {
    return;
}



// Print FAT FS size information
size_t bytes_total, bytes_free;
example_get_fatfs_usage(&bytes_total, &bytes_free);
ESP_LOGI(TAG, "FAT FS: %d kB total, %d kB free", bytes_total / 1024, bytes_free / 1024);



// Create a file in FAT FS
ESP_LOGI(TAG, "Opening file");
FILE *f = fopen("/extflash/hello.txt", "wb");
if (f == NULL) {
    ESP_LOGE(TAG, "Failed to open file for writing");
    return;
}
fprintf(f, "Written using ESP-IDF %s\n", esp_get_idf_version());
fclose(f);
//ESP_LOGI(TAG, "File written");
Serial.println("File written");


// Open file for reading
ESP_LOGI(TAG, "Reading file");
f = fopen("/extflash/hello.txt", "rb");
if (f == NULL) {
    ESP_LOGE(TAG, "Failed to open file for reading");
    return;
}
char line[128];
fgets(line, sizeof(line), f);
fclose(f);
// strip newline
char *pos = strchr(line, '\n');
if (pos) {
    *pos = '\0';
}
//ESP_LOGI(TAG, "Read from file: '%s'", line);
Serial.println(line);

}

static esp_flash_t* example_init_ext_flash(void)
{
const spi_bus_config_t bus_config = {
.mosi_io_num = VSPI_IOMUX_PIN_NUM_MOSI,
.miso_io_num = VSPI_IOMUX_PIN_NUM_MISO,
.sclk_io_num = VSPI_IOMUX_PIN_NUM_CLK,
.quadwp_io_num = VSPI_IOMUX_PIN_NUM_WP,
.quadhd_io_num = VSPI_IOMUX_PIN_NUM_HD,
};

const esp_flash_spi_device_config_t device_config = {
    .host_id = VSPI_HOST,
    .cs_io_num = VSPI_IOMUX_PIN_NUM_CS,
    .io_mode = SPI_FLASH_DIO,
    .speed = ESP_FLASH_40MHZ,
    .cs_id = 0,
};



ESP_LOGI(TAG, "Initializing external SPI Flash");
ESP_LOGI(TAG, "Pin assignments:");
ESP_LOGI(TAG, "MOSI: %2d   MISO: %2d   SCLK: %2d   CS: %2d",
    bus_config.mosi_io_num, bus_config.miso_io_num,
    bus_config.sclk_io_num, device_config.cs_io_num
);



// Initialize the SPI bus
ESP_ERROR_CHECK(spi_bus_initialize(VSPI_HOST, &bus_config, 1));



// Add device to the SPI bus
esp_flash_t* ext_flash;
ESP_ERROR_CHECK(spi_bus_add_flash_device(&ext_flash, &device_config));



// Probe the Flash chip and initialize it
esp_err_t err = esp_flash_init(ext_flash);
if (err != ESP_OK) {
    ESP_LOGE(TAG, "Failed to initialize external Flash: %s (0x%x)", esp_err_to_name(err), err);
    return NULL;
}



// Print out the ID and size
uint32_t id;
ESP_ERROR_CHECK(esp_flash_read_id(ext_flash, &id));
ESP_LOGI(TAG, "Initialized external Flash, size=%d KB, ID=0x%x", ext_flash->size / 1024, id);
Serial.print("Device ID");
Serial.println(id, HEX);   


return ext_flash;

}

static const esp_partition_t* example_add_partition(esp_flash_t* ext_flash, const char* partition_label)
{
ESP_LOGI(TAG, "Adding external Flash as a partition, label="%s", size=%d KB", partition_label, ext_flash->size / 1024);
const esp_partition_t* fat_partition;
ESP_ERROR_CHECK(esp_partition_register_external(ext_flash, 0, ext_flash->size, partition_label, ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_FAT, &fat_partition));
return fat_partition;
}

static void example_list_data_partitions(void)
{
ESP_LOGI(TAG, "Listing data partitions:");
esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, NULL);

for (; it != NULL; it = esp_partition_next(it)) {
    const esp_partition_t *part = esp_partition_get(it);
    ESP_LOGI(TAG, "- partition '%s', subtype %d, offset 0x%x, size %d kB",
    part->label, part->subtype, part->address, part->size / 1024);
}



esp_partition_iterator_release(it);

}

static bool example_mount_fatfs(const char* partition_label)
{
ESP_LOGI(TAG, "Mounting FAT filesystem");
const esp_vfs_fat_mount_config_t mount_config = {
.format_if_mount_failed = true,
.max_files = 4,
.allocation_unit_size = CONFIG_WL_SECTOR_SIZE
};
esp_err_t err = esp_vfs_fat_spiflash_mount(base_path, partition_label, &mount_config, &s_wl_handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to mount FATFS (%s)", esp_err_to_name(err));
return false;
}
return true;
}

static void example_get_fatfs_usage(size_t* out_total_bytes, size_t* out_free_bytes)
{
FATFS *fs;
size_t free_clusters;
int res = f_getfree("0:", &free_clusters, &fs);
assert(res == FR_OK);
size_t total_sectors = (fs->n_fatent - 2) * fs->csize;
size_t free_sectors = free_clusters * fs->csize;

// assuming the total size is < 4GiB, should be true for SPI Flash
if (out_total_bytes != NULL) {
    *out_total_bytes = total_sectors * fs->ssize;
}
if (out_free_bytes != NULL) {
    *out_free_bytes = free_sectors * fs->ssize;
}

}

@SuGlider
Copy link
Collaborator

SuGlider commented Aug 9, 2023

@savagerex - fread (DataBufRead, sizeof(uint8_t), sizeof(DataBufRead), f); reads 4 bytes only.

unsigned fread (void *buffer, int bytes_per_block, int number_of_blocks, FILE *fp);
sizeof(uint8_t) is 1
sizeof(uint8_t*) is 4 - uint8_t* DataBufRead is diffrent of uint8_t DataBufRead[1000000] in size.

The same issue when writing with uint8_t* DataBufWrite
fwrite (DataBufWrite, sizeof(uint8_t), sizeof(DataBufWrite), f); only writes 4 bytes.

@savagerex
Copy link
Author

OK, Thanks

@savagerex
Copy link
Author

@SuGlider

i use ESP32 WROVER, but my flash is connect HSPI.
i modify the code as below.
but it can not work.

there is the debug message.


E (593) memspi: no response

bootCount = 2
Task2 Going to sleep now
E (593) memspi: no response

bootCount = 3
Task2 Going to sleep now
E (593) memspi: no response

bootCount = 4
Task2 Going to sleep now


#include "esp_flash.h"
#include "esp_flash_spi_init.h"
#include "esp_vfs_fat.h"

#define uS_TO_S_FACTOR 1000000 /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP 3 //30
RTC_DATA_ATTR int bootCount = 0;

static const char *TAG = "example";

// Handle of the wear levelling library instance
static wl_handle_t s_wl_handle = WL_INVALID_HANDLE;

// Mount path for the partition
const char *base_path = "/extflash";

static esp_flash_t* example_init_ext_flash(void);
static const esp_partition_t* example_add_partition(esp_flash_t* ext_flash, const char* partition_label);
static void example_list_data_partitions(void);
static bool example_mount_fatfs(const char* partition_label);
static void example_get_fatfs_usage(size_t* out_total_bytes, size_t* out_free_bytes);

uint8_t* DataBufWrite;
uint8_t* DataBufRead;

void setup() {
Serial.begin(115200);

DataBufWrite = (uint8_t*)ps_calloc(1000000, sizeof(uint8_t)); //6 * 27000 * 3 = 486000
DataBufRead = (uint8_t*)ps_calloc(1000000, sizeof(uint8_t));

esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
bootCount++;

my_app_main();

Serial.print("bootCount = ");
Serial.println(bootCount);

xTaskCreatePinnedToCore(taskTwo, "TaskTwo", 30000, NULL, 2, NULL, 1);
}

void taskTwo( void * parameter ) {
disableCore1WDT();

for (;;) {
LoopFlash();
Serial.println("Task2 Going to sleep now");
delay(1000);
esp_deep_sleep_start();
}
vTaskDelete( NULL );
}

void loop() {
}

void LoopFlash(void)
{
// Create a file in FAT FS
ESP_LOGI(TAG, "Opening file");
FILE *f = fopen("/extflash/hello.txt", "wb");
if (f == NULL) {
ESP_LOGE(TAG, "Failed to open file for writing");
return;
}

for (int i = 0; i < 1000000; i++) {
DataBufWrite[i] = '1';
}

//fprintf(f, "Written using ESP-IDF %s\n", esp_get_idf_version());
fwrite (DataBufWrite, sizeof(uint8_t), 1000000, f);
fclose(f);
//ESP_LOGI(TAG, "File written");
Serial.println(sizeof(DataBufWrite));
Serial.println("File written");

// Open file for reading
ESP_LOGI(TAG, "Reading file");
f = fopen("/extflash/hello.txt", "rb");
if (f == NULL) {
ESP_LOGE(TAG, "Failed to open file for reading");
return;
}
//char line[128];
//fgets(line, sizeof(line), f);
fread (DataBufRead, sizeof(uint8_t), 1000000, f);
fclose(f);
// strip newline
//char *pos = strchr(line, '\n');
//if (pos) {
// *pos = '\0';
//}
//ESP_LOGI(TAG, "Read from file: '%s'", line);
//Serial.println(line);
Serial.println(sizeof(DataBufRead));
Serial.println((char)DataBufRead[100]);
remove("hello.txt");
}

void my_app_main(void)
{
// Set up SPI bus and initialize the external SPI Flash chip
esp_flash_t* flash = example_init_ext_flash();
if (flash == NULL) {
return;
}

// Add the entire external flash chip as a partition
const char *partition_label = "storage";
example_add_partition(flash, partition_label);

// List the available partitions
example_list_data_partitions();

// Initialize FAT FS in the partition
if (!example_mount_fatfs(partition_label)) {
return;
}

// Print FAT FS size information
size_t bytes_total, bytes_free;
example_get_fatfs_usage(&bytes_total, &bytes_free);
ESP_LOGI(TAG, "FAT FS: %d kB total, %d kB free", bytes_total / 1024, bytes_free / 1024);

// Create a file in FAT FS
ESP_LOGI(TAG, "Opening file");
FILE *f = fopen("/extflash/hello.txt", "wb");
if (f == NULL) {
ESP_LOGE(TAG, "Failed to open file for writing");
return;
}
fprintf(f, "Written using ESP-IDF %s\n", esp_get_idf_version());
fclose(f);
//ESP_LOGI(TAG, "File written");
Serial.println("File written");

// Open file for reading
ESP_LOGI(TAG, "Reading file");
f = fopen("/extflash/hello.txt", "rb");
if (f == NULL) {
ESP_LOGE(TAG, "Failed to open file for reading");
return;
}
char line[128];
fgets(line, sizeof(line), f);
fclose(f);
// strip newline
char *pos = strchr(line, '\n');
if (pos) {
*pos = '\0';
}
//ESP_LOGI(TAG, "Read from file: '%s'", line);
Serial.println(line);
}

static esp_flash_t* example_init_ext_flash(void)
{
const spi_bus_config_t bus_config = {
.mosi_io_num = HSPI_IOMUX_PIN_NUM_MOSI,
.miso_io_num = HSPI_IOMUX_PIN_NUM_MISO,
.sclk_io_num = HSPI_IOMUX_PIN_NUM_CLK,
.quadwp_io_num = HSPI_IOMUX_PIN_NUM_WP,
.quadhd_io_num = HSPI_IOMUX_PIN_NUM_HD,
};

const esp_flash_spi_device_config_t device_config = {
.host_id = HSPI_HOST,
.cs_io_num = HSPI_IOMUX_PIN_NUM_CS,
.io_mode = SPI_FLASH_DIO,
.speed = ESP_FLASH_40MHZ,
.cs_id = 0,
};

ESP_LOGI(TAG, "Initializing external SPI Flash");
ESP_LOGI(TAG, "Pin assignments:");
ESP_LOGI(TAG, "MOSI: %2d MISO: %2d SCLK: %2d CS: %2d",
bus_config.mosi_io_num, bus_config.miso_io_num,
bus_config.sclk_io_num, device_config.cs_io_num
);

// Initialize the SPI bus
ESP_ERROR_CHECK(spi_bus_initialize(HSPI_HOST, &bus_config, 1));

// Add device to the SPI bus
esp_flash_t* ext_flash;
ESP_ERROR_CHECK(spi_bus_add_flash_device(&ext_flash, &device_config));

// Probe the Flash chip and initialize it
esp_err_t err = esp_flash_init(ext_flash);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize external Flash: %s (0x%x)", esp_err_to_name(err), err);
return NULL;
}

// Print out the ID and size
uint32_t id;
ESP_ERROR_CHECK(esp_flash_read_id(ext_flash, &id));
ESP_LOGI(TAG, "Initialized external Flash, size=%d KB, ID=0x%x", ext_flash->size / 1024, id);
Serial.print("Device ID");
Serial.println(id, HEX);

return ext_flash;
}

static const esp_partition_t* example_add_partition(esp_flash_t* ext_flash, const char* partition_label)
{
ESP_LOGI(TAG, "Adding external Flash as a partition, label="%s", size=%d KB", partition_label, ext_flash->size / 1024);
const esp_partition_t* fat_partition;
ESP_ERROR_CHECK(esp_partition_register_external(ext_flash, 0, ext_flash->size, partition_label, ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_FAT, &fat_partition));
return fat_partition;
}

static void example_list_data_partitions(void)
{
ESP_LOGI(TAG, "Listing data partitions:");
esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, NULL);

for (; it != NULL; it = esp_partition_next(it)) {
const esp_partition_t *part = esp_partition_get(it);
ESP_LOGI(TAG, "- partition '%s', subtype %d, offset 0x%x, size %d kB",
part->label, part->subtype, part->address, part->size / 1024);
}

esp_partition_iterator_release(it);
}

static bool example_mount_fatfs(const char* partition_label)
{
ESP_LOGI(TAG, "Mounting FAT filesystem");
const esp_vfs_fat_mount_config_t mount_config = {
.format_if_mount_failed = true,
.max_files = 4,
.allocation_unit_size = CONFIG_WL_SECTOR_SIZE
};
esp_err_t err = esp_vfs_fat_spiflash_mount(base_path, partition_label, &mount_config, &s_wl_handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to mount FATFS (%s)", esp_err_to_name(err));
return false;
}
return true;
}

static void example_get_fatfs_usage(size_t* out_total_bytes, size_t* out_free_bytes)
{
FATFS *fs;
size_t free_clusters;
int res = f_getfree("0:", &free_clusters, &fs);
assert(res == FR_OK);
size_t total_sectors = (fs->n_fatent - 2) * fs->csize;
size_t free_sectors = free_clusters * fs->csize;

// assuming the total size is < 4GiB, should be true for SPI Flash
if (out_total_bytes != NULL) {
*out_total_bytes = total_sectors * fs->ssize;
}
if (out_free_bytes != NULL) {
*out_free_bytes = free_sectors * fs->ssize;
}
}

@SuGlider
Copy link
Collaborator

SuGlider commented Aug 11, 2023

@savagerex - memspi no response usually means that the flash chip doesn't send the correct response.
It could be an issue with MISO GPIO. Maybe using a logic analyzer may help.

Please check the pins and connections to make sure that it is correct.

#define HSPI_IOMUX_PIN_NUM_MISO 12
#define HSPI_IOMUX_PIN_NUM_MOSI 13
#define HSPI_IOMUX_PIN_NUM_CLK 14
#define HSPI_IOMUX_PIN_NUM_CS 15
#define HSPI_IOMUX_PIN_NUM_WP 2
#define HSPI_IOMUX_PIN_NUM_HD 4

@savagerex
Copy link
Author

OK!! Thanks

@VojtechBartoska
Copy link
Contributor

Can we consider this as solved and close this ticket?

@VojtechBartoska VojtechBartoska added the Resolution: Awaiting response Waiting for response of author label Aug 18, 2023
@Endorfin35
Copy link

Endorfin35 commented Sep 12, 2023

@SuGlider

IDF örneğinden Arduino 2.0.9'a bir "çeviri" oluşturuldu (aşağıya bakın), lütfen deneyin. Bu örnek https://github.com/espressif/esp-idf/tree/release/v4.4/examples/storage/ext_flash_fatfs

I tried this example successfully. I want to use the functions in the Ffat.h library when writing my own functions related to filing.

https://github.com/espressif/arduino-esp32/blob/master/libraries/FFat/examples/FFat_Test/FFat_Test.ino

However, I'm a little confused. In the example you gave, we had already installed the Fat system. Is it OK to add it back to the Ffat.h library? Or will Ffat.h only be effective on internal flash?

For example, I couldn't find a way to run the listdir() function.

@lbernstone
Copy link
Contributor

Please don't hijack threads.
listdir() is not a built in function. AFAIK, the test example should work just fine with an external flash mounted into arduino FS.

@Endorfin35
Copy link

Sorry for the confusion.

The example works just fine. I have no problem with this.

I want to ask something else. When I do not connect the Wp and Hold pins, the flash works without any problems. I want to use the io connections defined on these pins for another purpose. How can I make the code release these pins?

GPIO22WP
GPIO21HD

@SuGlider SuGlider mentioned this issue Sep 27, 2023
1 task
@VojtechBartoska
Copy link
Contributor

VojtechBartoska commented Dec 12, 2023

Hello, closing this ticket as it seems original questions have been answered.

@Endorfin35 if you found some issue in the code, please open another issue or if you have just question, please refer to Gitter channel. Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Resolution: Awaiting response Waiting for response of author Type: Question Only question
Projects
None yet
Development

No branches or pull requests

5 participants