Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/build_and_run_apps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,8 @@ jobs:
*/examples/*/build_linux*/config/sdkconfig.json
*/test_app*/**/build_linux*/*.elf
*/test_app*/**/build_linux*/config/sdkconfig.json
*/host_test/**/build_linux*/*.elf
*/host_test/**/build_linux*/config/sdkconfig.json
build_info*.json

run-target:
Expand Down Expand Up @@ -291,6 +293,7 @@ jobs:
chmod +x */examples/*/build_linux*/*.elf || echo "No example .elf files found"
shopt -s globstar
chmod +x */test_app*/**/build_linux*/*.elf || echo "No test_app .elf files found"
chmod +x */host_test/**/build_linux*/*.elf || echo "No host_test .elf files found"
- name: Run apps
shell: bash
run: |
Expand Down
5 changes: 4 additions & 1 deletion spi_nand_flash/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
## [0.18.0]
## [0.19.0]
- fix: spi_nand_program_load fails in case buffer is not DMA aligned (https://github.com/espressif/idf-extra-components/issues/684)

## [0.18.0]
- fix: Update esp_vfs_fat_register prototype to esp_vfs_fat_register_cfg to align with ESP-IDF v6.0.
The cfg version is now the primary API and remains aliased for compatibility.

Expand Down
10 changes: 5 additions & 5 deletions spi_nand_flash/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
idf_build_get_property(target IDF_TARGET)

set(reqs fatfs)
set(inc diskio include)
set(inc include)
set(priv_inc priv_include)
set(srcs "src/nand.c"
"src/dhara_glue.c"
"src/nand_impl_wrap.c"
"diskio/diskio_nand.c")
"src/nand_impl_wrap.c")

if(${target} STREQUAL "linux")
list(APPEND srcs "src/nand_impl_linux.c"
Expand All @@ -22,10 +20,12 @@ else()
"src/nand_impl_wrap.c"
"src/nand_diag_api.c"
"src/spi_nand_oper.c"
"diskio/diskio_nand.c"
"vfs/vfs_fat_spinandflash.c")

set(reqs fatfs)
set(priv_reqs vfs esp_mm)
list(APPEND inc vfs)
list(APPEND inc vfs diskio)

if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER "5.3")
list(APPEND reqs esp_driver_spi)
Expand Down
1 change: 1 addition & 0 deletions spi_nand_flash/host_test/sdkconfig.defaults
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
CONFIG_IDF_TARGET="linux"
CONFIG_COMPILER_CXX_EXCEPTIONS=y
CONFIG_MMU_PAGE_SIZE=0X10000
CONFIG_NAND_ENABLE_STATS=y
2 changes: 1 addition & 1 deletion spi_nand_flash/idf_component.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version: "0.18.0"
version: "0.19.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
Expand Down
1 change: 1 addition & 0 deletions spi_nand_flash/priv_include/spi_nand_oper.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ typedef struct spi_nand_transaction_t spi_nand_transaction_t;
#define STAT_ECC1 1 << 5
#define STAT_ECC2 1 << 6

size_t spi_nand_get_dma_alignment(void);
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_nand_flash_device_t *handle, uint8_t reg, uint8_t *val);
Expand Down
9 changes: 8 additions & 1 deletion spi_nand_flash/src/nand.c
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,11 @@ esp_err_t spi_nand_flash_init_device(spi_nand_flash_config_t *config, spi_nand_f
(*handle)->read_buffer = heap_caps_malloc((*handle)->chip.page_size, MALLOC_CAP_DMA | MALLOC_CAP_8BIT);
ESP_GOTO_ON_FALSE((*handle)->read_buffer != NULL, ESP_ERR_NO_MEM, fail, TAG, "nomem");

(*handle)->temp_buffer = heap_caps_malloc((*handle)->chip.page_size + 4, MALLOC_CAP_DMA | MALLOC_CAP_8BIT);
#ifndef CONFIG_IDF_TARGET_LINUX
size_t dma_alignment = spi_nand_get_dma_alignment();
(*handle)->temp_buffer = heap_caps_aligned_alloc(dma_alignment, (*handle)->chip.page_size + dma_alignment, MALLOC_CAP_DMA | MALLOC_CAP_8BIT);
ESP_GOTO_ON_FALSE((*handle)->temp_buffer != NULL, ESP_ERR_NO_MEM, fail, TAG, "nomem");
#endif

(*handle)->mutex = xSemaphoreCreateMutex();
if (!(*handle)->mutex) {
Expand All @@ -199,7 +202,9 @@ esp_err_t spi_nand_flash_init_device(spi_nand_flash_config_t *config, spi_nand_f
fail:
free((*handle)->work_buffer);
free((*handle)->read_buffer);
#ifndef CONFIG_IDF_TARGET_LINUX
free((*handle)->temp_buffer);
#endif
if ((*handle)->mutex) {
vSemaphoreDelete((*handle)->mutex);
}
Expand Down Expand Up @@ -337,7 +342,9 @@ esp_err_t spi_nand_flash_deinit_device(spi_nand_flash_device_t *handle)
nand_unregister_dev(handle);
free(handle->work_buffer);
free(handle->read_buffer);
#ifndef CONFIG_IDF_TARGET_LINUX
free(handle->temp_buffer);
#endif
vSemaphoreDelete(handle->mutex);
free(handle);
return ret;
Expand Down
43 changes: 31 additions & 12 deletions spi_nand_flash/src/spi_nand_oper.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <string.h>
#include "spi_nand_oper.h"
#include "driver/spi_master.h"
#include "esp_memory_utils.h"
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE == 1
#include "esp_private/esp_cache_private.h"
#endif
Expand Down Expand Up @@ -102,17 +103,22 @@ esp_err_t spi_nand_read_page(spi_nand_flash_device_t *handle, uint32_t page)
return spi_nand_execute_transaction(handle, &t);
}

static uint16_t check_length_alignment(spi_nand_flash_device_t *handle, uint16_t length)
size_t spi_nand_get_dma_alignment(void)
{
size_t alignment;
uint16_t data_len = length;

#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE == 1
esp_cache_get_alignment(MALLOC_CAP_DMA, &alignment);
#else
// For non-L1CACHE targets, use DMA alignment of 4 bytes
alignment = 4;
#endif
return alignment;
}

static uint16_t check_length_alignment(spi_nand_flash_device_t *handle, uint16_t length)
{
uint16_t data_len = length;
size_t alignment = spi_nand_get_dma_alignment();

bool is_length_unaligned = (length & (alignment - 1)) ? true : false;
if (is_length_unaligned) {
Expand Down Expand Up @@ -294,6 +300,28 @@ esp_err_t spi_nand_program_load(spi_nand_flash_device_t *handle, const uint8_t *
const uint8_t *data_write = data;
uint16_t data_write_len = length;

#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0)
uint16_t aligned_len = check_length_alignment(handle, length);

if (aligned_len == length) {
// Length is already DMA-aligned. If the buffer address is not DMA-capable
// or not aligned, bounce through temp_buffer which is pre-allocated as
// DMA-capable. We can safely set SPI_TRANS_DMA_BUFFER_ALIGN_MANUAL since
// both buffer and length now satisfy DMA requirements.
size_t alignment = spi_nand_get_dma_alignment();
bool buf_dma_ok = esp_ptr_dma_capable(data) && (((uintptr_t)data % alignment) == 0);
if (!buf_dma_ok) {
memcpy(handle->temp_buffer, data, length);
data_write = handle->temp_buffer;
}
spi_flags |= SPI_TRANS_DMA_BUFFER_ALIGN_MANUAL;
}
// When length is not DMA-aligned, we do not set SPI_TRANS_DMA_BUFFER_ALIGN_MANUAL.
// This lets the SPI driver internally allocate an aligned buffer and handle the
// DMA transfer. Unlike reads, we cannot pad the write length to aligned_len here
// because the extra bytes would be programmed into the NAND page, corrupting data.
#endif

spi_nand_transaction_t t = {
.command = cmd,
.address_bytes = 2,
Expand All @@ -303,15 +331,6 @@ esp_err_t spi_nand_program_load(spi_nand_flash_device_t *handle, const uint8_t *
.flags = spi_flags,
};

#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0)
// Check if length needs alignment for DMA
uint16_t aligned_len = check_length_alignment(handle, length);

if (aligned_len == length) {
t.flags |= SPI_TRANS_DMA_BUFFER_ALIGN_MANUAL;
}
#endif

return spi_nand_execute_transaction(handle, &t);
}

Expand Down
Loading