Merge branch 'test/fatfs_component_test_apps' into 'master'

fatfs: migrate unit tests to component test app, re-enable test for C2

Closes IDF-5588 and IDF-5136

See merge request espressif/esp-idf!20462
This commit is contained in:
Martin Vychodil 2022-10-06 21:10:39 +08:00
commit 1abd4eac2c
38 changed files with 588 additions and 229 deletions

View File

@ -476,6 +476,38 @@ component_ut_pytest_esp32c3_flash_multi:
- build_pytest_components_esp32c3
tags: [ esp32c3, flash_mutli ]
component_ut_pytest_esp32_sdmmc:
extends:
- .pytest_components_dir_template
- .rules:test:component_ut-esp32
needs:
- build_pytest_components_esp32
tags: [ esp32, sdcard_sdmode ]
component_ut_pytest_esp32_sdspi:
extends:
- .pytest_components_dir_template
- .rules:test:component_ut-esp32
needs:
- build_pytest_components_esp32
tags: [ esp32, sdcard_spimode ]
component_ut_pytest_esp32s2_sdspi:
extends:
- .pytest_components_dir_template
- .rules:test:component_ut-esp32s2
needs:
- build_pytest_components_esp32s2
tags: [ esp32s2, sdcard_spimode ]
component_ut_pytest_esp32c3_sdspi:
extends:
- .pytest_components_dir_template
- .rules:test:component_ut-esp32c3
needs:
- build_pytest_components_esp32c3
tags: [ esp32c3, sdcard_spimode ]
example_test_pytest_openthread_br:
extends:
- .pytest_examples_dir_template

View File

@ -0,0 +1,7 @@
# Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps
components/fatfs/test_apps/sdcard:
disable_test:
- if: IDF_TARGET in ["esp32s3", "esp32c2"]
temporary: true
reason: No sdspi runners for these targets

View File

@ -1,6 +0,0 @@
idf_component_register(SRC_DIRS .
PRIV_INCLUDE_DIRS .
PRIV_REQUIRES cmock test_utils vfs fatfs
EMBED_TXTFILES fatfs.img
)
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")

Binary file not shown.

View File

@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 3.16)
set(COMPONENTS main)
set(EXTRA_COMPONENT_DIRS "${CMAKE_CURRENT_LIST_DIR}/../test_fatfs_common")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(test_fatfs_flash_ro)

View File

@ -0,0 +1,14 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- |
This test app runs a few FATFS test cases in a read-only FAT partition.
These tests should be possible to run on any ESP development board, not extra hardware is necessary.
The initial FAT image is generated during the build process in [main/CMakeLists.txt](main/CMakeLists.txt):
- `create_test_files` function creates a set of files expected by the test cases
- `fatfs_create_rawflash_image` generates a FAT image from the set of files (via `fatfsgen.py`)
The generated FAT image is flashed into `storage` partition when running `idf.py flash`.
See [../README.md](../README.md) for more information about FATFS test apps.

View File

@ -0,0 +1,41 @@
idf_component_register(SRCS "test_fatfs_flash_ro.c"
INCLUDE_DIRS "."
PRIV_REQUIRES unity spi_flash fatfs vfs test_fatfs_common
WHOLE_ARCHIVE)
set(out_dir "${CMAKE_CURRENT_BINARY_DIR}/fatfs_image")
# This helper function creates a set of files expected by the test case.
# The files are then added into the FAT image by 'fatfs_create_rawflash_image' below.
function(create_test_files)
message(STATUS "Generating source files for test_fatfs_flash_ro in ${out_dir}...")
# used in "(raw) can read file"
file(WRITE "${out_dir}/hello.txt" "Hello, World!\n")
# used in "(raw) can open maximum number of files"
foreach(i RANGE 1 32)
file(WRITE "${out_dir}/f/${i}.txt")
endforeach()
# used in "(raw) opendir, readdir, rewinddir, seekdir work as expected"
file(WRITE "${out_dir}/dir/1.txt")
file(WRITE "${out_dir}/dir/2.txt")
file(WRITE "${out_dir}/dir/boo.bin")
file(WRITE "${out_dir}/dir/inner/3.txt")
# used in "(raw) multiple tasks can use same volume"
foreach(i RANGE 1 4)
string(REPEAT "${i}" 32000 file_content)
file(WRITE "${out_dir}/ccrnt/${i}.txt" ${file_content})
endforeach()
# used in "(raw) read speed test"
string(REPEAT "a" 262144 file_content)
file(WRITE "${out_dir}/256k.bin" ${file_content})
endfunction()
create_test_files()
fatfs_create_rawflash_image(storage ${out_dir} FLASH_IN_PROJECT PRESERVE_TIME)

View File

@ -11,53 +11,30 @@
#include <sys/time.h>
#include <sys/unistd.h>
#include "unity.h"
#include "test_utils.h"
#include "esp_log.h"
#include "esp_system.h"
#include "esp_vfs.h"
#include "esp_vfs_fat.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "test_fatfs_common.h"
#include "esp_partition.h"
#include "ff.h"
#include "esp_rom_sys.h"
#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32C2)
//IDF-5136
void app_main(void)
{
unity_run_menu();
}
static void test_setup(size_t max_files)
{
extern const char fatfs_start[] asm("_binary_fatfs_img_start");
extern const char fatfs_end[] asm("_binary_fatfs_img_end");
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
.format_if_mount_failed = false,
.max_files = max_files
};
const esp_partition_t* part = get_test_data_partition();
TEST_ASSERT(part->size == (fatfs_end - fatfs_start - 1));
spi_flash_mmap_handle_t mmap_handle;
const void* mmap_ptr;
TEST_ESP_OK(esp_partition_mmap(part, 0, part->size, SPI_FLASH_MMAP_DATA, &mmap_ptr, &mmap_handle));
bool content_valid = memcmp(fatfs_start, mmap_ptr, part->size) == 0;
spi_flash_munmap(mmap_handle);
if (!content_valid) {
printf("Copying fatfs.img into test partition...\n");
esp_partition_erase_range(part, 0, part->size);
for (int i = 0; i < part->size; i+= SPI_FLASH_SEC_SIZE) {
ESP_ERROR_CHECK( esp_partition_write(part, i, fatfs_start + i, SPI_FLASH_SEC_SIZE) );
}
}
TEST_ESP_OK(esp_vfs_fat_spiflash_mount_ro("/spiflash", "flash_test", &mount_config));
TEST_ESP_OK(esp_vfs_fat_spiflash_mount_ro("/spiflash", "storage", &mount_config));
}
static void test_teardown(void)
{
TEST_ESP_OK(esp_vfs_fat_spiflash_unmount_ro("/spiflash","flash_test"));
TEST_ESP_OK(esp_vfs_fat_spiflash_unmount_ro("/spiflash", "storage"));
}
TEST_CASE("(raw) can read file", "[fatfs]")
@ -94,7 +71,6 @@ TEST_CASE("(raw) can open maximum number of files", "[fatfs]")
}
TEST_CASE("(raw) can lseek", "[fatfs]")
{
test_setup(5);
@ -129,7 +105,7 @@ TEST_CASE("(raw) stat returns correct values", "[fatfs]")
printf("Reference time: %s", asctime(&tm));
struct stat st;
TEST_ASSERT_EQUAL(0, stat("/spiflash/stat.txt", &st));
TEST_ASSERT_EQUAL(0, stat("/spiflash/hello.txt", &st));
time_t mtime = st.st_mtime;
struct tm mtm;
@ -148,8 +124,6 @@ TEST_CASE("(raw) stat returns correct values", "[fatfs]")
test_teardown();
}
TEST_CASE("(raw) can opendir root directory of FS", "[fatfs]")
{
test_setup(5);
@ -161,7 +135,7 @@ TEST_CASE("(raw) can opendir root directory of FS", "[fatfs]")
if (!de) {
break;
}
if (strcasecmp(de->d_name, "test_opd.txt") == 0) {
if (strcasecmp(de->d_name, "hello.txt") == 0) {
found = true;
break;
}
@ -171,6 +145,7 @@ TEST_CASE("(raw) can opendir root directory of FS", "[fatfs]")
test_teardown();
}
TEST_CASE("(raw) opendir, readdir, rewinddir, seekdir work as expected", "[fatfs]")
{
test_setup(5);
@ -229,20 +204,17 @@ TEST_CASE("(raw) opendir, readdir, rewinddir, seekdir work as expected", "[fatfs
test_teardown();
}
typedef struct {
const char* filename;
size_t word_count;
int seed;
int val;
unsigned val;
SemaphoreHandle_t done;
int result;
esp_err_t result;
} read_test_arg_t;
#define READ_TEST_ARG_INIT(name, seed_, val_) \
#define READ_TEST_ARG_INIT(name, val_) \
{ \
.filename = name, \
.seed = seed_, \
.word_count = 8000, \
.val = val_, \
.done = xSemaphoreCreateBinary() \
@ -257,12 +229,11 @@ static void read_task(void* param)
goto done;
}
srand(args->seed);
for (size_t i = 0; i < args->word_count; ++i) {
uint32_t rval;
unsigned rval;
int cnt = fread(&rval, sizeof(rval), 1, f);
if (cnt != 1 || rval != args->val) {
esp_rom_printf("E(r): i=%d, cnt=%d rval=%d val=%d\n\n", i, cnt, rval, args->val);
printf("E(r): i=%d, cnt=%d rval=0x08%x val=0x%08x\n", i, cnt, rval, args->val);
args->result = ESP_FAIL;
goto close;
}
@ -278,7 +249,6 @@ done:
vTaskDelete(NULL);
}
TEST_CASE("(raw) multiple tasks can use same volume", "[fatfs]")
{
test_setup(5);
@ -287,10 +257,10 @@ TEST_CASE("(raw) multiple tasks can use same volume", "[fatfs]")
snprintf(names[i], sizeof(names[i]), "/spiflash/ccrnt/%d.txt", i + 1);
}
read_test_arg_t args1 = READ_TEST_ARG_INIT(names[0], 1, 0x31313131);
read_test_arg_t args2 = READ_TEST_ARG_INIT(names[1], 2, 0x32323232);
read_test_arg_t args3 = READ_TEST_ARG_INIT(names[2], 3, 0x33333333);
read_test_arg_t args4 = READ_TEST_ARG_INIT(names[3], 4, 0x34343434);
read_test_arg_t args1 = READ_TEST_ARG_INIT(names[0], 0x31313131);
read_test_arg_t args2 = READ_TEST_ARG_INIT(names[1], 0x32323232);
read_test_arg_t args3 = READ_TEST_ARG_INIT(names[2], 0x33333333);
read_test_arg_t args4 = READ_TEST_ARG_INIT(names[3], 0x34343434);
const int cpuid_0 = 0;
const int cpuid_1 = portNUM_PROCESSORS - 1;
@ -339,10 +309,3 @@ TEST_CASE("(raw) read speed test", "[fatfs][timeout=60]")
free(buf);
test_teardown();
}
#else //!TEMPORARY_DISABLED_FOR_TARGETS(ESP32C2)
TEST_CASE("FATFS dummy test", "[spi_flash]")
{
printf("This test does nothing, just to make the UT build fatfs-fast-seek passed.\n");
printf("When any case above is supported, remove this test case\n");
}
#endif //!TEMPORARY_DISABLED_FOR_TARGETS(ESP32C2)

View File

@ -0,0 +1,3 @@
# Name, Type, SubType, Offset, Size, Flags
factory, app, factory, 0x10000, 1M,
storage, data, fat, , 528k,
1 # Name Type SubType Offset Size Flags
2 factory app factory 0x10000 1M
3 storage data fat 528k

View File

@ -0,0 +1,15 @@
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded import Dut
@pytest.mark.supported_targets
@pytest.mark.generic
def test_fatfs_flash_ro(dut: Dut) -> None:
dut.expect_exact('Press ENTER to see the list of tests')
dut.write('')
dut.expect_exact('Enter test for running.')
dut.write('*')
dut.expect_unity_test_output()

View File

@ -0,0 +1,14 @@
# General options for additional checks
CONFIG_HEAP_POISONING_COMPREHENSIVE=y
CONFIG_COMPILER_WARN_WRITE_STRINGS=y
CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y
CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y
CONFIG_COMPILER_STACK_CHECK_MODE_STRONG=y
CONFIG_COMPILER_STACK_CHECK=y
# disable task watchdog since this app uses an interactive menu
CONFIG_ESP_TASK_WDT_INIT=n
# use custom partition table
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"

View File

@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 3.16)
set(COMPONENTS main)
set(EXTRA_COMPONENT_DIRS "${CMAKE_CURRENT_LIST_DIR}/../test_fatfs_common")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(test_fatfs_flash_wl)

View File

@ -0,0 +1,8 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- |
This test app runs a few FATFS test cases in a wear levelling FAT partition.
These tests should be possible to run on any ESP development board, not extra hardware is necessary.
See [../README.md](../README.md) for more information about FATFS test apps.

View File

@ -0,0 +1,4 @@
idf_component_register(SRCS "test_fatfs_flash_wl.c"
INCLUDE_DIRS "."
PRIV_REQUIRES unity spi_flash fatfs vfs test_fatfs_common
WHOLE_ARCHIVE)

View File

@ -11,7 +11,7 @@
#include <sys/time.h>
#include <sys/unistd.h>
#include "unity.h"
#include "test_utils.h"
#include "esp_partition.h"
#include "esp_log.h"
#include "esp_random.h"
#include "esp_vfs.h"
@ -23,9 +23,11 @@
#include "esp_partition.h"
#include "esp_memory_utils.h"
void app_main(void)
{
unity_run_menu();
}
#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32C2)
//IDF-5136
static wl_handle_t s_test_wl_handle;
static void test_setup(void)
{
@ -44,7 +46,8 @@ static void test_teardown(void)
TEST_CASE("(WL) can format partition", "[fatfs][wear_levelling]")
{
const esp_partition_t* part = get_test_data_partition();
const esp_partition_t* part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
ESP_PARTITION_SUBTYPE_DATA_FAT, NULL);
esp_partition_erase_range(part, 0, part->size);
test_setup();
test_teardown();
@ -190,7 +193,8 @@ TEST_CASE("(WL) fatfs does not ignore leading spaces", "[fatfs][wear_levelling]"
TEST_CASE("(WL) write/read speed test", "[fatfs][wear_levelling][timeout=60]")
{
/* Erase partition before running the test to get consistent results */
const esp_partition_t* part = get_test_data_partition();
const esp_partition_t* part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
ESP_PARTITION_SUBTYPE_DATA_FAT, NULL);
esp_partition_erase_range(part, 0, part->size);
test_setup();
@ -221,7 +225,6 @@ TEST_CASE("(WL) can get partition info", "[fatfs][wear_levelling]")
test_fatfs_info("/spiflash", "/spiflash/test.txt");
test_teardown();
}
#endif //!TEMPORARY_DISABLED_FOR_TARGETS(ESP32C2)
/*
* In FatFs menuconfig, set CONFIG_FATFS_API_ENCODING to UTF-8 and set the
@ -229,9 +232,6 @@ TEST_CASE("(WL) can get partition info", "[fatfs][wear_levelling]")
* Ensure that the text editor is UTF-8 compatible when compiling these tests.
*/
#if defined(CONFIG_FATFS_API_ENCODING_UTF_8) && (CONFIG_FATFS_CODEPAGE == 936)
#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32C2)
//IDF-5136
TEST_CASE("(WL) can read file with UTF-8 encoded strings", "[fatfs][wear_levelling]")
{
test_setup();
@ -246,7 +246,6 @@ TEST_CASE("(WL) opendir, readdir, rewinddir, seekdir work as expected using UTF-
test_fatfs_opendir_readdir_rewinddir_utf_8("/spiflash/目录");
test_teardown();
}
#endif //!TEMPORARY_DISABLED_FOR_TARGETS(ESP32C2)
#endif //defined(CONFIG_FATFS_API_ENCODING_UTF_8) && (CONFIG_FATFS_CODEPAGE == 936)
#ifdef CONFIG_SPIRAM

View File

@ -0,0 +1,3 @@
# Name, Type, SubType, Offset, Size, Flags
factory, app, factory, 0x10000, 1M,
storage, data, fat, , 528k,
1 # Name Type SubType Offset Size Flags
2 factory app factory 0x10000 1M
3 storage data fat 528k

View File

@ -0,0 +1,39 @@
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded import Dut
@pytest.mark.supported_targets
@pytest.mark.generic
@pytest.mark.parametrize(
'config',
[
'default',
'release',
'fastseek',
]
)
def test_fatfs_flash_wl_generic(dut: Dut) -> None:
dut.expect_exact('Press ENTER to see the list of tests')
dut.write('')
dut.expect_exact('Enter test for running.')
dut.write('*')
dut.expect_unity_test_output(timeout=120)
@pytest.mark.supported_targets
@pytest.mark.psram
@pytest.mark.parametrize(
'config',
[
'psram',
]
)
def test_fatfs_flash_wl_psram(dut: Dut) -> None:
dut.expect_exact('Press ENTER to see the list of tests')
dut.write('')
dut.expect_exact('Enter test for running.')
dut.write('*')
dut.expect_unity_test_output(timeout=120)

View File

@ -1,3 +1,2 @@
TEST_COMPONENTS=fatfs
CONFIG_FATFS_USE_FASTSEEK=y
CONFIG_FATFS_FAST_SEEK_BUFFER_SIZE=64

View File

@ -0,0 +1,3 @@
CONFIG_SPIRAM=y
CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=0
CONFIG_FATFS_ALLOC_PREFER_EXTRAM=y

View File

@ -0,0 +1,2 @@
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y

View File

@ -0,0 +1,18 @@
# General options for additional checks
CONFIG_HEAP_POISONING_COMPREHENSIVE=y
CONFIG_COMPILER_WARN_WRITE_STRINGS=y
CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y
CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y
CONFIG_COMPILER_STACK_CHECK_MODE_STRONG=y
CONFIG_COMPILER_STACK_CHECK=y
# disable task watchdog since this app uses an interactive menu
CONFIG_ESP_TASK_WDT_INIT=n
# use custom partition table
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
# some tests verify file name encoding
CONFIG_FATFS_API_ENCODING_UTF_8=y
CONFIG_FATFS_CODEPAGE_936=y

View File

@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 3.16)
set(COMPONENTS main)
set(EXTRA_COMPONENT_DIRS "${CMAKE_CURRENT_LIST_DIR}/../test_fatfs_common")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(test_fatfs_sdcard)

View File

@ -0,0 +1,14 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- |
This test app runs a few FATFS test cases in a FAT-formatted SD card.
These tests require a development board with an SD card slot:
* ESP32-WROVER-KIT
* ESP32-S2 USB_OTG
* ESP32-C3-DevKit-C with an SD card breakout board
The test cases are split between `[sdmmc]` and `[sdspi]`. Only a few tests are executed for sdspi, though. The app could be refactored to ensure that a similar set of tests runs for sdmmc and sdspi.
See [../README.md](../README.md) for more information about FATFS test apps.

View File

@ -0,0 +1,8 @@
idf_component_register(SRCS "test_fatfs_sdcard_main.c" "test_fatfs_sdspi.c"
INCLUDE_DIRS "."
PRIV_REQUIRES unity fatfs vfs sdmmc driver test_fatfs_common
WHOLE_ARCHIVE)
if(CONFIG_SOC_SDMMC_HOST_SUPPORTED)
target_sources(${COMPONENT_LIB} PRIVATE "test_fatfs_sdmmc.c")
endif()

View File

@ -0,0 +1,11 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include "unity.h"
void app_main(void)
{
unity_run_menu();
}

View File

@ -47,12 +47,10 @@
#endif //SPI_DMA_CHAN
#define SDSPI_HOST_ID SPI2_HOST
#if SOC_SDMMC_HOST_SUPPORTED
#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S3)
// No runner
#include "driver/sdmmc_host.h"
static void test_setup_sdmmc(void)
{
sdmmc_host_t host = SDMMC_HOST_DEFAULT();
@ -72,7 +70,7 @@ static void test_teardown_sdmmc(void)
static const char* test_filename = "/sdcard/hello.txt";
TEST_CASE("Mount fails cleanly without card inserted", "[fatfs][sd][ignore]")
TEST_CASE("Mount fails cleanly without card inserted", "[fatfs][ignore]")
{
size_t heap_size;
HEAP_SIZE_CAPTURE(heap_size);
@ -92,14 +90,14 @@ TEST_CASE("Mount fails cleanly without card inserted", "[fatfs][sd][ignore]")
HEAP_SIZE_CHECK(heap_size, 0);
}
TEST_CASE("(SD) can create and write file", "[fatfs][sd][test_env=UT_T1_SDMODE][timeout=60]")
TEST_CASE("(SD) can create and write file", "[fatfs][sdmmc]")
{
test_setup_sdmmc();
test_fatfs_create_file_with_text(test_filename, fatfs_test_hello_str);
test_teardown_sdmmc();
}
TEST_CASE("(SD) can read file", "[fatfs][test_env=UT_T1_SDMODE][timeout=60]")
TEST_CASE("(SD) can read file", "[fatfs][sdmmc]")
{
test_setup_sdmmc();
test_fatfs_create_file_with_text(test_filename, fatfs_test_hello_str);
@ -107,7 +105,7 @@ TEST_CASE("(SD) can read file", "[fatfs][test_env=UT_T1_SDMODE][timeout=60]")
test_teardown_sdmmc();
}
TEST_CASE("(SD) can read file with pread()", "[fatfs][test_env=UT_T1_SDMODE][timeout=60]")
TEST_CASE("(SD) can read file with pread()", "[fatfs][sdmmc]")
{
test_setup_sdmmc();
test_fatfs_create_file_with_text(test_filename, fatfs_test_hello_str);
@ -115,91 +113,91 @@ TEST_CASE("(SD) can read file with pread()", "[fatfs][test_env=UT_T1_SDMODE][tim
test_teardown_sdmmc();
}
TEST_CASE("(SD) pwrite() works well", "[fatfs][test_env=UT_T1_SDMODE][timeout=60]")
TEST_CASE("(SD) pwrite() works well", "[fatfs][sdmmc]")
{
test_setup_sdmmc();
test_fatfs_pwrite_file(test_filename);
test_teardown_sdmmc();
}
TEST_CASE("(SD) overwrite and append file", "[fatfs][sd][test_env=UT_T1_SDMODE][timeout=60]")
TEST_CASE("(SD) overwrite and append file", "[fatfs][sdmmc]")
{
test_setup_sdmmc();
test_fatfs_overwrite_append(test_filename);
test_teardown_sdmmc();
}
TEST_CASE("(SD) can lseek", "[fatfs][sd][test_env=UT_T1_SDMODE][timeout=60]")
TEST_CASE("(SD) can lseek", "[fatfs][sdmmc]")
{
test_setup_sdmmc();
test_fatfs_lseek("/sdcard/seek.txt");
test_teardown_sdmmc();
}
TEST_CASE("(SD) can truncate", "[fatfs][sd][test_env=UT_T1_SDMODE][timeout=60]")
TEST_CASE("(SD) can truncate", "[fatfs][sdmmc]")
{
test_setup_sdmmc();
test_fatfs_truncate_file("/sdcard/truncate.txt");
test_teardown_sdmmc();
}
TEST_CASE("(SD) can ftruncate", "[fatfs][sd][test_env=UT_T1_SDMODE][timeout=60]")
TEST_CASE("(SD) can ftruncate", "[fatfs][sdmmc]")
{
test_setup_sdmmc();
test_fatfs_ftruncate_file("/sdcard/ftrunc.txt");
test_teardown_sdmmc();
}
TEST_CASE("(SD) stat returns correct values", "[fatfs][test_env=UT_T1_SDMODE][timeout=60]")
TEST_CASE("(SD) stat returns correct values", "[fatfs][sdmmc]")
{
test_setup_sdmmc();
test_fatfs_stat("/sdcard/stat.txt", "/sdcard");
test_teardown_sdmmc();
}
TEST_CASE("(SD) utime sets modification time", "[fatfs][test_env=UT_T1_SDMODE][timeout=60]")
TEST_CASE("(SD) utime sets modification time", "[fatfs][sdmmc]")
{
test_setup_sdmmc();
test_fatfs_utime("/sdcard/utime.txt", "/sdcard");
test_teardown_sdmmc();
}
TEST_CASE("(SD) unlink removes a file", "[fatfs][test_env=UT_T1_SDMODE][timeout=60]")
TEST_CASE("(SD) unlink removes a file", "[fatfs][sdmmc]")
{
test_setup_sdmmc();
test_fatfs_unlink("/sdcard/unlink.txt");
test_teardown_sdmmc();
}
TEST_CASE("(SD) link copies a file, rename moves a file", "[fatfs][test_env=UT_T1_SDMODE][timeout=60]")
TEST_CASE("(SD) link copies a file, rename moves a file", "[fatfs][sdmmc]")
{
test_setup_sdmmc();
test_fatfs_link_rename("/sdcard/link");
test_teardown_sdmmc();
}
TEST_CASE("(SD) can create and remove directories", "[fatfs][test_env=UT_T1_SDMODE][timeout=60]")
TEST_CASE("(SD) can create and remove directories", "[fatfs][sdmmc]")
{
test_setup_sdmmc();
test_fatfs_mkdir_rmdir("/sdcard/dir");
test_teardown_sdmmc();
}
TEST_CASE("(SD) can opendir root directory of FS", "[fatfs][test_env=UT_T1_SDMODE][timeout=60]")
TEST_CASE("(SD) can opendir root directory of FS", "[fatfs][sdmmc]")
{
test_setup_sdmmc();
test_fatfs_can_opendir("/sdcard");
test_teardown_sdmmc();
}
TEST_CASE("(SD) opendir, readdir, rewinddir, seekdir work as expected", "[fatfs][test_env=UT_T1_SDMODE][timeout=60]")
TEST_CASE("(SD) opendir, readdir, rewinddir, seekdir work as expected", "[fatfs][sdmmc]")
{
test_setup_sdmmc();
test_fatfs_opendir_readdir_rewinddir("/sdcard/dir");
test_teardown_sdmmc();
}
TEST_CASE("(SD) multiple tasks can use same volume", "[fatfs][test_env=UT_T1_SDMODE][timeout=60]")
TEST_CASE("(SD) multiple tasks can use same volume", "[fatfs][sdmmc]")
{
test_setup_sdmmc();
test_fatfs_concurrent("/sdcard/f");
@ -208,7 +206,7 @@ TEST_CASE("(SD) multiple tasks can use same volume", "[fatfs][test_env=UT_T1_SDM
static void sdmmc_speed_test(void *buf, size_t buf_size, size_t file_size, bool write);
TEST_CASE("(SD) write/read speed test", "[fatfs][sd][test_env=UT_T1_SDMODE][timeout=60]")
TEST_CASE("(SD) write/read speed test", "[fatfs][sdmmc]")
{
size_t heap_size;
HEAP_SIZE_CAPTURE(heap_size);
@ -248,7 +246,7 @@ static void sdmmc_speed_test(void *buf, size_t buf_size, size_t file_size, bool
TEST_ESP_OK(esp_vfs_fat_sdmmc_unmount());
}
TEST_CASE("(SD) mount two FAT partitions, SDMMC and WL, at the same time", "[fatfs][sd][test_env=UT_T1_SDMODE][timeout=60]")
TEST_CASE("(SD) mount two FAT partitions, SDMMC and WL, at the same time", "[fatfs][sdmmc]")
{
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
.format_if_mount_failed = true,
@ -260,10 +258,10 @@ TEST_CASE("(SD) mount two FAT partitions, SDMMC and WL, at the same time", "[fat
const char* str_sd = "this is sd\n";
const char* str_wl = "this is spiflash\n";
/* Erase flash before the firs use */
const esp_partition_t *test_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "flash_test");
/* Erase flash before the first use */
const esp_partition_t *test_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_FAT, NULL);
TEST_ASSERT_NOT_NULL(test_partition);
esp_partition_erase_range(test_partition, 0, test_partition->size);
printf("Partition erased: addr- 0x%08x, size- 0x%08x\n", test_partition->address, test_partition->size);
/* Mount FATFS in SD can WL at the same time. Create a file on each FS */
wl_handle_t wl_handle = WL_INVALID_HANDLE;
@ -307,7 +305,7 @@ TEST_CASE("(SD) mount two FAT partitions, SDMMC and WL, at the same time", "[fat
static const char* test_filename_utf_8 = "/sdcard/测试文件.txt";
TEST_CASE("(SD) can read file using UTF-8 encoded strings", "[fatfs][sd][test_env=UT_T1_SDMODE]")
TEST_CASE("(SD) can read file using UTF-8 encoded strings", "[fatfs][sdmmc]")
{
test_setup_sdmmc();
test_fatfs_create_file_with_text(test_filename_utf_8, fatfs_test_hello_str_utf);
@ -323,7 +321,7 @@ TEST_CASE("(SD) opendir, readdir, rewinddir, seekdir work as expected using UTF-
}
#endif // CONFIG_FATFS_API_ENCODING_UTF_8 && CONFIG_FATFS_CODEPAGE == 936
TEST_CASE("(SD) can get partition info", "[fatfs][sd][test_env=UT_T1_SDMODE][timeout=60]")
TEST_CASE("(SD) can get partition info", "[fatfs][sdmmc]")
{
test_setup_sdmmc();
test_fatfs_info("/sdcard", "/sdcard/test.txt");
@ -331,122 +329,3 @@ TEST_CASE("(SD) can get partition info", "[fatfs][sd][test_env=UT_T1_SDMODE][tim
}
#endif //!TEMPORARY_DISABLED_FOR_TARGETS(ESP32S3)
#endif //SDMMC HOST SUPPORTED
#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S3, ESP32C2)
//no runners
typedef struct sdspi_mem {
size_t heap_size;
uint32_t* buf;
} sdspi_mem_t;
static void sdspi_speed_test(void *buf, size_t buf_size, size_t file_size, bool write);
static void test_setup_sdspi(sdspi_mem_t* mem)
{
HEAP_SIZE_CAPTURE(mem->heap_size);
const size_t buf_size = 16 * 1024;
mem->buf = (uint32_t*) calloc(1, buf_size);
esp_fill_random(mem->buf, buf_size);
spi_bus_config_t bus_cfg = {
.mosi_io_num = SDSPI_MOSI_PIN,
.miso_io_num = SDSPI_MISO_PIN,
.sclk_io_num = SDSPI_CLK_PIN,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 4000,
};
esp_err_t err = spi_bus_initialize(SDSPI_HOST_ID, &bus_cfg, SPI_DMA_CHAN);
TEST_ESP_OK(err);
}
static void test_teardown_sdspi(sdspi_mem_t* mem)
{
free(mem->buf);
spi_bus_free(SDSPI_HOST_ID);
HEAP_SIZE_CHECK(mem->heap_size, 0);
}
TEST_CASE("(SDSPI) write/read speed test", "[fatfs][sd][test_env=UT_T1_SPIMODE][timeout=60]")
{
sdspi_mem_t mem;
size_t file_size = 1 * 1024 * 1024;
test_setup_sdspi(&mem);
sdspi_speed_test(mem.buf, 4 * 1024, file_size, true);
sdspi_speed_test(mem.buf, 8 * 1024, file_size, true);
sdspi_speed_test(mem.buf, 16 * 1024, file_size, true);
sdspi_speed_test(mem.buf, 4 * 1024, file_size, false);
sdspi_speed_test(mem.buf, 8 * 1024, file_size, false);
sdspi_speed_test(mem.buf, 16 * 1024, file_size, false);
test_teardown_sdspi(&mem);
}
static void sdspi_speed_test(void *buf, size_t buf_size, size_t file_size, bool write)
{
const char path[] = "/sdcard";
sdmmc_card_t *card;
card = NULL;
sdspi_device_config_t device_cfg = {
.gpio_cs = SDSPI_CS_PIN,
.host_id = SDSPI_HOST_ID,
.gpio_cd = SDSPI_SLOT_NO_CD,
.gpio_wp = SDSPI_SLOT_NO_WP,
.gpio_int = SDSPI_SLOT_NO_INT,
};
sdmmc_host_t host = SDSPI_HOST_DEFAULT();
host.slot = SDSPI_HOST_ID;
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
.format_if_mount_failed = write,
.max_files = 5,
.allocation_unit_size = 64 * 1024
};
TEST_ESP_OK(esp_vfs_fat_sdspi_mount(path, &host, &device_cfg, &mount_config, &card));
test_fatfs_rw_speed("/sdcard/4mb.bin", buf, buf_size, file_size, write);
TEST_ESP_OK(esp_vfs_fat_sdcard_unmount(path, card));
}
TEST_CASE("(SDSPI) can get partition info", "[fatfs][sd][test_env=UT_T1_SPIMODE][timeout=60]")
{
sdspi_mem_t mem;
test_setup_sdspi(&mem);
const char path[] = "/sdcard";
sdmmc_card_t *card;
card = NULL;
sdspi_device_config_t device_cfg = {
.gpio_cs = SDSPI_CS_PIN,
.host_id = SDSPI_HOST_ID,
.gpio_cd = SDSPI_SLOT_NO_CD,
.gpio_wp = SDSPI_SLOT_NO_WP,
.gpio_int = SDSPI_SLOT_NO_INT,
};
sdmmc_host_t host = SDSPI_HOST_DEFAULT();
host.slot = SDSPI_HOST_ID;
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
.format_if_mount_failed = true,
.max_files = 5,
.allocation_unit_size = 64 * 1024
};
TEST_ESP_OK(esp_vfs_fat_sdspi_mount(path, &host, &device_cfg, &mount_config, &card));
test_fatfs_info("/sdcard", "/sdcard/test.txt");
TEST_ESP_OK(esp_vfs_fat_sdcard_unmount(path, card));
test_teardown_sdspi(&mem);
}
#endif //TEMPORARY_DISABLED_FOR_TARGETS(ESP32S3)

View File

@ -0,0 +1,165 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <sys/unistd.h>
#include "unity.h"
#include "esp_log.h"
#include "esp_random.h"
#include "esp_vfs.h"
#include "esp_vfs_fat.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/sdmmc_defs.h"
#include "sdmmc_cmd.h"
#include "ff.h"
#include "test_fatfs_common.h"
#include "soc/soc_caps.h"
#if CONFIG_IDF_TARGET_ESP32
#define SDSPI_MISO_PIN 2
#define SDSPI_MOSI_PIN 15
#define SDSPI_CLK_PIN 14
#define SDSPI_CS_PIN 13
#elif CONFIG_IDF_TARGET_ESP32S2
// Adapted for internal test board ESP-32-S3-USB-OTG-Ev-BOARD_V1.0 (with ESP32-S2-MINI-1 module)
#define SDSPI_MISO_PIN 37
#define SDSPI_MOSI_PIN 35
#define SDSPI_CLK_PIN 36
#define SDSPI_CS_PIN 34
#elif CONFIG_IDF_TARGET_ESP32C3
#define SDSPI_MISO_PIN 6
#define SDSPI_MOSI_PIN 4
#define SDSPI_CLK_PIN 5
#define SDSPI_CS_PIN 1
#define SPI_DMA_CHAN SPI_DMA_CH_AUTO
#endif //CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3
#ifndef SPI_DMA_CHAN
#define SPI_DMA_CHAN 1
#endif //SPI_DMA_CHAN
#define SDSPI_HOST_ID SPI2_HOST
#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S3, ESP32C2)
//no runners
typedef struct sdspi_mem {
size_t heap_size;
uint32_t* buf;
} sdspi_mem_t;
static void sdspi_speed_test(void *buf, size_t buf_size, size_t file_size, bool write);
static void test_setup_sdspi(sdspi_mem_t* mem)
{
HEAP_SIZE_CAPTURE(mem->heap_size);
const size_t buf_size = 16 * 1024;
mem->buf = (uint32_t*) calloc(1, buf_size);
esp_fill_random(mem->buf, buf_size);
spi_bus_config_t bus_cfg = {
.mosi_io_num = SDSPI_MOSI_PIN,
.miso_io_num = SDSPI_MISO_PIN,
.sclk_io_num = SDSPI_CLK_PIN,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 4000,
};
esp_err_t err = spi_bus_initialize(SDSPI_HOST_ID, &bus_cfg, SPI_DMA_CHAN);
TEST_ESP_OK(err);
}
static void test_teardown_sdspi(sdspi_mem_t* mem)
{
free(mem->buf);
spi_bus_free(SDSPI_HOST_ID);
HEAP_SIZE_CHECK(mem->heap_size, 0);
}
TEST_CASE("(SDSPI) write/read speed test", "[fatfs][sdspi]")
{
sdspi_mem_t mem;
size_t file_size = 1 * 1024 * 1024;
test_setup_sdspi(&mem);
sdspi_speed_test(mem.buf, 4 * 1024, file_size, true);
sdspi_speed_test(mem.buf, 8 * 1024, file_size, true);
sdspi_speed_test(mem.buf, 16 * 1024, file_size, true);
sdspi_speed_test(mem.buf, 4 * 1024, file_size, false);
sdspi_speed_test(mem.buf, 8 * 1024, file_size, false);
sdspi_speed_test(mem.buf, 16 * 1024, file_size, false);
test_teardown_sdspi(&mem);
}
static void sdspi_speed_test(void *buf, size_t buf_size, size_t file_size, bool write)
{
const char path[] = "/sdcard";
sdmmc_card_t *card;
card = NULL;
sdspi_device_config_t device_cfg = {
.gpio_cs = SDSPI_CS_PIN,
.host_id = SDSPI_HOST_ID,
.gpio_cd = SDSPI_SLOT_NO_CD,
.gpio_wp = SDSPI_SLOT_NO_WP,
.gpio_int = SDSPI_SLOT_NO_INT,
};
sdmmc_host_t host = SDSPI_HOST_DEFAULT();
host.slot = SDSPI_HOST_ID;
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
.format_if_mount_failed = write,
.max_files = 5,
.allocation_unit_size = 64 * 1024
};
TEST_ESP_OK(esp_vfs_fat_sdspi_mount(path, &host, &device_cfg, &mount_config, &card));
test_fatfs_rw_speed("/sdcard/4mb.bin", buf, buf_size, file_size, write);
TEST_ESP_OK(esp_vfs_fat_sdcard_unmount(path, card));
}
TEST_CASE("(SDSPI) can get partition info", "[fatfs][sdspi]")
{
sdspi_mem_t mem;
test_setup_sdspi(&mem);
const char path[] = "/sdcard";
sdmmc_card_t *card;
card = NULL;
sdspi_device_config_t device_cfg = {
.gpio_cs = SDSPI_CS_PIN,
.host_id = SDSPI_HOST_ID,
.gpio_cd = SDSPI_SLOT_NO_CD,
.gpio_wp = SDSPI_SLOT_NO_WP,
.gpio_int = SDSPI_SLOT_NO_INT,
};
sdmmc_host_t host = SDSPI_HOST_DEFAULT();
host.slot = SDSPI_HOST_ID;
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
.format_if_mount_failed = true,
.max_files = 5,
.allocation_unit_size = 64 * 1024
};
TEST_ESP_OK(esp_vfs_fat_sdspi_mount(path, &host, &device_cfg, &mount_config, &card));
test_fatfs_info("/sdcard", "/sdcard/test.txt");
TEST_ESP_OK(esp_vfs_fat_sdcard_unmount(path, card));
test_teardown_sdspi(&mem);
}
#endif //TEMPORARY_DISABLED_FOR_TARGETS(ESP32S3)

View File

@ -0,0 +1,3 @@
# Name, Type, SubType, Offset, Size, Flags
factory, app, factory, 0x10000, 1M,
storage, data, fat, , 528k,
1 # Name Type SubType Offset Size Flags
2 factory app factory 0x10000 1M
3 storage data fat 528k

View File

@ -0,0 +1,75 @@
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded import Dut
@pytest.mark.esp32
@pytest.mark.sdcard_sdmode
@pytest.mark.parametrize(
'config',
[
'default',
'release',
]
)
def test_fatfs_sdcard_generic_sdmmc(dut: Dut) -> None:
dut.expect_exact('Press ENTER to see the list of tests')
dut.write('')
dut.expect_exact('Enter test for running.')
dut.write('[sdmmc]')
dut.expect_unity_test_output()
@pytest.mark.esp32
@pytest.mark.esp32s2
@pytest.mark.esp32c3
@pytest.mark.sdcard_spimode
@pytest.mark.parametrize(
'config',
[
'default',
'release',
]
)
def test_fatfs_sdcard_generic_sdspi(dut: Dut) -> None:
dut.expect_exact('Press ENTER to see the list of tests')
dut.write('')
dut.expect_exact('Enter test for running.')
dut.write('[sdspi]')
dut.expect_unity_test_output()
@pytest.mark.esp32
@pytest.mark.sdcard_sdmode
@pytest.mark.psram
@pytest.mark.parametrize(
'config',
[
'psram',
]
)
def test_fatfs_sdcard_psram_sdmmc(dut: Dut) -> None:
dut.expect_exact('Press ENTER to see the list of tests')
dut.write('')
dut.expect_exact('Enter test for running.')
dut.write('[sdmmc]')
dut.expect_unity_test_output()
@pytest.mark.esp32
@pytest.mark.sdcard_spimode
@pytest.mark.psram
@pytest.mark.parametrize(
'config',
[
'psram',
]
)
def test_fatfs_sdcard_psram_sdspi(dut: Dut) -> None:
dut.expect_exact('Press ENTER to see the list of tests')
dut.write('')
dut.expect_exact('Enter test for running.')
dut.write('[sdspi]')
dut.expect_unity_test_output()

View File

@ -0,0 +1,3 @@
CONFIG_SPIRAM=y
CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=0
CONFIG_FATFS_ALLOC_PREFER_EXTRAM=y

View File

@ -0,0 +1,2 @@
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y

View File

@ -0,0 +1,19 @@
# General options for additional checks
CONFIG_HEAP_POISONING_COMPREHENSIVE=y
CONFIG_COMPILER_WARN_WRITE_STRINGS=y
CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y
CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y
CONFIG_COMPILER_STACK_CHECK_MODE_STRONG=y
CONFIG_COMPILER_STACK_CHECK=y
# disable task watchdog since this app uses an interactive menu
CONFIG_ESP_TASK_WDT_INIT=n
# some tests verify file name encoding
CONFIG_FATFS_API_ENCODING_UTF_8=y
CONFIG_FATFS_CODEPAGE_936=y
# some of the tests verify concurrent operation of FAT partitions in
# an SD card and in Flash, so need to use a custom partition table.
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"

View File

@ -0,0 +1,3 @@
idf_component_register(SRCS "test_fatfs_common.c"
INCLUDE_DIRS "."
PRIV_REQUIRES unity fatfs vfs unity)

View File

@ -15,15 +15,11 @@
#include <errno.h>
#include <utime.h>
#include "unity.h"
#include "esp_log.h"
#include "esp_system.h"
#include "esp_vfs.h"
#include "esp_vfs_fat.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "ff.h"
#include "test_fatfs_common.h"
#include "esp_rom_sys.h"
const char* fatfs_test_hello_str = "Hello, World!\n";
const char* fatfs_test_hello_str_utf = "世界,你好!\n";
@ -780,9 +776,9 @@ typedef struct {
const char* filename;
bool write;
size_t word_count;
int seed;
unsigned seed;
SemaphoreHandle_t done;
int result;
esp_err_t result;
} read_write_test_arg_t;
#define READ_WRITE_TEST_ARG_INIT(name, seed_) \
@ -805,19 +801,19 @@ static void read_write_task(void* param)
srand(args->seed);
for (size_t i = 0; i < args->word_count; ++i) {
uint32_t val = rand();
unsigned val = rand();
if (args->write) {
int cnt = fwrite(&val, sizeof(val), 1, f);
if (cnt != 1) {
esp_rom_printf("E(w): i=%d, cnt=%d val=%d\n\n", i, cnt, val);
printf("E(w): i=%d, cnt=%d val=0x08%x\n", i, cnt, val);
args->result = ESP_FAIL;
goto close;
}
} else {
uint32_t rval;
unsigned rval;
int cnt = fread(&rval, sizeof(rval), 1, f);
if (cnt != 1 || rval != val) {
esp_rom_printf("E(r): i=%d, cnt=%d rval=%d val=%d\n\n", i, cnt, rval, val);
printf("E(r): i=%d, cnt=%d rval=0x08%x val=0x08%x\n", i, cnt, rval, val);
args->result = ESP_FAIL;
goto close;
}

View File

@ -22,7 +22,6 @@ CONFIG_COMPILER_WARN_WRITE_STRINGS=y
CONFIG_SPI_MASTER_IN_IRAM=y
CONFIG_EFUSE_VIRTUAL=y
CONFIG_SPIRAM_BANKSWITCH_ENABLE=n
CONFIG_FATFS_ALLOC_PREFER_EXTRAM=y
CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL=y
CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=3000
CONFIG_MQTT_TEST_BROKER_URI="mqtt://${EXAMPLE_MQTT_BROKER_TCP}"