Skip to content

Commit

Permalink
feat(spi_nand_flash): Add linux target support
Browse files Browse the repository at this point in the history
  • Loading branch information
RathiSonika committed Jan 30, 2025
1 parent 52be198 commit 5d7dac6
Show file tree
Hide file tree
Showing 16 changed files with 556 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .build-test-rules.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ spi_nand_flash/test_app:
- 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.

spi_nand_flash/host_test:
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.

thorvg/examples/thorvg-example:
enable:
- if: (IDF_VERSION_MAJOR == 5 and IDF_VERSION_MINOR >= 3) and (IDF_TARGET in ["esp32p4"])
Expand Down
26 changes: 22 additions & 4 deletions spi_nand_flash/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
idf_build_get_property(target IDF_TARGET)

set(reqs fatfs)
set(inc diskio include)
set(priv_inc priv_include)

if(${target} STREQUAL "linux")

list(APPEND reqs esp_partition)
set(srcs "src/nand_linux.c"
"src/nand_impl_linux.c"
"src/dhara_glue.c"
"diskio/diskio_nand.c")

else()

set(srcs "src/nand.c"
"src/nand_winbond.c"
"src/nand_gigadevice.c"
Expand All @@ -11,18 +27,20 @@ set(srcs "src/nand.c"
"vfs/vfs_fat_spinandflash.c"
"diskio/diskio_nand.c")

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

if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER "5.3")
list(APPEND reqs esp_driver_spi)
else()
list(APPEND reqs driver)
endif()

set(priv_reqs vfs)
endif()


idf_component_register(SRCS ${srcs}
INCLUDE_DIRS include vfs diskio
PRIV_INCLUDE_DIRS "priv_include"
INCLUDE_DIRS ${inc}
PRIV_INCLUDE_DIRS ${priv_inc}
REQUIRES ${reqs}
PRIV_REQUIRES ${priv_reqs})
3 changes: 2 additions & 1 deletion spi_nand_flash/diskio/diskio_nand.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,11 +133,12 @@ DRESULT ff_nand_ioctl(BYTE pdrv, BYTE cmd, void *buff)
break;
}
#if FF_USE_TRIM
case CTRL_TRIM:
case CTRL_TRIM: {
DWORD start_sector = *((DWORD *)buff);
DWORD end_sector = *((DWORD *)buff + 1) + 1;
DWORD sector_count = end_sector - start_sector;
return ff_nand_trim(pdrv, start_sector, sector_count);
}
#endif //FF_USE_TRIM
default:
return RES_ERROR;
Expand Down
8 changes: 8 additions & 0 deletions spi_nand_flash/host_test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 3.16)

include($ENV{IDF_PATH}/tools/cmake/project.cmake)
set(COMPONENTS main)
# This test doesn't require FreeRTOS, uses a mock instead
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/mocks/freertos/")

project(nand_flash_host_test)
2 changes: 2 additions & 0 deletions spi_nand_flash/host_test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
| Supported Targets | Linux |
| ----------------- | ----- |
8 changes: 8 additions & 0 deletions spi_nand_flash/host_test/main/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
idf_component_register(SRCS "test_nand_flash.cpp"
REQUIRES fatfs
WHOLE_ARCHIVE
)

# Currently 'main' for IDF_TARGET=linux is defined in freertos component.
# Since we are using a freertos mock here, need to let Catch2 provide 'main'.
target_link_libraries(${COMPONENT_LIB} PRIVATE Catch2WithMain)
5 changes: 5 additions & 0 deletions spi_nand_flash/host_test/main/idf_component.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
dependencies:
espressif/catch2: "^3.4.0"
espressif/spi_nand_flash:
version: '*'
override_path: '../../'
98 changes: 98 additions & 0 deletions spi_nand_flash/host_test/main/test_nand_flash.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

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

#include "ff.h"
#include "esp_partition.h"
#include "diskio_impl.h"
#include "diskio_nand.h"
#include "spi_nand_flash.h"

#include <catch2/catch_test_macros.hpp>

TEST_CASE("Create volume, open file, write and read back data", "[fatfs, spi_nand_flash]")
{
FRESULT fr_result;
BYTE pdrv;
FATFS fs;
FIL file;
UINT bw;

esp_err_t esp_result;
spi_nand_flash_config_t nand_flash_config;
spi_nand_flash_device_t *device_handle;
REQUIRE(spi_nand_flash_init_device(&nand_flash_config, &device_handle) == ESP_OK);

// Get a physical drive
esp_result = ff_diskio_get_drive(&pdrv);
REQUIRE(esp_result == ESP_OK);

// Register physical drive as wear-levelled partition
esp_result = ff_diskio_register_nand(pdrv, device_handle);

// Create FAT volume on the entire disk
LBA_t part_list[] = {100, 0, 0, 0};
BYTE work_area[FF_MAX_SS];

fr_result = f_fdisk(pdrv, part_list, work_area);
REQUIRE(fr_result == FR_OK);

char drv[3] = {(char)('0' + pdrv), ':', 0};
const MKFS_PARM opt = {(BYTE)(FM_ANY), 0, 0, 0, 0};
fr_result = f_mkfs(drv, &opt, work_area, sizeof(work_area)); // Use default volume
REQUIRE(fr_result == FR_OK);

// Mount the volume
fr_result = f_mount(&fs, drv, 0);
REQUIRE(fr_result == FR_OK);

// Open, write and read data
fr_result = f_open(&file, "0:/test.txt", FA_OPEN_ALWAYS | FA_READ | FA_WRITE);
REQUIRE(fr_result == FR_OK);

// Generate data
uint32_t data_size = 1000;

char *data = (char *) malloc(data_size);
char *read = (char *) malloc(data_size);

for (uint32_t i = 0; i < data_size; i += sizeof(i)) {
*((uint32_t *)(data + i)) = i;
}

// Write generated data
fr_result = f_write(&file, data, data_size, &bw);
REQUIRE(fr_result == FR_OK);
REQUIRE(bw == data_size);

// Move to beginning of file
fr_result = f_lseek(&file, 0);
REQUIRE(fr_result == FR_OK);

// Read written data
fr_result = f_read(&file, read, data_size, &bw);
REQUIRE(fr_result == FR_OK);
REQUIRE(bw == data_size);

REQUIRE(memcmp(data, read, data_size) == 0);

// Close file
fr_result = f_close(&file);
REQUIRE(fr_result == FR_OK);

// Unmount default volume
fr_result = f_mount(0, drv, 0);
REQUIRE(fr_result == FR_OK);

// Clear
free(read);
free(data);
ff_diskio_unregister(pdrv);
ff_diskio_clear_pdrv_nand(device_handle);
spi_nand_flash_deinit_device(device_handle);
}
6 changes: 6 additions & 0 deletions spi_nand_flash/host_test/partition_table.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 1M,
storage, data, fat, , 8M,
10 changes: 10 additions & 0 deletions spi_nand_flash/host_test/pytest_nand_flash_linux.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
import pytest
from pytest_embedded import Dut


@pytest.mark.linux
@pytest.mark.host_test
def test_nand_flash_linux(dut: Dut) -> None:
dut.expect_exact('All tests passed', timeout=120)
8 changes: 8 additions & 0 deletions spi_nand_flash/host_test/sdkconfig.defaults
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
CONFIG_IDF_TARGET="linux"
CONFIG_COMPILER_CXX_EXCEPTIONS=y
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=n
CONFIG_PARTITION_TABLE_OFFSET=0x8000
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partition_table.csv"
CONFIG_MMU_PAGE_SIZE=0X10000
CONFIG_ESP_PARTITION_ENABLE_STATS=y
4 changes: 4 additions & 0 deletions spi_nand_flash/include/spi_nand_flash.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@

#include <stdint.h>
#include "esp_err.h"
#ifndef CONFIG_IDF_TARGET_LINUX
#include "driver/spi_common.h"
#include "driver/spi_master.h"
#endif

#ifdef __cplusplus
extern "C" {
Expand All @@ -21,7 +23,9 @@ extern "C" {
@note The spi_device_handle_t must be initialized with the flag SPI_DEVICE_HALFDUPLEX
*/
struct spi_nand_flash_config_t {
#ifndef CONFIG_IDF_TARGET_LINUX
spi_device_handle_t device_handle; ///< SPI Device for this nand chip.
#endif
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
};
Expand Down
11 changes: 11 additions & 0 deletions spi_nand_flash/priv_include/nand.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@

#include <stdint.h>
#include "spi_nand_flash.h"
#ifdef CONFIG_IDF_TARGET_LINUX
#include "FreeRTOS.h"
#include "esp_partition.h"
#endif
#include "freertos/semphr.h"

#ifdef __cplusplus
Expand Down Expand Up @@ -40,6 +44,10 @@ typedef struct {
uint8_t log2_ppb; //is power of 2, log2_ppb shift ((1<<log2_ppb) * page_size) will be stored in block size
uint32_t block_size;
uint32_t page_size;
#ifdef CONFIG_IDF_TARGET_LINUX
uint32_t emulated_page_size;
uint32_t emulated_page_oob;
#endif
uint32_t num_blocks;
uint32_t read_page_delay_us;
uint32_t erase_block_delay_us;
Expand Down Expand Up @@ -68,6 +76,9 @@ struct spi_nand_flash_device_t {
uint8_t *work_buffer;
uint8_t *read_buffer;
SemaphoreHandle_t mutex;
#ifdef CONFIG_IDF_TARGET_LINUX
const esp_partition_t *partition;
#endif
};

esp_err_t nand_register_dev(spi_nand_flash_device_t *handle);
Expand Down
2 changes: 2 additions & 0 deletions spi_nand_flash/src/dhara_glue.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
#include "dhara/error.h"
#include "esp_check.h"
#include "esp_err.h"
#ifndef CONFIG_IDF_TARGET_LINUX
#include "spi_nand_oper.h"
#endif
#include "nand_impl.h"
#include "nand.h"

Expand Down
Loading

0 comments on commit 5d7dac6

Please sign in to comment.