Skip to content

Commit af096d6

Browse files
committed
feat(spi_nand_flash): update test_app, host_tests and documentation for block device support
1 parent 9e0efb1 commit af096d6

File tree

14 files changed

+984
-30
lines changed

14 files changed

+984
-30
lines changed

.build-test-rules.yml

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -76,20 +76,17 @@ esp_lcd_qemu_rgb/examples/lcd_qemu_rgb_panel:
7676

7777
spi_nand_flash/examples:
7878
disable:
79-
- if: IDF_VERSION_MAJOR < 5
80-
reason: The spi_nand_flash component is compatible with IDF version v5.0 and above, due to a change in the f_mkfs API in versions above v5.0, which is not supported in older IDF versions.
79+
- if: IDF_VERSION_MAJOR < 6
80+
reason: The spi_nand_flash component uses the esp_blockdev interface, which is supported starting from IDF version v6.0. It is not available in older IDF versions.
8181

8282
spi_nand_flash/test_app:
8383
disable:
84-
- if: IDF_VERSION_MAJOR < 5
85-
reason: The spi_nand_flash component is compatible with IDF version v5.0 and above, due to a change in the f_mkfs API in versions above v5.0, which is not supported in older IDF versions.
84+
- if: IDF_VERSION_MAJOR < 6
85+
reason: The spi_nand_flash component uses the esp_blockdev interface, which is supported starting from IDF version v6.0. It is not available in older IDF versions.
8686

8787
spi_nand_flash/host_test:
8888
enable:
8989
- if: IDF_TARGET == "linux"
9090
disable:
91-
- if: IDF_VERSION_MAJOR < 5
92-
reason: The spi_nand_flash component is compatible with IDF version v5.0 and above, due to a change in the f_mkfs API in versions above v5.0, which is not supported in older IDF versions.
93-
disable:
94-
- if: IDF_VERSION_MAJOR == 5 and (IDF_VERSION_MINOR < 3)
95-
reason: Fails to build on older versions of IDF
91+
- if: IDF_VERSION_MAJOR < 6
92+
reason: The spi_nand_flash component uses the esp_blockdev interface, which is supported starting from IDF version v6.0. It is not available in older IDF versions.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# The following lines of boilerplate have to be in your project's CMakeLists
2+
# in this exact order for cmake to work correctly
3+
cmake_minimum_required(VERSION 3.5)
4+
5+
set(COMPONENTS main)
6+
7+
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
8+
project(nand_flash_bdl)
9+
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
2+
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
3+
4+
# SPI NAND Flash BDL Example
5+
6+
This example demonstrates how to use the SPI NAND Flash driver with FAT filesystem using the Block Device Layer (BDL) API in ESP-IDF.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
idf_component_register(SRCS "spi_nand_flash_bdl_example_main.c"
2+
INCLUDE_DIRS "."
3+
PRIV_REQUIRES spi_nand_flash
4+
)
5+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
menu "Example Configuration"
2+
3+
config EXAMPLE_FORMAT_IF_MOUNT_FAILED
4+
bool "Format the file system if mount failed"
5+
default n
6+
help
7+
If this configuration is enabled, the example will format the file system
8+
if it fails to mount the file system.
9+
10+
endmenu
11+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
dependencies:
2+
espressif/spi_nand_flash:
3+
version: '*'
4+
override_path: '../../../'
5+
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Unlicense OR CC0-1.0
5+
*/
6+
7+
#include <stdlib.h>
8+
#include <stdio.h>
9+
#include <string.h>
10+
11+
#include "esp_system.h"
12+
#include "soc/spi_pins.h"
13+
#include "esp_vfs_fat_nand.h"
14+
#include "esp_nand_blockdev.h"
15+
16+
#define EXAMPLE_FLASH_FREQ_KHZ 40000
17+
18+
static const char *TAG = "example_bdl";
19+
20+
// Pin mapping
21+
// ESP32 (VSPI)
22+
#ifdef CONFIG_IDF_TARGET_ESP32
23+
#define HOST_ID SPI3_HOST
24+
#define PIN_MOSI SPI3_IOMUX_PIN_NUM_MOSI
25+
#define PIN_MISO SPI3_IOMUX_PIN_NUM_MISO
26+
#define PIN_CLK SPI3_IOMUX_PIN_NUM_CLK
27+
#define PIN_CS SPI3_IOMUX_PIN_NUM_CS
28+
#define PIN_WP SPI3_IOMUX_PIN_NUM_WP
29+
#define PIN_HD SPI3_IOMUX_PIN_NUM_HD
30+
#define SPI_DMA_CHAN SPI_DMA_CH_AUTO
31+
#else // Other chips (SPI2/HSPI)
32+
#define HOST_ID SPI2_HOST
33+
#define PIN_MOSI SPI2_IOMUX_PIN_NUM_MOSI
34+
#define PIN_MISO SPI2_IOMUX_PIN_NUM_MISO
35+
#define PIN_CLK SPI2_IOMUX_PIN_NUM_CLK
36+
#define PIN_CS SPI2_IOMUX_PIN_NUM_CS
37+
#define PIN_WP SPI2_IOMUX_PIN_NUM_WP
38+
#define PIN_HD SPI2_IOMUX_PIN_NUM_HD
39+
#define SPI_DMA_CHAN SPI_DMA_CH_AUTO
40+
#endif
41+
42+
// Mount path for the partition
43+
const char *base_path = "/nandflash_bdl_example";
44+
45+
void app_main(void)
46+
{
47+
esp_err_t ret;
48+
spi_device_handle_t spi = NULL;
49+
esp_blockdev_handle_t wl_bdl = NULL;
50+
51+
// Initialize SPI bus
52+
const spi_bus_config_t bus_config = {
53+
.mosi_io_num = PIN_MOSI,
54+
.miso_io_num = PIN_MISO,
55+
.sclk_io_num = PIN_CLK,
56+
.quadhd_io_num = PIN_HD,
57+
.quadwp_io_num = PIN_WP,
58+
.max_transfer_sz = 4096 * 2,
59+
};
60+
61+
ESP_LOGI(TAG, "DMA CHANNEL: %d", SPI_DMA_CHAN);
62+
ESP_ERROR_CHECK(spi_bus_initialize(HOST_ID, &bus_config, SPI_DMA_CHAN));
63+
64+
const uint32_t spi_flags = SPI_DEVICE_HALFDUPLEX;
65+
spi_device_interface_config_t devcfg = {
66+
.clock_speed_hz = EXAMPLE_FLASH_FREQ_KHZ * 1000,
67+
.mode = 0,
68+
.spics_io_num = PIN_CS,
69+
.queue_size = 10,
70+
.flags = spi_flags,
71+
};
72+
73+
ESP_ERROR_CHECK(spi_bus_add_device(HOST_ID, &devcfg, &spi));
74+
75+
// Create Flash Block Device Layer (this will initialize the device)
76+
spi_nand_flash_config_t config = {
77+
.device_handle = spi,
78+
.io_mode = SPI_NAND_IO_MODE_SIO,
79+
.flags = spi_flags,
80+
.gc_factor = 4, // Wear leveling GC factor
81+
};
82+
83+
ret = spi_nand_flash_init_with_layers(&config, &wl_bdl);
84+
if (ret != ESP_OK) {
85+
ESP_LOGE(TAG, "Failed to create BDL: %s", esp_err_to_name(ret));
86+
goto cleanup;
87+
}
88+
89+
// Mount FATFS using BDL
90+
esp_vfs_fat_mount_config_t mount_config = {
91+
.max_files = 4,
92+
#ifdef CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED
93+
.format_if_mount_failed = true,
94+
#else
95+
.format_if_mount_failed = false,
96+
#endif
97+
.allocation_unit_size = 16 * 1024
98+
};
99+
100+
ret = esp_vfs_fat_nand_mount_bdl(base_path, wl_bdl, &mount_config);
101+
if (ret != ESP_OK) {
102+
if (ret == ESP_FAIL) {
103+
ESP_LOGE(TAG, "Failed to mount filesystem. "
104+
"If you want the flash memory to be formatted, set the CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED menuconfig option.");
105+
}
106+
goto cleanup;
107+
}
108+
109+
// Print FAT FS size information
110+
uint64_t bytes_total, bytes_free;
111+
esp_vfs_fat_info(base_path, &bytes_total, &bytes_free);
112+
ESP_LOGI(TAG, "FAT FS: %" PRIu64 " kB total, %" PRIu64 " kB free", bytes_total / 1024, bytes_free / 1024);
113+
114+
// Create a file in FAT FS
115+
ESP_LOGI(TAG, "Opening file");
116+
FILE *f = fopen("/nandflash/hello_bdl.txt", "wb");
117+
if (f == NULL) {
118+
ESP_LOGE(TAG, "Failed to open file for writing");
119+
goto cleanup_fs;
120+
}
121+
fprintf(f, "Written using ESP-IDF %s with BDL API\n", esp_get_idf_version());
122+
fclose(f);
123+
ESP_LOGI(TAG, "File written");
124+
125+
// Open file for reading
126+
ESP_LOGI(TAG, "Reading file");
127+
f = fopen("/nandflash/hello_bdl.txt", "rb");
128+
if (f == NULL) {
129+
ESP_LOGE(TAG, "Failed to open file for reading");
130+
goto cleanup_fs;
131+
}
132+
char line[128];
133+
fgets(line, sizeof(line), f);
134+
fclose(f);
135+
// strip newline
136+
char *pos = strchr(line, '\n');
137+
if (pos) {
138+
*pos = '\0';
139+
}
140+
ESP_LOGI(TAG, "Read from file: '%s'", line);
141+
142+
esp_vfs_fat_info(base_path, &bytes_total, &bytes_free);
143+
ESP_LOGI(TAG, "FAT FS: %" PRIu64 " kB total, %" PRIu64 " kB free", bytes_total / 1024, bytes_free / 1024);
144+
145+
cleanup_fs:
146+
// Unmount FATFS
147+
esp_vfs_fat_nand_unmount_bdl(base_path, wl_bdl);
148+
149+
cleanup:
150+
// Release block device handles
151+
if (wl_bdl) {
152+
wl_bdl->ops->release(wl_bdl);
153+
}
154+
// Cleanup SPI bus
155+
if (spi) {
156+
ESP_ERROR_CHECK(spi_bus_remove_device(spi));
157+
}
158+
ESP_ERROR_CHECK(spi_bus_free(HOST_ID));
159+
}
160+

spi_nand_flash/host_test/README.md

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,21 +34,44 @@ nand_mmap_emul_config_t cfg = {
3434

3535
### Usage Example:
3636

37+
#### Option 1: Direct Device API
3738
```c
3839
// Initialize with custom settings
39-
nand_mmap_emul_config_t cfg = {
40+
nand_file_mmap_emul_config_t cfg = {
4041
.flash_file_name = "/tmp/my_nand.bin",
41-
.flash_file_size = 1024 * 1024, // 1MB
42+
.flash_file_size = 50 * 1024 * 1024, // 50MB
4243
.keep_dump = false
4344
};
44-
spi_nand_flash_config_t nand_flash_config = {.emul_conf = &cfg};
45+
spi_nand_flash_config_t nand_flash_config = {&cfg, 0, SPI_NAND_IO_MODE_SIO, 0};
4546

46-
// Initialize nand_flash with NAND emulation parameter
47+
// Initialize NAND flash with emulation
4748
spi_nand_flash_device_t *handle;
48-
spi_nand_flash_init_device(&nand_flash_config, &handle)
49+
spi_nand_flash_init_device(&nand_flash_config, &handle);
50+
51+
// Use direct NAND operations
52+
spi_nand_flash_read_sector(handle, buffer, sector_id);
53+
spi_nand_flash_write_sector(handle, buffer, sector_id);
54+
55+
// Cleanup
56+
spi_nand_flash_deinit_device(handle);
57+
```
58+
59+
#### Option 2: Block Device API
60+
```c
61+
// Initialize with block device interface
62+
nand_file_mmap_emul_config_t cfg = {"", 50 * 1024 * 1024, false};
63+
spi_nand_flash_config_t nand_flash_config = {&cfg, 0, SPI_NAND_IO_MODE_SIO, 0};
64+
65+
spi_nand_flash_device_t *device_handle;
66+
esp_blockdev_handle_t nand_bdl;
67+
68+
// Create Flash Block Device Layer
69+
nand_flash_get_blockdev(&nand_flash_config, &device_handle, &nand_bdl);
4970
50-
// Use NAND operations...
71+
// Use block device operations
72+
nand_bdl->ops->read(nand_bdl, buffer, sector_size, offset, size);
73+
nand_bdl->ops->write(nand_bdl, buffer, offset, size);
5174
5275
// Cleanup
53-
ESP_ERROR_CHECK(spi_nand_flash_deinit_device(handle));
76+
nand_bdl->ops->release(nand_bdl);
5477
```

0 commit comments

Comments
 (0)