DIO works with the same connections as Fast Read, so use it by default. Also correct the note in README.md which says that DIO requires additional pins.
174 lines
5.7 KiB
C
174 lines
5.7 KiB
C
/* 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 <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "esp_flash.h"
|
|
#include "esp_flash_spi_init.h"
|
|
#include "esp_partition.h"
|
|
#include "esp_vfs.h"
|
|
#include "esp_vfs_fat.h"
|
|
#include "esp_system.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();
|
|
static const esp_partition_t* example_add_partition(esp_flash_t* ext_flash, const char* partition_label);
|
|
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 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);
|
|
|
|
// 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()
|
|
{
|
|
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 = -1,
|
|
.quadhd_io_num = -1,
|
|
};
|
|
|
|
const esp_flash_spi_device_config_t device_config = {
|
|
.host_id = VSPI_HOST,
|
|
.cs_id = 0,
|
|
.cs_io_num = VSPI_IOMUX_PIN_NUM_CS,
|
|
.io_mode = SPI_FLASH_DIO,
|
|
.speed = ESP_FLASH_40MHZ
|
|
};
|
|
|
|
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 bool example_mount_fatfs(const char* partition_label)
|
|
{
|
|
ESP_LOGI(TAG, "Mounting FAT filesystem");
|
|
const esp_vfs_fat_mount_config_t mount_config = {
|
|
.max_files = 4,
|
|
.format_if_mount_failed = true,
|
|
.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;
|
|
}
|
|
}
|