From 3030c3d1ab565026196df4e39dee27756ac77e4b Mon Sep 17 00:00:00 2001 From: "sonika.rathi" Date: Wed, 12 Feb 2025 09:49:38 +0100 Subject: [PATCH] feat(spi_nand_flash): Add support for standard SPI mode (full-duplex) and DIO mode --- spi_nand_flash/Kconfig | 1 + .../main/spi_nand_flash_example_main.c | 8 +- spi_nand_flash/include/spi_nand_flash.h | 8 ++ spi_nand_flash/priv_include/spi_nand_oper.h | 20 ++-- spi_nand_flash/src/nand.c | 6 +- spi_nand_flash/src/nand_alliance.c | 5 +- spi_nand_flash/src/nand_gigadevice.c | 5 +- spi_nand_flash/src/nand_impl.c | 52 ++++----- spi_nand_flash/src/nand_micron.c | 5 +- spi_nand_flash/src/nand_winbond.c | 5 +- spi_nand_flash/src/spi_nand_oper.c | 106 ++++++++++++++---- .../test_app/main/test_spi_nand_flash.c | 50 +++++++-- 12 files changed, 193 insertions(+), 78 deletions(-) diff --git a/spi_nand_flash/Kconfig b/spi_nand_flash/Kconfig index 4bfdee2913..f0dd6b201a 100644 --- a/spi_nand_flash/Kconfig +++ b/spi_nand_flash/Kconfig @@ -7,4 +7,5 @@ menu "SPI NAND Flash configuration" If this option is enabled, any time SPI NAND flash is written then the data will be read back and verified. This can catch hardware problems with SPI NAND flash, or flash which was not erased before verification. + endmenu diff --git a/spi_nand_flash/examples/nand_flash/main/spi_nand_flash_example_main.c b/spi_nand_flash/examples/nand_flash/main/spi_nand_flash_example_main.c index 22b684bc72..064cb1b62f 100644 --- a/spi_nand_flash/examples/nand_flash/main/spi_nand_flash_example_main.c +++ b/spi_nand_flash/examples/nand_flash/main/spi_nand_flash_example_main.c @@ -56,12 +56,16 @@ static void example_init_nand_flash(spi_nand_flash_device_t **out_handle, spi_de ESP_LOGI(TAG, "DMA CHANNEL: %d", SPI_DMA_CHAN); ESP_ERROR_CHECK(spi_bus_initialize(HOST_ID, &bus_config, SPI_DMA_CHAN)); + // spi_flags = SPI_DEVICE_HALFDUPLEX -> half duplex + // spi_flags = 0 -> full_duplex + const uint32_t spi_flags = SPI_DEVICE_HALFDUPLEX; + 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, + .flags = spi_flags, }; spi_device_handle_t spi; @@ -69,6 +73,8 @@ static void example_init_nand_flash(spi_nand_flash_device_t **out_handle, spi_de spi_nand_flash_config_t nand_flash_config = { .device_handle = spi, + .io_mode = SPI_NAND_IO_MODE_SIO, + .flags = spi_flags, }; spi_nand_flash_device_t *nand_flash_device_handle; ESP_ERROR_CHECK(spi_nand_flash_init_device(&nand_flash_config, &nand_flash_device_handle)); diff --git a/spi_nand_flash/include/spi_nand_flash.h b/spi_nand_flash/include/spi_nand_flash.h index a11f1ed395..12eb3ccc9d 100644 --- a/spi_nand_flash/include/spi_nand_flash.h +++ b/spi_nand_flash/include/spi_nand_flash.h @@ -17,6 +17,12 @@ extern "C" { #endif +typedef enum { + SPI_NAND_IO_MODE_SIO = 0, + SPI_NAND_IO_MODE_DOUT, + SPI_NAND_IO_MODE_DIO, +} spi_nand_flash_io_mode_t; + /** @brief Structure to describe how to configure the nand access layer. @note The spi_device_handle_t must be initialized with the flag SPI_DEVICE_HALFDUPLEX */ @@ -24,6 +30,8 @@ struct spi_nand_flash_config_t { spi_device_handle_t device_handle; ///< SPI Device for this nand chip. uint8_t gc_factor; ///< The gc factor controls the number of blocks to spare block ratio. ///< Lower values will reduce the available space but increase performance + spi_nand_flash_io_mode_t io_mode; ///< set io mode for SPI NAND communication + uint8_t flags; ///< set flag with SPI_DEVICE_HALFDUPLEX for half duplex communcation. }; typedef struct spi_nand_flash_config_t spi_nand_flash_config_t; diff --git a/spi_nand_flash/priv_include/spi_nand_oper.h b/spi_nand_flash/priv_include/spi_nand_oper.h index 39036fd897..531d249df6 100644 --- a/spi_nand_flash/priv_include/spi_nand_oper.h +++ b/spi_nand_flash/priv_include/spi_nand_oper.h @@ -11,6 +11,7 @@ #include #include #include +#include "nand.h" #ifdef __cplusplus extern "C" { @@ -42,6 +43,7 @@ typedef struct spi_nand_transaction_t spi_nand_transaction_t; #define CMD_READ_X2 0x3B #define CMD_READ_X4 0x6B #define CMD_ERASE_BLOCK 0xD8 +#define CMD_READ_DIO 0xBB #define REG_PROTECT 0xA0 #define REG_CONFIG 0xB0 @@ -55,16 +57,16 @@ typedef struct spi_nand_transaction_t spi_nand_transaction_t; #define STAT_ECC1 1 << 5 #define STAT_ECC2 1 << 6 -esp_err_t spi_nand_execute_transaction(spi_device_handle_t device, spi_nand_transaction_t *transaction); +esp_err_t spi_nand_execute_transaction(spi_nand_flash_device_t *handle, spi_nand_transaction_t *transaction); -esp_err_t spi_nand_read_register(spi_device_handle_t device, uint8_t reg, uint8_t *val); -esp_err_t spi_nand_write_register(spi_device_handle_t device, uint8_t reg, uint8_t val); -esp_err_t spi_nand_write_enable(spi_device_handle_t device); -esp_err_t spi_nand_read_page(spi_device_handle_t device, uint32_t page); -esp_err_t spi_nand_read(spi_device_handle_t device, uint8_t *data, uint16_t column, uint16_t length); -esp_err_t spi_nand_program_execute(spi_device_handle_t device, uint32_t page); -esp_err_t spi_nand_program_load(spi_device_handle_t device, const uint8_t *data, uint16_t column, uint16_t length); -esp_err_t spi_nand_erase_block(spi_device_handle_t device, uint32_t page); +esp_err_t spi_nand_read_register(spi_nand_flash_device_t *handle, uint8_t reg, uint8_t *val); +esp_err_t spi_nand_write_register(spi_nand_flash_device_t *handle, uint8_t reg, uint8_t val); +esp_err_t spi_nand_write_enable(spi_nand_flash_device_t *handle); +esp_err_t spi_nand_read_page(spi_nand_flash_device_t *handle, uint32_t page); +esp_err_t spi_nand_read(spi_nand_flash_device_t *handle, uint8_t *data, uint16_t column, uint16_t length); +esp_err_t spi_nand_program_execute(spi_nand_flash_device_t *handle, uint32_t page); +esp_err_t spi_nand_program_load(spi_nand_flash_device_t *handle, const uint8_t *data, uint16_t column, uint16_t length); +esp_err_t spi_nand_erase_block(spi_nand_flash_device_t *handle, uint32_t page); #ifdef __cplusplus } diff --git a/spi_nand_flash/src/nand.c b/spi_nand_flash/src/nand.c index 38256b5485..92100835d3 100644 --- a/spi_nand_flash/src/nand.c +++ b/spi_nand_flash/src/nand.c @@ -29,7 +29,7 @@ static esp_err_t detect_chip(spi_nand_flash_device_t *dev) .miso_data = &manufacturer_id, .flags = SPI_TRANS_USE_RXDATA, }; - spi_nand_execute_transaction(dev->config.device_handle, &t); + spi_nand_execute_transaction(dev, &t); ESP_LOGD(TAG, "%s: manufacturer_id: %x\n", __func__, manufacturer_id); switch (manufacturer_id) { @@ -49,13 +49,13 @@ static esp_err_t detect_chip(spi_nand_flash_device_t *dev) static esp_err_t unprotect_chip(spi_nand_flash_device_t *dev) { uint8_t status; - esp_err_t ret = spi_nand_read_register(dev->config.device_handle, REG_PROTECT, &status); + esp_err_t ret = spi_nand_read_register(dev, REG_PROTECT, &status); if (ret != ESP_OK) { return ret; } if (status != 0x00) { - ret = spi_nand_write_register(dev->config.device_handle, REG_PROTECT, 0); + ret = spi_nand_write_register(dev, REG_PROTECT, 0); } return ret; diff --git a/spi_nand_flash/src/nand_alliance.c b/spi_nand_flash/src/nand_alliance.c index fee26fa5db..1de761df06 100644 --- a/spi_nand_flash/src/nand_alliance.c +++ b/spi_nand_flash/src/nand_alliance.c @@ -18,13 +18,12 @@ esp_err_t spi_nand_alliance_init(spi_nand_flash_device_t *dev) spi_nand_transaction_t t = { .command = CMD_READ_ID, .address = 1, - .address_bytes = 1, - .dummy_bits = 8, + .address_bytes = 2, .miso_len = 1, .miso_data = &device_id, .flags = SPI_TRANS_USE_RXDATA, }; - spi_nand_execute_transaction(dev->config.device_handle, &t); + spi_nand_execute_transaction(dev, &t); dev->chip.erase_block_delay_us = 3000; dev->chip.program_page_delay_us = 630; ESP_LOGD(TAG, "%s: device_id: %x\n", __func__, device_id); diff --git a/spi_nand_flash/src/nand_gigadevice.c b/spi_nand_flash/src/nand_gigadevice.c index 0bc9947039..19231de4e9 100644 --- a/spi_nand_flash/src/nand_gigadevice.c +++ b/spi_nand_flash/src/nand_gigadevice.c @@ -17,12 +17,13 @@ esp_err_t spi_nand_gigadevice_init(spi_nand_flash_device_t *dev) uint8_t device_id; spi_nand_transaction_t t = { .command = CMD_READ_ID, - .dummy_bits = 16, + .address = 0, + .address_bytes = 2, .miso_len = 1, .miso_data = &device_id, .flags = SPI_TRANS_USE_RXDATA, }; - spi_nand_execute_transaction(dev->config.device_handle, &t); + spi_nand_execute_transaction(dev, &t); dev->chip.read_page_delay_us = 25; dev->chip.erase_block_delay_us = 3200; dev->chip.program_page_delay_us = 380; diff --git a/spi_nand_flash/src/nand_impl.c b/spi_nand_flash/src/nand_impl.c index 23f5ed243a..f54463d26c 100644 --- a/spi_nand_flash/src/nand_impl.c +++ b/spi_nand_flash/src/nand_impl.c @@ -23,7 +23,7 @@ static esp_err_t s_verify_write(spi_nand_flash_device_t *handle, const uint8_t * uint8_t *temp_buf = NULL; temp_buf = heap_caps_malloc(length, MALLOC_CAP_DMA | MALLOC_CAP_8BIT); ESP_RETURN_ON_FALSE(temp_buf != NULL, ESP_ERR_NO_MEM, TAG, "nomem"); - if (spi_nand_read(handle->config.device_handle, temp_buf, offset, length)) { + if (spi_nand_read(handle, temp_buf, offset, length)) { ESP_LOGE(TAG, "%s: Failed to read nand flash to verify previous write", __func__); free(temp_buf); return ESP_FAIL; @@ -39,7 +39,7 @@ static esp_err_t s_verify_write(spi_nand_flash_device_t *handle, const uint8_t * } #endif //CONFIG_NAND_FLASH_VERIFY_WRITE -static esp_err_t wait_for_ready(spi_device_handle_t device, uint32_t expected_operation_time_us, uint8_t *status_out) +static esp_err_t wait_for_ready(spi_nand_flash_device_t *dev, uint32_t expected_operation_time_us, uint8_t *status_out) { if (expected_operation_time_us < ROM_WAIT_THRESHOLD_US) { esp_rom_delay_us(expected_operation_time_us); @@ -47,7 +47,7 @@ static esp_err_t wait_for_ready(spi_device_handle_t device, uint32_t expected_op while (true) { uint8_t status; - ESP_RETURN_ON_ERROR(spi_nand_read_register(device, REG_STATUS, &status), TAG, ""); + ESP_RETURN_ON_ERROR(spi_nand_read_register(dev, REG_STATUS, &status), TAG, ""); if ((status & STAT_BUSY) == 0) { if (status_out) { @@ -66,16 +66,16 @@ static esp_err_t wait_for_ready(spi_device_handle_t device, uint32_t expected_op static esp_err_t read_page_and_wait(spi_nand_flash_device_t *dev, uint32_t page, uint8_t *status_out) { - ESP_RETURN_ON_ERROR(spi_nand_read_page(dev->config.device_handle, page), TAG, ""); + ESP_RETURN_ON_ERROR(spi_nand_read_page(dev, page), TAG, ""); - return wait_for_ready(dev->config.device_handle, dev->chip.read_page_delay_us, status_out); + return wait_for_ready(dev, dev->chip.read_page_delay_us, status_out); } static esp_err_t program_execute_and_wait(spi_nand_flash_device_t *dev, uint32_t page, uint8_t *status_out) { - ESP_RETURN_ON_ERROR(spi_nand_program_execute(dev->config.device_handle, page), TAG, ""); + ESP_RETURN_ON_ERROR(spi_nand_program_execute(dev, page), TAG, ""); - return wait_for_ready(dev->config.device_handle, dev->chip.program_page_delay_us, status_out); + return wait_for_ready(dev, dev->chip.program_page_delay_us, status_out); } esp_err_t nand_is_bad(spi_nand_flash_device_t *handle, uint32_t block, bool *is_bad_status) @@ -87,7 +87,7 @@ esp_err_t nand_is_bad(spi_nand_flash_device_t *handle, uint32_t block, bool *is_ ESP_GOTO_ON_ERROR(read_page_and_wait(handle, first_block_page, NULL), fail, TAG, ""); // Read the first 2 bytes on the OOB of the first page in the block. This should be 0xFFFF for a good block - ESP_GOTO_ON_ERROR(spi_nand_read(handle->config.device_handle, (uint8_t *) &bad_block_indicator, handle->chip.page_size, 2), + ESP_GOTO_ON_ERROR(spi_nand_read(handle, (uint8_t *) &bad_block_indicator, handle->chip.page_size, 2), fail, TAG, ""); ESP_LOGD(TAG, "is_bad, block=%"PRIu32", page=%"PRIu32",indicator = %04x", block, first_block_page, bad_block_indicator); @@ -113,18 +113,18 @@ esp_err_t nand_mark_bad(spi_nand_flash_device_t *handle, uint32_t block) ESP_LOGD(TAG, "mark_bad, block=%"PRIu32", page=%"PRIu32",indicator = %04x", block, first_block_page, bad_block_indicator); ESP_GOTO_ON_ERROR(read_page_and_wait(handle, first_block_page, NULL), fail, TAG, ""); - ESP_GOTO_ON_ERROR(spi_nand_write_enable(handle->config.device_handle), fail, TAG, ""); - ESP_GOTO_ON_ERROR(spi_nand_erase_block(handle->config.device_handle, first_block_page), + ESP_GOTO_ON_ERROR(spi_nand_write_enable(handle), fail, TAG, ""); + ESP_GOTO_ON_ERROR(spi_nand_erase_block(handle, first_block_page), fail, TAG, ""); - ESP_GOTO_ON_ERROR(wait_for_ready(handle->config.device_handle, handle->chip.erase_block_delay_us, &status), + ESP_GOTO_ON_ERROR(wait_for_ready(handle, handle->chip.erase_block_delay_us, &status), fail, TAG, ""); if ((status & STAT_ERASE_FAILED) != 0) { ret = ESP_ERR_NOT_FINISHED; goto fail; } - ESP_GOTO_ON_ERROR(spi_nand_write_enable(handle->config.device_handle), fail, TAG, ""); - ESP_GOTO_ON_ERROR(spi_nand_program_load(handle->config.device_handle, (const uint8_t *) &bad_block_indicator, + ESP_GOTO_ON_ERROR(spi_nand_write_enable(handle), fail, TAG, ""); + ESP_GOTO_ON_ERROR(spi_nand_program_load(handle, (const uint8_t *) &bad_block_indicator, handle->chip.page_size, 2), fail, TAG, ""); ESP_GOTO_ON_ERROR(program_execute_and_wait(handle, first_block_page, NULL), fail, TAG, ""); @@ -147,10 +147,10 @@ esp_err_t nand_erase_chip(spi_nand_flash_device_t *handle) uint8_t status; for (int i = 0; i < handle->chip.num_blocks; i++) { - ESP_GOTO_ON_ERROR(spi_nand_write_enable(handle->config.device_handle), end, TAG, ""); - ESP_GOTO_ON_ERROR(spi_nand_erase_block(handle->config.device_handle, i * (1 << handle->chip.log2_ppb)), + ESP_GOTO_ON_ERROR(spi_nand_write_enable(handle), end, TAG, ""); + ESP_GOTO_ON_ERROR(spi_nand_erase_block(handle, i * (1 << handle->chip.log2_ppb)), end, TAG, ""); - ESP_GOTO_ON_ERROR(wait_for_ready(handle->config.device_handle, handle->chip.erase_block_delay_us, &status), + ESP_GOTO_ON_ERROR(wait_for_ready(handle, handle->chip.erase_block_delay_us, &status), end, TAG, ""); if ((status & STAT_ERASE_FAILED) != 0) { ret = ESP_ERR_NOT_FINISHED; @@ -171,10 +171,10 @@ esp_err_t nand_erase_block(spi_nand_flash_device_t *handle, uint32_t block) uint32_t first_block_page = block * (1 << handle->chip.log2_ppb); - ESP_GOTO_ON_ERROR(spi_nand_write_enable(handle->config.device_handle), fail, TAG, ""); - ESP_GOTO_ON_ERROR(spi_nand_erase_block(handle->config.device_handle, first_block_page), + ESP_GOTO_ON_ERROR(spi_nand_write_enable(handle), fail, TAG, ""); + ESP_GOTO_ON_ERROR(spi_nand_erase_block(handle, first_block_page), fail, TAG, ""); - ESP_GOTO_ON_ERROR(wait_for_ready(handle->config.device_handle, + ESP_GOTO_ON_ERROR(wait_for_ready(handle, handle->chip.erase_block_delay_us, &status), fail, TAG, ""); @@ -196,10 +196,10 @@ esp_err_t nand_prog(spi_nand_flash_device_t *handle, uint32_t page, const uint8_ uint8_t status; ESP_GOTO_ON_ERROR(read_page_and_wait(handle, page, NULL), fail, TAG, ""); - ESP_GOTO_ON_ERROR(spi_nand_write_enable(handle->config.device_handle), fail, TAG, ""); - ESP_GOTO_ON_ERROR(spi_nand_program_load(handle->config.device_handle, data, 0, handle->chip.page_size), + ESP_GOTO_ON_ERROR(spi_nand_write_enable(handle), fail, TAG, ""); + ESP_GOTO_ON_ERROR(spi_nand_program_load(handle, data, 0, handle->chip.page_size), fail, TAG, ""); - ESP_GOTO_ON_ERROR(spi_nand_program_load(handle->config.device_handle, (uint8_t *)&used_marker, + ESP_GOTO_ON_ERROR(spi_nand_program_load(handle, (uint8_t *)&used_marker, handle->chip.page_size + 2, 2), fail, TAG, ""); ESP_GOTO_ON_ERROR(program_execute_and_wait(handle, page, &status), fail, TAG, ""); @@ -232,7 +232,7 @@ esp_err_t nand_is_free(spi_nand_flash_device_t *handle, uint32_t page, bool *is_ uint16_t used_marker; ESP_GOTO_ON_ERROR(read_page_and_wait(handle, page, NULL), fail, TAG, ""); - ESP_GOTO_ON_ERROR(spi_nand_read(handle->config.device_handle, (uint8_t *)&used_marker, + ESP_GOTO_ON_ERROR(spi_nand_read(handle, (uint8_t *)&used_marker, handle->chip.page_size + 2, 2), fail, TAG, ""); @@ -288,7 +288,7 @@ esp_err_t nand_read(spi_nand_flash_device_t *handle, uint32_t page, size_t offse return ESP_FAIL; } - ESP_GOTO_ON_ERROR(spi_nand_read(handle->config.device_handle, data, offset, length), fail, TAG, ""); + ESP_GOTO_ON_ERROR(spi_nand_read(handle, data, offset, length), fail, TAG, ""); return ret; fail: @@ -312,7 +312,7 @@ esp_err_t nand_copy(spi_nand_flash_device_t *handle, uint32_t src, uint32_t dst) return ESP_FAIL; } - ESP_GOTO_ON_ERROR(spi_nand_write_enable(handle->config.device_handle), fail, TAG, ""); + ESP_GOTO_ON_ERROR(spi_nand_write_enable(handle), fail, TAG, ""); ESP_GOTO_ON_ERROR(program_execute_and_wait(handle, dst, &status), fail, TAG, ""); if ((status & STAT_PROGRAM_FAILED) != 0) { @@ -324,7 +324,7 @@ esp_err_t nand_copy(spi_nand_flash_device_t *handle, uint32_t src, uint32_t dst) // First read src page data from cache to temp_buf temp_buf = heap_caps_malloc(handle->chip.page_size, MALLOC_CAP_DMA | MALLOC_CAP_8BIT); ESP_RETURN_ON_FALSE(temp_buf != NULL, ESP_ERR_NO_MEM, TAG, "nomem"); - if (spi_nand_read(handle->config.device_handle, temp_buf, 0, handle->chip.page_size)) { + if (spi_nand_read(handle, temp_buf, 0, handle->chip.page_size)) { ESP_LOGE(TAG, "%s: Failed to read src_page=%"PRIu32"", __func__, src); goto fail; } diff --git a/spi_nand_flash/src/nand_micron.c b/spi_nand_flash/src/nand_micron.c index 01a0f6ea2d..b397bc7822 100644 --- a/spi_nand_flash/src/nand_micron.c +++ b/spi_nand_flash/src/nand_micron.c @@ -17,12 +17,13 @@ esp_err_t spi_nand_micron_init(spi_nand_flash_device_t *dev) uint8_t device_id; spi_nand_transaction_t t = { .command = CMD_READ_ID, - .dummy_bits = 16, + .address = 0, + .address_bytes = 2, .miso_len = 1, .miso_data = &device_id, .flags = SPI_TRANS_USE_RXDATA, }; - spi_nand_execute_transaction(dev->config.device_handle, &t); + spi_nand_execute_transaction(dev, &t); dev->chip.ecc_data.ecc_status_reg_len_in_bits = 3; dev->chip.erase_block_delay_us = 2000; ESP_LOGD(TAG, "%s: device_id: %x\n", __func__, device_id); diff --git a/spi_nand_flash/src/nand_winbond.c b/spi_nand_flash/src/nand_winbond.c index acf80e3de3..3c5e491217 100644 --- a/spi_nand_flash/src/nand_winbond.c +++ b/spi_nand_flash/src/nand_winbond.c @@ -17,12 +17,13 @@ esp_err_t spi_nand_winbond_init(spi_nand_flash_device_t *dev) uint8_t device_id_buf[2]; spi_nand_transaction_t t = { .command = CMD_READ_ID, - .dummy_bits = 16, + .address = 0, + .address_bytes = 2, .miso_len = 2, .miso_data = device_id_buf, .flags = SPI_TRANS_USE_RXDATA, }; - spi_nand_execute_transaction(dev->config.device_handle, &t); + spi_nand_execute_transaction(dev, &t); uint16_t device_id = (device_id_buf[0] << 8) + device_id_buf[1]; dev->chip.read_page_delay_us = 10; dev->chip.erase_block_delay_us = 2500; diff --git a/spi_nand_flash/src/spi_nand_oper.c b/spi_nand_flash/src/spi_nand_oper.c index 88496a844c..14ab051e2a 100644 --- a/spi_nand_flash/src/spi_nand_oper.c +++ b/spi_nand_flash/src/spi_nand_oper.c @@ -10,8 +10,15 @@ #include "spi_nand_oper.h" #include "driver/spi_master.h" -esp_err_t spi_nand_execute_transaction(spi_device_handle_t device, spi_nand_transaction_t *transaction) +esp_err_t spi_nand_execute_transaction(spi_nand_flash_device_t *handle, spi_nand_transaction_t *transaction) { + uint8_t half_duplex = handle->config.flags & SPI_DEVICE_HALFDUPLEX; + if (!half_duplex) { + uint32_t len = transaction->miso_len > transaction->mosi_len ? transaction->miso_len : transaction->mosi_len; + transaction->miso_len = len; + transaction->mosi_len = len; + } + spi_transaction_ext_t e = { .base = { .flags = SPI_TRANS_VARIABLE_ADDR | SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_DUMMY | transaction->flags, @@ -35,7 +42,7 @@ esp_err_t spi_nand_execute_transaction(spi_device_handle_t device, spi_nand_tran assert(transaction->miso_len <= 4 && "SPI_TRANS_USE_RXDATA used for a long transaction"); } - esp_err_t ret = spi_device_transmit(device, (spi_transaction_t *) &e); + esp_err_t ret = spi_device_transmit(handle->config.device_handle, (spi_transaction_t *) &e); if (ret == ESP_OK) { if (transaction->flags == SPI_TRANS_USE_RXDATA) { memcpy(transaction->miso_data, e.base.rx_data, transaction->miso_len); @@ -44,7 +51,7 @@ esp_err_t spi_nand_execute_transaction(spi_device_handle_t device, spi_nand_tran return ret; } -esp_err_t spi_nand_read_register(spi_device_handle_t device, uint8_t reg, uint8_t *val) +esp_err_t spi_nand_read_register(spi_nand_flash_device_t *handle, uint8_t reg, uint8_t *val) { spi_nand_transaction_t t = { .command = CMD_READ_REGISTER, @@ -55,10 +62,10 @@ esp_err_t spi_nand_read_register(spi_device_handle_t device, uint8_t reg, uint8_ .flags = SPI_TRANS_USE_RXDATA, }; - return spi_nand_execute_transaction(device, &t); + return spi_nand_execute_transaction(handle, &t); } -esp_err_t spi_nand_write_register(spi_device_handle_t device, uint8_t reg, uint8_t val) +esp_err_t spi_nand_write_register(spi_nand_flash_device_t *handle, uint8_t reg, uint8_t val) { spi_nand_transaction_t t = { .command = CMD_SET_REGISTER, @@ -69,19 +76,19 @@ esp_err_t spi_nand_write_register(spi_device_handle_t device, uint8_t reg, uint8 .flags = SPI_TRANS_USE_TXDATA, }; - return spi_nand_execute_transaction(device, &t); + return spi_nand_execute_transaction(handle, &t); } -esp_err_t spi_nand_write_enable(spi_device_handle_t device) +esp_err_t spi_nand_write_enable(spi_nand_flash_device_t *handle) { spi_nand_transaction_t t = { .command = CMD_WRITE_ENABLE }; - return spi_nand_execute_transaction(device, &t); + return spi_nand_execute_transaction(handle, &t); } -esp_err_t spi_nand_read_page(spi_device_handle_t device, uint32_t page) +esp_err_t spi_nand_read_page(spi_nand_flash_device_t *handle, uint32_t page) { spi_nand_transaction_t t = { .command = CMD_PAGE_READ, @@ -89,27 +96,86 @@ esp_err_t spi_nand_read_page(spi_device_handle_t device, uint32_t page) .address = page }; - return spi_nand_execute_transaction(device, &t); + return spi_nand_execute_transaction(handle, &t); } -esp_err_t spi_nand_read(spi_device_handle_t device, uint8_t *data, uint16_t column, uint16_t length) +static esp_err_t spi_nand_dual_read(spi_nand_flash_device_t *handle, uint8_t *data, uint16_t column, uint16_t length) { + uint32_t spi_flags = SPI_TRANS_MODE_DIO; + uint8_t cmd = CMD_READ_X2; + uint8_t dummy_bits = 8; + + if (handle->config.io_mode == SPI_NAND_IO_MODE_DIO) { + spi_flags |= SPI_TRANS_MULTILINE_ADDR; + cmd = CMD_READ_DIO; + dummy_bits = 4; + } + spi_nand_transaction_t t = { - .command = CMD_READ_FAST, + .command = cmd, .address_bytes = 2, .address = column, .miso_len = length, .miso_data = data, - .dummy_bits = 8, + .dummy_bits = dummy_bits, + .flags = spi_flags, + }; + +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0) + t.flags |= SPI_TRANS_DMA_BUFFER_ALIGN_MANUAL; +#endif + return spi_nand_execute_transaction(handle, &t); +} + +static esp_err_t spi_nand_fast_read(spi_nand_flash_device_t *handle, uint8_t *data, uint16_t column, uint16_t length) +{ + uint8_t *data_read = NULL; + uint16_t data_read_len; + uint8_t half_duplex = handle->config.flags & SPI_DEVICE_HALFDUPLEX; + if (half_duplex) { + data_read_len = length; + data_read = data; + } else { + data_read_len = length + 1; + data_read = heap_caps_malloc(data_read_len, MALLOC_CAP_DMA | MALLOC_CAP_8BIT); + } + spi_nand_transaction_t t = { + .command = CMD_READ_FAST, + .address_bytes = 2, + .address = column, + .miso_len = data_read_len, + .miso_data = data_read, #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0) .flags = SPI_TRANS_DMA_BUFFER_ALIGN_MANUAL, #endif }; - return spi_nand_execute_transaction(device, &t); + if (half_duplex) { + t.dummy_bits = 8; + } + esp_err_t ret = spi_nand_execute_transaction(handle, &t); + if (ret != ESP_OK) { + goto fail; + } + if (!half_duplex) { + memcpy(data, data_read + 1, length); + } +fail: + if (!half_duplex) { + free(data_read); + } + return ret; +} + +esp_err_t spi_nand_read(spi_nand_flash_device_t *handle, uint8_t *data, uint16_t column, uint16_t length) +{ + if (handle->config.io_mode == SPI_NAND_IO_MODE_DOUT || handle->config.io_mode == SPI_NAND_IO_MODE_DIO) { + return spi_nand_dual_read(handle, data, column, length); + } + return spi_nand_fast_read(handle, data, column, length); } -esp_err_t spi_nand_program_execute(spi_device_handle_t device, uint32_t page) +esp_err_t spi_nand_program_execute(spi_nand_flash_device_t *handle, uint32_t page) { spi_nand_transaction_t t = { .command = CMD_PROGRAM_EXECUTE, @@ -117,10 +183,10 @@ esp_err_t spi_nand_program_execute(spi_device_handle_t device, uint32_t page) .address = page }; - return spi_nand_execute_transaction(device, &t); + return spi_nand_execute_transaction(handle, &t); } -esp_err_t spi_nand_program_load(spi_device_handle_t device, const uint8_t *data, uint16_t column, uint16_t length) +esp_err_t spi_nand_program_load(spi_nand_flash_device_t *handle, const uint8_t *data, uint16_t column, uint16_t length) { spi_nand_transaction_t t = { .command = CMD_PROGRAM_LOAD, @@ -130,10 +196,10 @@ esp_err_t spi_nand_program_load(spi_device_handle_t device, const uint8_t *data, .mosi_data = data }; - return spi_nand_execute_transaction(device, &t); + return spi_nand_execute_transaction(handle, &t); } -esp_err_t spi_nand_erase_block(spi_device_handle_t device, uint32_t page) +esp_err_t spi_nand_erase_block(spi_nand_flash_device_t *handle, uint32_t page) { spi_nand_transaction_t t = { .command = CMD_ERASE_BLOCK, @@ -141,5 +207,5 @@ esp_err_t spi_nand_erase_block(spi_device_handle_t device, uint32_t page) .address = page }; - return spi_nand_execute_transaction(device, &t); + return spi_nand_execute_transaction(handle, &t); } diff --git a/spi_nand_flash/test_app/main/test_spi_nand_flash.c b/spi_nand_flash/test_app/main/test_spi_nand_flash.c index 7856e2be2e..f151ff6f31 100644 --- a/spi_nand_flash/test_app/main/test_spi_nand_flash.c +++ b/spi_nand_flash/test_app/main/test_spi_nand_flash.c @@ -48,6 +48,10 @@ #define PATTERN_SEED 0x12345678 +// SPI_FLAGS -> SPI_DEVICE_HALFDUPLEX => half-duplex mode +// SPI_FLAGS -> 0 => full-duplex mode +#define SPI_FLAGS SPI_DEVICE_HALFDUPLEX + static void do_single_write_test(spi_nand_flash_device_t *flash, uint32_t start_sec, uint16_t sec_count); static void setup_bus(spi_host_device_t host_id) { @@ -72,19 +76,21 @@ static void setup_chip(spi_device_handle_t *spi) .mode = 0, .spics_io_num = PIN_CS, .queue_size = 10, - .flags = SPI_DEVICE_HALFDUPLEX, + .flags = SPI_FLAGS, }; TEST_ESP_OK(spi_bus_add_device(HOST_ID, &devcfg, spi)); } -static void setup_nand_flash(spi_nand_flash_device_t **out_handle, spi_device_handle_t *spi_handle) +static void setup_nand_flash(spi_nand_flash_device_t **out_handle, spi_device_handle_t *spi_handle, spi_nand_flash_io_mode_t mode) { spi_device_handle_t spi; setup_chip(&spi); spi_nand_flash_config_t nand_flash_config = { .device_handle = spi, + .flags = SPI_FLAGS, + .io_mode = mode, }; spi_nand_flash_device_t *device_handle; TEST_ESP_OK(spi_nand_flash_init_device(&nand_flash_config, &device_handle)); @@ -104,7 +110,7 @@ TEST_CASE("erase nand flash", "[spi_nand_flash]") { spi_nand_flash_device_t *nand_flash_device_handle; spi_device_handle_t spi; - setup_nand_flash(&nand_flash_device_handle, &spi); + setup_nand_flash(&nand_flash_device_handle, &spi, SPI_NAND_IO_MODE_SIO); TEST_ESP_OK(spi_nand_erase_chip(nand_flash_device_handle)); do_single_write_test(nand_flash_device_handle, 1, 1); deinit_nand_flash(nand_flash_device_handle, spi); @@ -175,7 +181,7 @@ TEST_CASE("write nand flash sectors", "[spi_nand_flash]") uint32_t sector_num, sector_size; spi_nand_flash_device_t *nand_flash_device_handle; spi_device_handle_t spi; - setup_nand_flash(&nand_flash_device_handle, &spi); + setup_nand_flash(&nand_flash_device_handle, &spi, SPI_NAND_IO_MODE_SIO); TEST_ESP_OK(spi_nand_flash_get_capacity(nand_flash_device_handle, §or_num)); TEST_ESP_OK(spi_nand_flash_get_sector_size(nand_flash_device_handle, §or_size)); @@ -196,7 +202,7 @@ TEST_CASE("copy nand flash sectors", "[spi_nand_flash]") { spi_nand_flash_device_t *nand_flash_device_handle; spi_device_handle_t spi; - setup_nand_flash(&nand_flash_device_handle, &spi); + setup_nand_flash(&nand_flash_device_handle, &spi, SPI_NAND_IO_MODE_SIO); uint32_t sector_num, sector_size; uint32_t src_sec = 10; uint32_t dst_sec = 11; @@ -216,7 +222,7 @@ TEST_CASE("verify mark_bad_block works", "[spi_nand_flash]") { spi_nand_flash_device_t *nand_flash_device_handle; spi_device_handle_t spi; - setup_nand_flash(&nand_flash_device_handle, &spi); + setup_nand_flash(&nand_flash_device_handle, &spi, SPI_NAND_IO_MODE_SIO); uint32_t sector_num, sector_size; TEST_ESP_OK(spi_nand_flash_get_capacity(nand_flash_device_handle, §or_num)); @@ -239,11 +245,8 @@ TEST_CASE("verify mark_bad_block works", "[spi_nand_flash]") deinit_nand_flash(nand_flash_device_handle, spi); } -TEST_CASE("verify nand_prog, nand_read, nand_copy, nand_is_free works", "[spi_nand_flash]") +static void test_nand_operations(spi_nand_flash_device_t *nand_flash_device_handle) { - spi_nand_flash_device_t *nand_flash_device_handle; - spi_device_handle_t spi; - setup_nand_flash(&nand_flash_device_handle, &spi); uint32_t sector_num, sector_size, block_size; TEST_ESP_OK(spi_nand_flash_get_capacity(nand_flash_device_handle, §or_num)); @@ -262,6 +265,7 @@ TEST_CASE("verify nand_prog, nand_read, nand_copy, nand_is_free works", "[spi_na uint32_t test_block = 20; uint32_t test_page = test_block * (block_size / sector_size); //(block_num * pages_per_block) uint32_t dst_page = test_page + 1; + TEST_ESP_OK(nand_wrap_erase_block(nand_flash_device_handle, test_block)); if (test_page < sector_num) { // Verify if test_page is free TEST_ESP_OK(nand_wrap_is_free(nand_flash_device_handle, test_page, &is_page_free)); @@ -282,5 +286,31 @@ TEST_CASE("verify nand_prog, nand_read, nand_copy, nand_is_free works", "[spi_na } free(pattern_buf); free(temp_buf); +} + +TEST_CASE("verify nand_prog, nand_read, nand_copy, nand_is_free works in SIO and DIO mode", "[spi_nand_flash]") +{ + spi_nand_flash_device_t *nand_flash_device_handle; + spi_device_handle_t spi; + + //setup chip for SIO mode + ESP_LOGI("test", "Starting SIO mode"); + setup_nand_flash(&nand_flash_device_handle, &spi, SPI_NAND_IO_MODE_SIO); + test_nand_operations(nand_flash_device_handle); + do_single_write_test(nand_flash_device_handle, 1, 16); + deinit_nand_flash(nand_flash_device_handle, spi); + + //setup chip for DOUT mode + ESP_LOGI("test", "Starting DOUT mode"); + setup_nand_flash(&nand_flash_device_handle, &spi, SPI_NAND_IO_MODE_DOUT); + test_nand_operations(nand_flash_device_handle); + do_single_write_test(nand_flash_device_handle, 1, 16); + deinit_nand_flash(nand_flash_device_handle, spi); + + //setup chip for DIO mode + ESP_LOGI("test", "Starting DIO mode"); + setup_nand_flash(&nand_flash_device_handle, &spi, SPI_NAND_IO_MODE_DIO); + test_nand_operations(nand_flash_device_handle); + do_single_write_test(nand_flash_device_handle, 1, 16); deinit_nand_flash(nand_flash_device_handle, spi); }