-
Notifications
You must be signed in to change notification settings - Fork 7.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'feature/ext_flash_example' into 'master'
examples: add FATFS in external Flash example See merge request espressif/esp-idf!5579
- Loading branch information
Showing
7 changed files
with
263 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# The following lines of boilerplate have to be in your project's CMakeLists | ||
# in this exact order for cmake to work correctly | ||
cmake_minimum_required(VERSION 3.5) | ||
|
||
include($ENV{IDF_PATH}/tools/cmake/project.cmake) | ||
project(ext_flash_fatfs) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# | ||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a | ||
# project subdirectory. | ||
# | ||
|
||
PROJECT_NAME := ext_flash_fatfs | ||
|
||
include $(IDF_PATH)/make/project.mk | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
# FAT FS on External Flash example | ||
|
||
(See the README.md file in the upper level 'examples' directory for more information about examples.) | ||
|
||
This example is similar to the [wear levelling](../wear_levelling/README.md) example, except that it uses an external SPI Flash chip. This can be useful if you need to add more storage to a module with only 4 MB flash size. | ||
|
||
The flow of the example is as follows: | ||
|
||
1. Initialize the SPI bus and configure the pins. In this example, VSPI peripheral is used. The pins chosen in this example correspond to IOMUX pins for the VSPI peripheral. If the pin assignment is changed, SPI driver will instead connect the peripheral to the pins using the GPIO Matrix. | ||
|
||
2. Initialize the SPI flash chip. This involves creating a run-time object which describes the flash chip (`esp_flash_t`), probing the flash chip, and configuring it for the selected read mode. By default this example uses "Fast Read" mode, which only requires 4 pins (MOSI, MISO, SCLK, CS). For modes such as DIO, QIO, additional pins must be connected. | ||
|
||
3. Register the entire area of the Flash chip as a *partition* (`esp_partition_t`). This allows other components (FATFS, SPIFFS, NVS, etc) to use the storage provided by the external flash chip. | ||
|
||
4. Do some read and write operations using C standard library functions: create a file, write to it, open it for reading, print the contents to the console. | ||
|
||
## How to use example | ||
|
||
### Hardware required | ||
|
||
This example needs an SPI NOR Flash chip connected to the ESP32. The SPI Flash chip must have 3.3V logic levels. The example has been tested with Winbond W25Q32 SPI Flash chip. | ||
|
||
Use the following pin assignments: | ||
|
||
ESP32 pin | SPI bus signal | SPI Flash pin | ||
--------------|----------------|---------------- | ||
GPIO23 | MOSI | DI | ||
GPIO19 | MISO | DO | ||
GPIO18 | SCLK | CLK | ||
GPIO5 | CS | CMD | ||
unconnected | | WP | ||
unconnected | | HOLD | ||
GND | | GND | ||
VCC | | VCC | ||
|
||
### Build and flash | ||
|
||
Build the project and flash it to the board, then run monitor tool to view serial output: | ||
|
||
``` | ||
idf.py -p PORT flash monitor | ||
``` | ||
|
||
(Replace PORT with serial port name.) | ||
|
||
(To exit the serial monitor, type ``Ctrl-]``.) | ||
|
||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. | ||
|
||
## Example output | ||
|
||
Here is a typical example console output. | ||
|
||
``` | ||
I (328) example: Initializing external SPI Flash | ||
I (338) example: Pin assignments: | ||
I (338) example: MOSI: 23 MISO: 19 SCLK: 18 CS: 5 | ||
I (348) spi_flash: detected chip: generic | ||
I (348) spi_flash: flash io: fastrd | ||
I (348) example: Initialized external Flash, size=4096 KB, ID=0xef4016 | ||
I (358) example: Adding external Flash as a partition, label="storage", size=4096 KB | ||
I (368) example: Mounting FAT filesystem | ||
I (378) example: FAT FS: 4024 kB total, 4020 kB free | ||
I (378) example: Opening file | ||
I (958) example: File written | ||
I (958) example: Reading file | ||
I (958) example: Read from file: 'Written using ESP-IDF v4.0-dev-1301-g0a1160468' | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
idf_component_register(SRCS "ext_flash_fatfs_example_main.c") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# | ||
# "main" pseudo-component makefile. | ||
# | ||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) |
174 changes: 174 additions & 0 deletions
174
examples/storage/ext_flash_fatfs/main/ext_flash_fatfs_example_main.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
/* 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_FASTRD, | ||
.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; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters