Skip to content

Commit

Permalink
feat(spi_nand_flash): Adding test application for spi_nand_flash comp…
Browse files Browse the repository at this point in the history
…onent
  • Loading branch information
RathiSonika committed Jan 16, 2024
1 parent e5fdd32 commit 68bd5cb
Show file tree
Hide file tree
Showing 28 changed files with 494 additions and 54 deletions.
5 changes: 5 additions & 0 deletions .build-test-rules.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,8 @@ esp_lcd_qemu_rgb/examples/lcd_qemu_rgb_panel:
enable:
- if: ((IDF_VERSION_MAJOR == 5 and IDF_VERSION_MINOR >= 3) or (IDF_VERSION_MAJOR > 5)) and (IDF_TARGET in ["esp32", "esp32c3"])
reason: Example is meant to be run under QEMU, which currently only supports ESP32 and ESP32-C3

spi_nand_flash/examples/nand_flash:
disable:
- if: IDF_VERSION_MAJOR < 5
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.
1 change: 1 addition & 0 deletions .github/workflows/upload_component.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ jobs:
qrcode;
quirc;
sh2lib;
spi_nand_flash;
usb/esp_modem_usb_dte;
usb/esp_tinyusb;
usb/usb_host_cdc_acm;
Expand Down
18 changes: 8 additions & 10 deletions spi_nand_flash/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
if(CONFIG_SPI_FLASH_NAND_ENABLED)
set(srcs "src/nand.c"
"src/spi_nand_oper.c"
"src/dhara_glue.c"
"dhara/dhara/error.c"
"dhara/dhara/journal.c"
"dhara/dhara/map.c"
"vfs/vfs_fat_spinandflash.c"
"diskio/diskio_nand.c")
endif()
set(srcs "src/nand.c"
"src/spi_nand_oper.c"
"src/dhara_glue.c"
"dhara/dhara/error.c"
"dhara/dhara/journal.c"
"dhara/dhara/map.c"
"vfs/vfs_fat_spinandflash.c"
"diskio/diskio_nand.c")

idf_component_register(SRCS ${srcs}
INCLUDE_DIRS include dhara vfs diskio
Expand Down
9 changes: 0 additions & 9 deletions spi_nand_flash/Kconfig

This file was deleted.

12 changes: 5 additions & 7 deletions spi_nand_flash/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# SPI NAND Flash Driver

This driver is designed to support SPI nand flash with ESP chipsets.
This driver is designed to support SPI NAND Flash with ESP chipsets.

This component incorporates the [dhara library](https://github.com/dlbeer/dhara), licenced under the [LICENCE](https://github.com/dlbeer/dhara/blob/master/LICENSE)

## About SPI NAND Flash
SPI NAND Flash combines the benefits of NAND Flash technology with the simplicity of the SPI interface, providing an efficient and cost-effective solution for non-volatile data storage in diverse applications. Its versatility, reliability, and affordability make it a popular choice for many embedded systems and electronic devices.
Expand All @@ -16,14 +18,10 @@ SPI NAND Flash combines the benefits of NAND Flash technology with the simplicit

* Fast Read/Write Operations: The SPI interface enables reasonably fast read and write operations, making it suitable for applications where data access speed is crucial.

## Example

Get started with demo example: [nand_flash](https://github.com/espressif/esp-idf/tree/master/examples/storage/nand_flash)

## Supported SPI NAND Flash chips

At present, ESP-IDF is compatible with the chips produced by following SPI NAND flash manufacturer:
At present, `spi_nand_flash` component is compatible with the chips produced by the following manufacturers:

* Winbond
* Gigadevice
* Alliance
* Alliance
8 changes: 4 additions & 4 deletions spi_nand_flash/diskio/diskio_nand.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,16 +88,16 @@ DRESULT ff_nand_ioctl(BYTE pdrv, BYTE cmd, void *buff)
uint16_t num_sectors;
ESP_GOTO_ON_ERROR(spi_nand_flash_get_capacity(dev, &num_sectors),
fail, TAG, "get_capacity failed");
*((DWORD*)buff) = num_sectors;
ESP_LOGV(TAG, "capacity=%ld", *((DWORD *) buff));
*((DWORD *)buff) = num_sectors;
ESP_LOGV(TAG, "capacity=%"PRIu32"", *((DWORD *) buff));
break;
}
case GET_SECTOR_SIZE: {
uint16_t capacity;
ESP_GOTO_ON_ERROR(spi_nand_flash_get_sector_size(dev, &capacity),
fail, TAG, "get_sector_size failed");
*((WORD*)buff) = capacity;
ESP_LOGV(TAG, "sector size=%d", *((WORD*)buff));
*((WORD *)buff) = capacity;
ESP_LOGV(TAG, "sector size=%d", *((WORD *)buff));
break;
}
default:
Expand Down
4 changes: 2 additions & 2 deletions spi_nand_flash/diskio/diskio_nand.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ extern "C" {
* @param pdrv drive number
* @param device pointer to a nand flash device structure; device should be initialized before calling f_mount.
*/
esp_err_t ff_diskio_register_nand(BYTE pdrv, spi_nand_flash_device_t* device);
esp_err_t ff_diskio_register_nand(BYTE pdrv, spi_nand_flash_device_t *device);

/**
* @brief Get the driver number corresponding to a device
*
* @param device The device for which to return its driver
* @return Driver number of the device
*/
BYTE ff_diskio_get_pdrv_nand(const spi_nand_flash_device_t* device);
BYTE ff_diskio_get_pdrv_nand(const spi_nand_flash_device_t *device);

/**
* @brief Clear a registered nand driver, so it can be reused
Expand Down
8 changes: 8 additions & 0 deletions spi_nand_flash/examples/nand_flash/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# 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)

set(COMPONENTS main)

include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(nand_flash)
2 changes: 2 additions & 0 deletions spi_nand_flash/examples/nand_flash/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
4 changes: 4 additions & 0 deletions spi_nand_flash/examples/nand_flash/main/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
idf_component_register(SRCS "spi_nand_flash_example_main.c"
INCLUDE_DIRS "."
PRIV_REQUIRES spi_nand_flash
)
9 changes: 9 additions & 0 deletions spi_nand_flash/examples/nand_flash/main/Kconfig.projbuild
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
menu "SPI Example Configuration"

config EXAMPLE_FORMAT_IF_MOUNT_FAILED
bool "Format the flash if mount failed"
default n
help
If this config item is set, format_if_mount_failed will be set to true and the card will be formatted if
the mount has failed.
endmenu
4 changes: 4 additions & 0 deletions spi_nand_flash/examples/nand_flash/main/idf_component.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
dependencies:
espressif/spi_nand_flash:
version: '0.1.0'
override_path: '../../../'
148 changes: 148 additions & 0 deletions spi_nand_flash/examples/nand_flash/main/spi_nand_flash_example_main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "esp_vfs.h"
#include "esp_system.h"
#include "soc/spi_pins.h"
#include "esp_vfs_fat_nand.h"

#define EXAMPLE_FLASH_FREQ_KHZ 40000

static const char *TAG = "example";

// Pin mapping
// ESP32 (VSPI)
#ifdef CONFIG_IDF_TARGET_ESP32
#define HOST_ID SPI3_HOST
#define PIN_MOSI SPI3_IOMUX_PIN_NUM_MOSI
#define PIN_MISO SPI3_IOMUX_PIN_NUM_MISO
#define PIN_CLK SPI3_IOMUX_PIN_NUM_CLK
#define PIN_CS SPI3_IOMUX_PIN_NUM_CS
#define PIN_WP SPI3_IOMUX_PIN_NUM_WP
#define PIN_HD SPI3_IOMUX_PIN_NUM_HD
#define SPI_DMA_CHAN SPI_DMA_CH_AUTO
#else // Other chips (SPI2/HSPI)
#define HOST_ID SPI2_HOST
#define PIN_MOSI SPI2_IOMUX_PIN_NUM_MOSI
#define PIN_MISO SPI2_IOMUX_PIN_NUM_MISO
#define PIN_CLK SPI2_IOMUX_PIN_NUM_CLK
#define PIN_CS SPI2_IOMUX_PIN_NUM_CS
#define PIN_WP SPI2_IOMUX_PIN_NUM_WP
#define PIN_HD SPI2_IOMUX_PIN_NUM_HD
#define SPI_DMA_CHAN SPI_DMA_CH_AUTO
#endif

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

static spi_nand_flash_device_t *example_init_nand_flash(void);

void app_main(void)
{
esp_err_t ret;
// Set up SPI bus and initialize the external SPI Flash chip
spi_nand_flash_device_t *flash = example_init_nand_flash();
if (flash == NULL) {
return;
}

esp_vfs_fat_mount_config_t config = {
.max_files = 4,
#ifdef CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED
.format_if_mount_failed = true,
#else
.format_if_mount_failed = false,
#endif
.allocation_unit_size = 16 * 1024
};

ret = esp_vfs_fat_nand_mount(base_path, flash, &config);
if (ret != ESP_OK) {
if (ret == ESP_FAIL) {
ESP_LOGE(TAG, "Failed to mount filesystem. "
"If you want the flash memory to be formatted, set the CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED menuconfig option.");
}
return;
}

// Print FAT FS size information
uint64_t bytes_total, bytes_free;
esp_vfs_fat_info(base_path, &bytes_total, &bytes_free);
ESP_LOGI(TAG, "FAT FS: %" PRIu64 " kB total, %" PRIu64 " kB free", bytes_total / 1024, bytes_free / 1024);

// Create a file in FAT FS
ESP_LOGI(TAG, "Opening file");
FILE *f = fopen("/nandflash/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("/nandflash/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);

esp_vfs_fat_info(base_path, &bytes_total, &bytes_free);
ESP_LOGI(TAG, "FAT FS: %" PRIu64 " kB total, %" PRIu64 " kB free", bytes_total / 1024, bytes_free / 1024);

esp_vfs_fat_nand_unmount(base_path, flash);

spi_nand_flash_deinit_device(flash);
}

static spi_nand_flash_device_t *example_init_nand_flash(void)
{
const spi_bus_config_t bus_config = {
.mosi_io_num = PIN_MOSI,
.miso_io_num = PIN_MISO,
.sclk_io_num = PIN_CLK,
.quadhd_io_num = PIN_HD,
.quadwp_io_num = PIN_WP,
};

// Initialize the SPI bus
ESP_LOGI(TAG, "DMA CHANNEL: %d", SPI_DMA_CHAN);
ESP_ERROR_CHECK(spi_bus_initialize(HOST_ID, &bus_config, SPI_DMA_CHAN));

spi_device_interface_config_t devcfg = {
.clock_speed_hz = EXAMPLE_FLASH_FREQ_KHZ * 1000,
.mode = 0,
.spics_io_num = PIN_CS,
.queue_size = 10,
.flags = SPI_DEVICE_HALFDUPLEX,
};

spi_device_handle_t spi;
spi_bus_add_device(HOST_ID, &devcfg, &spi);

spi_nand_flash_config_t nand_flash_config = {
.device_handle = spi,
};
spi_nand_flash_device_t *nand_flash_device_handle;
ESP_ERROR_CHECK(spi_nand_flash_init_device(&nand_flash_config, &nand_flash_device_handle));

return nand_flash_device_handle;
}
13 changes: 10 additions & 3 deletions spi_nand_flash/idf_component.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
version: "0.0.3"
description: Driver for accessing spi nand flash
version: "0.1.0"
description: Driver for accessing SPI NAND Flash
url: https://github.com/espressif/idf-extra-components/tree/master/spi_nand_flash
issues: https://github.com/espressif/idf-extra-components/issues
repository: https://github.com/espressif/idf-extra-components.git
documentation: https://github.com/espressif/idf-extra-components/tree/main/spi_nand_flash/README.md
dependencies:
idf: ">=5.2"
idf: ">=5.0"
sbom:
manifests:
- path: sbom_dhara.yml
dest: dhara
7 changes: 7 additions & 0 deletions spi_nand_flash/sbom_dhara.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
name: dhara
version: 1b166e41b74b4a62ee6001ba5fab7a8805e80ea2
cpe: cpe:2.3:a:dhara:dhara:{}:*:*:*:*:*:*:*
supplier: 'Organization: dhara'
description: NAND Flash translation layer for small MCUs
url: https://github.com/dlbeer/dhara
hash: 1b166e41b74b4a62ee6001ba5fab7a8805e80ea2
Loading

0 comments on commit 68bd5cb

Please sign in to comment.