-
Notifications
You must be signed in to change notification settings - Fork 95
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #451 from RathiSonika/feat/spi_nand_flash_diagnost…
…ic_app feat(spi_nand_flash): add diagnostics application for NAND flash
- Loading branch information
Showing
17 changed files
with
480 additions
and
41 deletions.
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
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
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,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_debug_app) |
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,51 @@ | ||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | | ||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | | ||
|
||
# SPI NAND Flash debug example | ||
|
||
This example is designed to gather diagnostic statistics for NAND flash, as outlined below: | ||
|
||
1. Bad block statistics. | ||
2. ECC error statistics. | ||
3. Read-write NAND sector throughput (both at the lower level and through the Dhara library). | ||
4. Verification of NAND write operations using the Kconfig option `CONFIG_NAND_FLASH_VERIFY_WRITE`. | ||
|
||
## How to use example | ||
|
||
To run the example, type the following command: | ||
|
||
```CMake | ||
# CMake | ||
idf.py -p PORT flash monitor | ||
``` | ||
|
||
(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 the example's console output: | ||
``` | ||
... | ||
I (353) debug_app: Get bad block statistics: | ||
I (533) nand_diag: | ||
Total number of Blocks: 1024 | ||
Bad Blocks: 1 | ||
Valid Blocks: 1023 | ||
I (533) debug_app: Read-Write Throughput via Dhara: | ||
I (3423) debug_app: Wrote 2048000 bytes in 2269005 us, avg 902.60 kB/s | ||
I (3423) debug_app: Read 2048000 bytes in 617570 us, avg 3316.22 kB/s | ||
I (3423) debug_app: Read-Write Throughput at lower level (bypassing Dhara): | ||
I (5913) debug_app: Wrote 2048000 bytes in 1883853 us, avg 1087.13 kB/s | ||
I (5913) debug_app: Read 2048000 bytes in 585556 us, avg 3497.53 kB/s | ||
I (5913) debug_app: ECC errors statistics: | ||
I (17173) nand_diag: | ||
Total number of ECC errors: 42 | ||
ECC not corrected count: 0 | ||
ECC errors exceeding threshold (4): 0 | ||
... | ||
``` |
4 changes: 4 additions & 0 deletions
4
spi_nand_flash/examples/nand_flash_debug_app/main/CMakeLists.txt
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 @@ | ||
idf_component_register(SRCS "spi_nand_flash_debug_app_main.c" | ||
INCLUDE_DIRS "." | ||
PRIV_REQUIRES spi_nand_flash esp_timer | ||
) |
4 changes: 4 additions & 0 deletions
4
spi_nand_flash/examples/nand_flash_debug_app/main/idf_component.yml
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 @@ | ||
dependencies: | ||
espressif/spi_nand_flash: | ||
version: '*' | ||
override_path: '../../../' |
187 changes: 187 additions & 0 deletions
187
spi_nand_flash/examples/nand_flash_debug_app/main/spi_nand_flash_debug_app_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,187 @@ | ||
/* | ||
* 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_system.h" | ||
#include "soc/spi_pins.h" | ||
#include "spi_nand_flash.h" | ||
#include "nand_diag_api.h" | ||
#include "nand_private/nand_impl_wrap.h" | ||
#include "esp_log.h" | ||
#include "esp_check.h" | ||
#include "esp_timer.h" | ||
|
||
#define EXAMPLE_FLASH_FREQ_KHZ 40000 | ||
#define PATTERN_SEED 0x12345678 | ||
|
||
static const char *TAG = "debug_app"; | ||
|
||
// 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 | ||
|
||
static void example_init_nand_flash(spi_nand_flash_device_t **out_handle, spi_device_handle_t *spi_handle) | ||
{ | ||
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, | ||
.max_transfer_sz = 4096 * 2, | ||
}; | ||
|
||
// 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; | ||
ESP_ERROR_CHECK(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)); | ||
|
||
*out_handle = nand_flash_device_handle; | ||
*spi_handle = spi; | ||
} | ||
|
||
static void example_deinit_nand_flash(spi_nand_flash_device_t *flash, spi_device_handle_t spi) | ||
{ | ||
ESP_ERROR_CHECK(spi_nand_flash_deinit_device(flash)); | ||
ESP_ERROR_CHECK(spi_bus_remove_device(spi)); | ||
ESP_ERROR_CHECK(spi_bus_free(HOST_ID)); | ||
} | ||
|
||
static void fill_buffer(uint32_t seed, uint8_t *dst, size_t count) | ||
{ | ||
srand(seed); | ||
for (size_t i = 0; i < count; ++i) { | ||
uint32_t val = rand(); | ||
memcpy(dst + i * sizeof(uint32_t), &val, sizeof(val)); | ||
} | ||
} | ||
|
||
static esp_err_t read_write_sectors_tp(spi_nand_flash_device_t *flash, uint32_t start_sec, uint16_t sec_count, bool get_raw_tp) | ||
{ | ||
esp_err_t ret = ESP_OK; | ||
uint8_t *temp_buf = NULL; | ||
uint8_t *pattern_buf = NULL; | ||
uint32_t sector_size, sector_num; | ||
|
||
ESP_ERROR_CHECK(spi_nand_flash_get_capacity(flash, §or_num)); | ||
ESP_ERROR_CHECK(spi_nand_flash_get_sector_size(flash, §or_size)); | ||
|
||
ESP_RETURN_ON_FALSE((start_sec + sec_count) < sector_num, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); | ||
|
||
pattern_buf = (uint8_t *)heap_caps_malloc(sector_size, MALLOC_CAP_DEFAULT); | ||
ESP_RETURN_ON_FALSE(pattern_buf != NULL, ESP_ERR_NO_MEM, TAG, "nomem"); | ||
temp_buf = (uint8_t *)heap_caps_malloc(sector_size, MALLOC_CAP_DEFAULT); | ||
ESP_RETURN_ON_FALSE(temp_buf != NULL, ESP_ERR_NO_MEM, TAG, "nomem"); | ||
|
||
fill_buffer(PATTERN_SEED, pattern_buf, sector_size / sizeof(uint32_t)); | ||
|
||
int64_t read_time = 0; | ||
int64_t write_time = 0; | ||
|
||
for (int i = start_sec; i < (start_sec + sec_count); i++) { | ||
int64_t start = esp_timer_get_time(); | ||
if (get_raw_tp) { | ||
ESP_ERROR_CHECK(nand_wrap_prog(flash, i, pattern_buf)); | ||
} else { | ||
ESP_ERROR_CHECK(spi_nand_flash_write_sector(flash, pattern_buf, i)); | ||
} | ||
write_time += esp_timer_get_time() - start; | ||
|
||
memset((void *)temp_buf, 0x00, sector_size); | ||
|
||
start = esp_timer_get_time(); | ||
if (get_raw_tp) { | ||
ESP_ERROR_CHECK(nand_wrap_read(flash, i, 0, sector_size, temp_buf)); | ||
} else { | ||
ESP_ERROR_CHECK(spi_nand_flash_read_sector(flash, temp_buf, i)); | ||
} | ||
read_time += esp_timer_get_time() - start; | ||
} | ||
free(pattern_buf); | ||
free(temp_buf); | ||
|
||
ESP_LOGI(TAG, "Wrote %" PRIu32 " bytes in %" PRId64 " us, avg %.2f kB/s", sector_size * sec_count, write_time, (float)sector_size * sec_count / write_time * 1000); | ||
ESP_LOGI(TAG, "Read %" PRIu32 " bytes in %" PRId64 " us, avg %.2f kB/s\n", sector_size * sec_count, read_time, (float)sector_size * sec_count / read_time * 1000); | ||
return ret; | ||
} | ||
|
||
void app_main(void) | ||
{ | ||
// Set up SPI bus and initialize the external SPI Flash chip | ||
spi_device_handle_t spi; | ||
spi_nand_flash_device_t *flash; | ||
example_init_nand_flash(&flash, &spi); | ||
if (flash == NULL) { | ||
return; | ||
} | ||
|
||
uint32_t num_blocks; | ||
ESP_ERROR_CHECK(spi_nand_flash_get_block_num(flash, &num_blocks)); | ||
|
||
// Get bad block statistics | ||
uint32_t bad_block_count; | ||
ESP_LOGI(TAG, "Get bad block statistics:"); | ||
ESP_ERROR_CHECK(nand_get_bad_block_stats(flash, &bad_block_count)); | ||
ESP_LOGI(TAG, "\nTotal number of Blocks: %"PRIu32"\nBad Blocks: %"PRIu32"\nValid Blocks: %"PRIu32"\n", | ||
num_blocks, bad_block_count, num_blocks - bad_block_count); | ||
|
||
// Calculate read and write throughput via Dhara | ||
uint32_t start_sec = 1; | ||
uint16_t sector_count = 1000; | ||
bool get_raw_tp = false; | ||
ESP_LOGI(TAG, "Read-Write Throughput via Dhara:"); | ||
ESP_ERROR_CHECK(read_write_sectors_tp(flash, start_sec, sector_count, get_raw_tp)); | ||
|
||
// Calculate read and write throughput via Dhara | ||
start_sec = 1001; | ||
sector_count = 1000; | ||
get_raw_tp = true; | ||
ESP_LOGI(TAG, "Read-Write Throughput at lower level (bypassing Dhara):"); | ||
ESP_ERROR_CHECK(read_write_sectors_tp(flash, start_sec, sector_count, get_raw_tp)); | ||
|
||
// Get ECC error statistics | ||
ESP_LOGI(TAG, "ECC errors statistics:"); | ||
ESP_ERROR_CHECK(nand_get_ecc_stats(flash)); | ||
|
||
example_deinit_nand_flash(flash, spi); | ||
} |
10 changes: 10 additions & 0 deletions
10
spi_nand_flash/examples/nand_flash_debug_app/pytest_nand_flash_debug_example.py
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,10 @@ | ||
import pytest | ||
|
||
|
||
@pytest.mark.spi_nand_flash | ||
def test_nand_flash_debug_example(dut) -> None: | ||
dut.expect_exact("Get bad block statistics:") | ||
dut.expect_exact("Read-Write Throughput via Dhara:") | ||
dut.expect_exact("Read-Write Throughput at lower level (bypassing Dhara):") | ||
dut.expect_exact("ECC errors statistics:") | ||
dut.expect_exact("Returned from app_main") |
2 changes: 2 additions & 0 deletions
2
spi_nand_flash/examples/nand_flash_debug_app/sdkconfig.defaults
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,2 @@ | ||
CONFIG_NAND_FLASH_VERIFY_WRITE=y | ||
CONFIG_ESP_TASK_WDT_EN=n |
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
Oops, something went wrong.