diff --git a/components/esp_driver_sdmmc/test_apps/sd_test_utils/components/common_test_flows/CMakeLists.txt b/components/esp_driver_sdmmc/test_apps/sd_test_utils/components/common_test_flows/CMakeLists.txt index 6fc914d3ff..649cb95a54 100644 --- a/components/esp_driver_sdmmc/test_apps/sd_test_utils/components/common_test_flows/CMakeLists.txt +++ b/components/esp_driver_sdmmc/test_apps/sd_test_utils/components/common_test_flows/CMakeLists.txt @@ -1,4 +1,4 @@ -set(srcs "sdmmc_test_cd_wp_common.c" "sdmmc_test_rw_common.c") +set(srcs "sdmmc_test_cd_wp_common.c" "sdmmc_test_rw_common.c" "sdmmc_test_erase_common_sd.c") set(public_include "include") diff --git a/components/esp_driver_sdmmc/test_apps/sd_test_utils/components/common_test_flows/include/sdmmc_test_erase_common_sd.h b/components/esp_driver_sdmmc/test_apps/sd_test_utils/components/common_test_flows/include/sdmmc_test_erase_common_sd.h new file mode 100644 index 0000000000..572c9e1f89 --- /dev/null +++ b/components/esp_driver_sdmmc/test_apps/sd_test_utils/components/common_test_flows/include/sdmmc_test_erase_common_sd.h @@ -0,0 +1,30 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include "driver/sdmmc_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Test erase blocks performance of the card + * + * This function writes a buffer to the card, then erase all the buffers. + * The time taken for each operation is measured, and the throughput is calculated. + * The process is repeated for different buffer ranges. + * In this test, data is always written and then erase from the card + * + * This test function works both with SDMMC and SDSPI hosts. + * + * @param card Pointer to the card object, must be initialized before calling this function. + */ +void sdmmc_test_sd_erase_blocks(sdmmc_card_t* card); + +#ifdef __cplusplus +}; +#endif diff --git a/components/esp_driver_sdmmc/test_apps/sd_test_utils/components/common_test_flows/sdmmc_test_erase_common_sd.c b/components/esp_driver_sdmmc/test_apps/sd_test_utils/components/common_test_flows/sdmmc_test_erase_common_sd.c new file mode 100644 index 0000000000..77ff8cc53e --- /dev/null +++ b/components/esp_driver_sdmmc/test_apps/sd_test_utils/components/common_test_flows/sdmmc_test_erase_common_sd.c @@ -0,0 +1,205 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include "unity.h" +#include "sdmmc_cmd.h" + +#define PATTERN_SEED 0x12345678 +#define FLAG_ERASE_TEST_ADJACENT (1 << 0) +#define FLAG_VERIFY_ERASE_STATE (1 << 1) + +#ifdef CONFIG_SOC_SDMMC_HOST_SUPPORTED +extern bool get_sanitize_flag(void); +#endif + +static void check_buffer(uint32_t seed, const uint8_t* src, size_t count) +{ + srand(seed); + for (size_t i = 0; i < count; ++i) { + uint32_t val; + memcpy(&val, src + i * sizeof(uint32_t), sizeof(val)); + TEST_ASSERT_EQUAL_HEX32(rand(), val); + } +} + +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 void ensure_sector_written(sdmmc_card_t* card, size_t sector, + uint8_t *pattern_buf, uint8_t *temp_buf) +{ + size_t block_size = card->csd.sector_size; + TEST_ESP_OK(sdmmc_write_sectors(card, pattern_buf, sector, 1)); + memset((void *)temp_buf, 0x00, block_size); + TEST_ESP_OK(sdmmc_read_sectors(card, temp_buf, sector, 1)); + check_buffer(PATTERN_SEED, temp_buf, block_size / sizeof(uint32_t)); +} + +static void ensure_sector_intact(sdmmc_card_t* card, size_t sector, + uint8_t *pattern_buf, uint8_t *temp_buf) +{ + size_t block_size = card->csd.sector_size; + memset((void *)temp_buf, 0x00, block_size); + TEST_ESP_OK(sdmmc_read_sectors(card, temp_buf, sector, 1)); + check_buffer(PATTERN_SEED, temp_buf, block_size / sizeof(uint32_t)); +} + +static int32_t ensure_sector_erase(sdmmc_card_t* card, size_t sector, + uint8_t *pattern_buf, uint8_t *temp_buf) +{ + size_t block_size = card->csd.sector_size; + memset((void *)temp_buf, 0, block_size); + TEST_ESP_OK(sdmmc_read_sectors(card, temp_buf, sector, 1)); + return memcmp(pattern_buf, temp_buf, block_size); +} + +static void do_single_erase_test(sdmmc_card_t* card, size_t start_block, + size_t block_count, uint8_t flags, sdmmc_erase_arg_t arg) +{ + size_t block_size = card->csd.sector_size; + uint8_t *temp_buf = NULL; + uint8_t *pattern_buf = NULL; + size_t end_block = (start_block + block_count - 1); + + /* + * To ensure erase is successful/valid + * selected blocks after erase should have erase state data pattern + * data of blocks adjacent to selected region should remain intact + */ + TEST_ESP_OK((start_block + block_count) > card->csd.capacity); + + pattern_buf = (uint8_t *)heap_caps_malloc(block_size, MALLOC_CAP_DMA); + TEST_ASSERT_NOT_NULL(pattern_buf); + temp_buf = (uint8_t *)heap_caps_malloc(block_size, MALLOC_CAP_DMA); + TEST_ASSERT_NOT_NULL(temp_buf); + + // create pattern buffer + fill_buffer(PATTERN_SEED, pattern_buf, block_size / sizeof(uint32_t)); + + // check if it's not the first block of device & write/read/verify pattern + if ((flags & FLAG_ERASE_TEST_ADJACENT) && start_block) { + ensure_sector_written(card, (start_block - 1), pattern_buf, temp_buf); + } + + ensure_sector_written(card, start_block, pattern_buf, temp_buf); + + // check if it's not the last block of device & write/read/verify pattern + if ((flags & FLAG_ERASE_TEST_ADJACENT) && (end_block < (card->csd.capacity - 1))) { + ensure_sector_written(card, (end_block + 1), pattern_buf, temp_buf); + } + + // when block count is 1, start and end block is same, hence skip + if (block_count != 1) { + ensure_sector_written(card, end_block, pattern_buf, temp_buf); + } + + // fill pattern to (start_block + end_block)/2 in the erase range + if (block_count > 2) { + ensure_sector_written(card, (start_block + end_block) / 2, pattern_buf, temp_buf); + } + + float total_size = (block_count / 1024.0f) * block_size; + printf(" %10d | %10d | %8.1f ", start_block, block_count, total_size); + fflush(stdout); + + // erase the blocks + struct timeval t_start_er; + gettimeofday(&t_start_er, NULL); + TEST_ESP_OK(sdmmc_erase_sectors(card, start_block, block_count, arg)); +#ifdef CONFIG_SOC_SDMMC_HOST_SUPPORTED + if (get_sanitize_flag()) { + TEST_ESP_OK(sdmmc_mmc_sanitize(card, block_count * 500)); + } +#endif + struct timeval t_stop_wr; + gettimeofday(&t_stop_wr, NULL); + float time_er = 1e3f * (t_stop_wr.tv_sec - t_start_er.tv_sec) + 1e-3f * (t_stop_wr.tv_usec - t_start_er.tv_usec); + printf(" | %8.2f\n", time_er); + + // ensure adjacent blocks are not affected + // block before start_block + if ((flags & FLAG_ERASE_TEST_ADJACENT) && start_block) { + ensure_sector_intact(card, (start_block - 1), pattern_buf, temp_buf); + } + + // block after end_block + if ((flags & FLAG_ERASE_TEST_ADJACENT) && (end_block < (card->csd.capacity - 1))) { + ensure_sector_intact(card, (end_block + 1), pattern_buf, temp_buf); + } + + uint8_t erase_mem_byte = 0xFF; + // ensure all the blocks are erased and are up to after erase state. + if (!card->is_mmc) { + erase_mem_byte = card->scr.erase_mem_state ? 0xFF : 0x00; + } else { + erase_mem_byte = card->ext_csd.erase_mem_state ? 0xFF : 0x00; + } + + memset((void *)pattern_buf, erase_mem_byte, block_size); + + // as it is block by block comparison, a time taking process. Really long + // when you do erase and verify on complete device. + if (flags & FLAG_VERIFY_ERASE_STATE) { + for (size_t i = 0; i < block_count; i++) { + if (ensure_sector_erase(card, (start_block + i), pattern_buf, temp_buf)) { + printf("Error: Sector %d erase\n", (start_block + i)); + break; + } + } + } + + free(temp_buf); + free(pattern_buf); +} + +void sdmmc_test_sd_erase_blocks(sdmmc_card_t* card) +{ + printf("block size %d capacity %d\n", card->csd.sector_size, card->csd.capacity); + printf(" sector | count | size(kB) | er_time(ms) \n"); + /* + * bit-0: verify adjacent blocks of given range + * bit-1: verify erase state of blocks in range + */ + uint8_t flags = 0; + sdmmc_erase_arg_t arg = SDMMC_ERASE_ARG; + + //check for adjacent blocks and erase state of blocks + flags |= (uint8_t)FLAG_ERASE_TEST_ADJACENT | (uint8_t)FLAG_VERIFY_ERASE_STATE; + do_single_erase_test(card, 1, 16, flags, arg); + do_single_erase_test(card, 1, 13, flags, arg); + do_single_erase_test(card, 16, 32, flags, arg); + do_single_erase_test(card, 48, 64, flags, arg); + do_single_erase_test(card, 128, 128, flags, arg); + do_single_erase_test(card, card->csd.capacity - 64, 32, flags, arg); + do_single_erase_test(card, card->csd.capacity - 64, 64, flags, arg); + // single sector erase is failing on different make cards + do_single_erase_test(card, card->csd.capacity - 8, 1, flags, arg); + do_single_erase_test(card, card->csd.capacity / 2, 1, flags, arg); + do_single_erase_test(card, card->csd.capacity / 2, 4, flags, arg); + do_single_erase_test(card, card->csd.capacity / 2, 8, flags, arg); + do_single_erase_test(card, card->csd.capacity / 2, 16, flags, arg); + do_single_erase_test(card, card->csd.capacity / 2, 32, flags, arg); + do_single_erase_test(card, card->csd.capacity / 2, 64, flags, arg); + do_single_erase_test(card, card->csd.capacity / 2, 128, flags, arg); +#ifdef SDMMC_FULL_ERASE_TEST + /* + * check for adjacent blocks, do not check erase state of blocks as it is + * time taking process to verify all the blocks. + */ + flags &= ~(uint8_t)FLAG_VERIFY_ERASE_STATE; //comment this line to verify after-erase state + // erase complete card + do_single_erase_test(card, 0, card->csd.capacity, flags, arg); +#endif //SDMMC_FULL_ERASE_TEST +} diff --git a/components/esp_driver_sdmmc/test_apps/sdmmc/components/sdmmc_tests/CMakeLists.txt b/components/esp_driver_sdmmc/test_apps/sdmmc/components/sdmmc_tests/CMakeLists.txt index c406967c6b..599b9ffba3 100644 --- a/components/esp_driver_sdmmc/test_apps/sdmmc/components/sdmmc_tests/CMakeLists.txt +++ b/components/esp_driver_sdmmc/test_apps/sdmmc/components/sdmmc_tests/CMakeLists.txt @@ -5,7 +5,11 @@ if(CONFIG_SOC_SDMMC_HOST_SUPPORTED) list(APPEND srcs "sdmmc_test_begin_end_sd.c" "sdmmc_test_cd_wp_sd.c" "sdmmc_test_probe_sd.c" - "sdmmc_test_rw_sd.c") + "sdmmc_test_rw_sd.c" + "sdmmc_test_erase_sd.c" + "sdmmc_test_trim_sd.c" + "sdmmc_test_discard_sd.c" + "sdmmc_test_sanitize_sd.c") endif() set(priv_requires "sdmmc" diff --git a/components/esp_driver_sdmmc/test_apps/sdmmc/components/sdmmc_tests/sdmmc_test_discard_sd.c b/components/esp_driver_sdmmc/test_apps/sdmmc/components/sdmmc_tests/sdmmc_test_discard_sd.c new file mode 100644 index 0000000000..b0211b73d9 --- /dev/null +++ b/components/esp_driver_sdmmc/test_apps/sdmmc/components/sdmmc_tests/sdmmc_test_discard_sd.c @@ -0,0 +1,66 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include "unity.h" +#include "driver/sdmmc_defs.h" +#include "sdmmc_cmd.h" +#include "sdmmc_test_begin_end_sd.h" +#include "sdmmc_test_erase_common_sd.h" + +static void test_discard_blocks(sdmmc_card_t* card, int slot) +{ + /* MMC discard applies to write blocks */ + sdmmc_erase_arg_t arg = SDMMC_DISCARD_ARG; + if (slot == SLOT_0) { + uint32_t prev_ext_csd = card->ext_csd.rev; + // overwrite discard_support as not-supported for -ve test + card->ext_csd.rev = 0; + TEST_ESP_ERR(ESP_ERR_NOT_SUPPORTED, sdmmc_erase_sectors(card, 0, 32, arg)); + // restore discard_support + card->ext_csd.rev = prev_ext_csd; + } else { + uint32_t prev_discard_support = card->ssr.discard_support; + // overwrite discard_support as not-supported for -ve test + card->ssr.discard_support = 0; + TEST_ESP_ERR(ESP_ERR_NOT_SUPPORTED, sdmmc_erase_sectors(card, 0, 32, arg)); + // restore discard_support + card->ssr.discard_support = prev_discard_support; + } + + if (sdmmc_can_discard(card) != ESP_OK) { + printf("Card/device do not support discard\n"); + return; + } + sdmmc_test_sd_erase_blocks(card); +} + +static void do_one_mmc_discard_test(int slot, int width, int freq_khz, int ddr) +{ + sdmmc_card_t card; + sdmmc_test_sd_skip_if_board_incompatible(slot, width, freq_khz, ddr); + sdmmc_test_sd_begin(slot, width, freq_khz, ddr, &card); + sdmmc_card_print_info(stdout, &card); + test_discard_blocks(&card, slot); + sdmmc_test_sd_end(&card); +} + +TEST_CASE("sdmmc discard, slot 0, 4-bit", "[sdmmc]") +{ + do_one_mmc_discard_test(SLOT_0, 4, SDMMC_FREQ_HIGHSPEED, NO_DDR); +} + +TEST_CASE("sdmmc discard, slot 0, 8-bit", "[sdmmc]") +{ + do_one_mmc_discard_test(SLOT_0, 8, SDMMC_FREQ_HIGHSPEED, NO_DDR); +} + +TEST_CASE("sdmmc discard, slot 1, 4-bit", "[sdmmc]") +{ + do_one_mmc_discard_test(SLOT_1, 4, SDMMC_FREQ_HIGHSPEED, NO_DDR); +} diff --git a/components/esp_driver_sdmmc/test_apps/sdmmc/components/sdmmc_tests/sdmmc_test_erase_sd.c b/components/esp_driver_sdmmc/test_apps/sdmmc/components/sdmmc_tests/sdmmc_test_erase_sd.c new file mode 100644 index 0000000000..9212c61a8c --- /dev/null +++ b/components/esp_driver_sdmmc/test_apps/sdmmc/components/sdmmc_tests/sdmmc_test_erase_sd.c @@ -0,0 +1,37 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include "unity.h" +#include "sdmmc_cmd.h" +#include "sdmmc_test_begin_end_sd.h" +#include "sdmmc_test_erase_common_sd.h" + +static void do_one_sdmmc_erase_test(int slot, int width, int freq_khz, int ddr) +{ + sdmmc_card_t card; + sdmmc_test_sd_skip_if_board_incompatible(slot, width, freq_khz, ddr); + sdmmc_test_sd_begin(slot, width, freq_khz, ddr, &card); + sdmmc_card_print_info(stdout, &card); + sdmmc_test_sd_erase_blocks(&card); + sdmmc_test_sd_end(&card); +} + +TEST_CASE("sdmmc erase, slot 1, 1-bit", "[sdmmc]") +{ + do_one_sdmmc_erase_test(SLOT_1, 1, SDMMC_FREQ_PROBING, NO_DDR); + do_one_sdmmc_erase_test(SLOT_1, 1, SDMMC_FREQ_DEFAULT, NO_DDR); + do_one_sdmmc_erase_test(SLOT_1, 1, SDMMC_FREQ_HIGHSPEED, NO_DDR); +} + +TEST_CASE("sdmmc erase, slot 1, 4-bit", "[sdmmc]") +{ + do_one_sdmmc_erase_test(SLOT_1, 4, SDMMC_FREQ_PROBING, NO_DDR); + do_one_sdmmc_erase_test(SLOT_1, 4, SDMMC_FREQ_DEFAULT, NO_DDR); + do_one_sdmmc_erase_test(SLOT_1, 4, SDMMC_FREQ_HIGHSPEED, NO_DDR); +} diff --git a/components/esp_driver_sdmmc/test_apps/sdmmc/components/sdmmc_tests/sdmmc_test_probe_sd.c b/components/esp_driver_sdmmc/test_apps/sdmmc/components/sdmmc_tests/sdmmc_test_probe_sd.c index 83b5c58ce2..ce4ab53fc4 100644 --- a/components/esp_driver_sdmmc/test_apps/sdmmc/components/sdmmc_tests/sdmmc_test_probe_sd.c +++ b/components/esp_driver_sdmmc/test_apps/sdmmc/components/sdmmc_tests/sdmmc_test_probe_sd.c @@ -8,6 +8,8 @@ #include "sdmmc_cmd.h" #include "sdmmc_test_begin_end_sd.h" +#define SDMMC_FREQ_CUSTOM_10M 10000 + static void do_one_sdmmc_probe_test(int slot, int width, int freq_khz, int ddr) { sdmmc_card_t card; @@ -58,6 +60,7 @@ TEST_CASE("sdmmc probe, slot 1, 4-bit", "[sdmmc]") do_one_sdmmc_probe_test(SLOT_1, 4, SDMMC_FREQ_PROBING, NO_DDR); do_one_sdmmc_probe_test(SLOT_1, 4, SDMMC_FREQ_DEFAULT, NO_DDR); do_one_sdmmc_probe_test(SLOT_1, 4, SDMMC_FREQ_HIGHSPEED, NO_DDR); + do_one_sdmmc_probe_test(SLOT_1, 4, SDMMC_FREQ_CUSTOM_10M, NO_DDR); } TEST_CASE("sdmmc probe, slot 1, 4-bit DDR", "[sdmmc]") diff --git a/components/esp_driver_sdmmc/test_apps/sdmmc/components/sdmmc_tests/sdmmc_test_sanitize_sd.c b/components/esp_driver_sdmmc/test_apps/sdmmc/components/sdmmc_tests/sdmmc_test_sanitize_sd.c new file mode 100644 index 0000000000..4fc434fbb5 --- /dev/null +++ b/components/esp_driver_sdmmc/test_apps/sdmmc/components/sdmmc_tests/sdmmc_test_sanitize_sd.c @@ -0,0 +1,53 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include "unity.h" +#include "driver/sdmmc_defs.h" +#include "sdmmc_cmd.h" +#include "sdmmc_test_begin_end_sd.h" +#include "sdmmc_test_erase_common_sd.h" + +static bool do_sanitize_flag; + +bool get_sanitize_flag(void) +{ + return do_sanitize_flag; +} + +static void test_mmc_sanitize_blocks(sdmmc_card_t* card) +{ + /* MMC trim applies to write blocks */ + if (sdmmc_mmc_can_sanitize(card) != ESP_OK) { + printf("Card/device do not support sanitize\n"); + return; + } + do_sanitize_flag = true; + sdmmc_test_sd_erase_blocks(card); + do_sanitize_flag = false; +} + +static void do_one_mmc_sanitize_test(int slot, int width, int freq_khz, int ddr) +{ + sdmmc_card_t card; + sdmmc_test_sd_skip_if_board_incompatible(slot, width, freq_khz, ddr); + sdmmc_test_sd_begin(slot, width, freq_khz, ddr, &card); + sdmmc_card_print_info(stdout, &card); + test_mmc_sanitize_blocks(&card); + sdmmc_test_sd_end(&card); +} + +TEST_CASE("sdmmc sanitize, slot 0, 4-bit", "[sdmmc]") +{ + do_one_mmc_sanitize_test(SLOT_0, 4, SDMMC_FREQ_HIGHSPEED, NO_DDR); +} + +TEST_CASE("sdmmc sanitize, slot 0, 8-bit", "[sdmmc]") +{ + do_one_mmc_sanitize_test(SLOT_0, 8, SDMMC_FREQ_HIGHSPEED, NO_DDR); +} diff --git a/components/esp_driver_sdmmc/test_apps/sdmmc/components/sdmmc_tests/sdmmc_test_trim_sd.c b/components/esp_driver_sdmmc/test_apps/sdmmc/components/sdmmc_tests/sdmmc_test_trim_sd.c new file mode 100644 index 0000000000..8f277b8066 --- /dev/null +++ b/components/esp_driver_sdmmc/test_apps/sdmmc/components/sdmmc_tests/sdmmc_test_trim_sd.c @@ -0,0 +1,51 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include "unity.h" +#include "driver/sdmmc_defs.h" +#include "sdmmc_cmd.h" +#include "sdmmc_test_begin_end_sd.h" +#include "sdmmc_test_erase_common_sd.h" + +static void test_mmc_trim_blocks(sdmmc_card_t* card) +{ + /* MMC trim applies to write blocks */ + sdmmc_erase_arg_t arg = SDMMC_ERASE_ARG; + uint8_t prev_sec_feature = card->ext_csd.sec_feature; + // overwrite sec_feature + card->ext_csd.sec_feature &= ~(EXT_CSD_SEC_GB_CL_EN); + TEST_ESP_ERR(ESP_ERR_NOT_SUPPORTED, sdmmc_erase_sectors(card, 0, 32, arg)); + // restore sec_feature + card->ext_csd.sec_feature = prev_sec_feature; + if (sdmmc_can_trim(card) != ESP_OK) { + printf("Card/device do not support trim\n"); + return; + } + sdmmc_test_sd_erase_blocks(card); +} + +static void do_one_mmc_trim_test(int slot, int width, int freq_khz, int ddr) +{ + sdmmc_card_t card; + sdmmc_test_sd_skip_if_board_incompatible(slot, width, freq_khz, ddr); + sdmmc_test_sd_begin(slot, width, freq_khz, ddr, &card); + sdmmc_card_print_info(stdout, &card); + test_mmc_trim_blocks(&card); + sdmmc_test_sd_end(&card); +} + +TEST_CASE("sdmmc trim, slot 0, 4-bit", "[sdmmc]") +{ + do_one_mmc_trim_test(SLOT_0, 4, SDMMC_FREQ_HIGHSPEED, NO_DDR); +} + +TEST_CASE("sdmmc trim, slot 0, 8-bit", "[sdmmc]") +{ + do_one_mmc_trim_test(SLOT_0, 8, SDMMC_FREQ_HIGHSPEED, NO_DDR); +} diff --git a/components/esp_driver_sdspi/test_apps/sdspi/components/sdspi_tests/CMakeLists.txt b/components/esp_driver_sdspi/test_apps/sdspi/components/sdspi_tests/CMakeLists.txt index 436d08e38b..b4e403e407 100644 --- a/components/esp_driver_sdspi/test_apps/sdspi/components/sdspi_tests/CMakeLists.txt +++ b/components/esp_driver_sdspi/test_apps/sdspi/components/sdspi_tests/CMakeLists.txt @@ -4,7 +4,9 @@ if(CONFIG_SOC_GPSPI_SUPPORTED) list(APPEND srcs "sdmmc_test_begin_end_spi.c" "sdmmc_test_cd_wp_spi.c" "sdmmc_test_probe_spi.c" - "sdmmc_test_rw_spi.c") + "sdmmc_test_rw_spi.c" + "sdmmc_test_erase_spi.c" + "sdmmc_test_erase_common_spi.c") endif() set(priv_requires "sdmmc" diff --git a/components/esp_driver_sdspi/test_apps/sdspi/components/sdspi_tests/sdmmc_test_erase_common_spi.c b/components/esp_driver_sdspi/test_apps/sdspi/components/sdspi_tests/sdmmc_test_erase_common_spi.c new file mode 100644 index 0000000000..d7daf7a17d --- /dev/null +++ b/components/esp_driver_sdspi/test_apps/sdspi/components/sdspi_tests/sdmmc_test_erase_common_spi.c @@ -0,0 +1,198 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include "unity.h" +#include "sdmmc_cmd.h" +#include "sdmmc_test_begin_end_spi.h" + +#define PATTERN_SEED 0x12345678 +#define FLAG_ERASE_TEST_ADJACENT (1 << 0) +#define FLAG_VERIFY_ERASE_STATE (1 << 1) + +static void check_buffer(uint32_t seed, const uint8_t* src, size_t count) +{ + srand(seed); + for (size_t i = 0; i < count; ++i) { + uint32_t val; + memcpy(&val, src + i * sizeof(uint32_t), sizeof(val)); + TEST_ASSERT_EQUAL_HEX32(rand(), val); + } +} + +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 void ensure_sector_written(sdmmc_card_t* card, size_t sector, + uint8_t *pattern_buf, uint8_t *temp_buf) +{ + size_t block_size = card->csd.sector_size; + TEST_ESP_OK(sdmmc_write_sectors(card, pattern_buf, sector, 1)); + memset((void *)temp_buf, 0x00, block_size); + TEST_ESP_OK(sdmmc_read_sectors(card, temp_buf, sector, 1)); + check_buffer(PATTERN_SEED, temp_buf, block_size / sizeof(uint32_t)); +} + +static void ensure_sector_intact(sdmmc_card_t* card, size_t sector, + uint8_t *pattern_buf, uint8_t *temp_buf) +{ + size_t block_size = card->csd.sector_size; + memset((void *)temp_buf, 0x00, block_size); + TEST_ESP_OK(sdmmc_read_sectors(card, temp_buf, sector, 1)); + check_buffer(PATTERN_SEED, temp_buf, block_size / sizeof(uint32_t)); +} + +static int32_t ensure_sector_erase(sdmmc_card_t* card, size_t sector, + uint8_t *pattern_buf, uint8_t *temp_buf) +{ + size_t block_size = card->csd.sector_size; + memset((void *)temp_buf, 0, block_size); + TEST_ESP_OK(sdmmc_read_sectors(card, temp_buf, sector, 1)); + return memcmp(pattern_buf, temp_buf, block_size); +} + +static void do_single_erase_test(sdmmc_card_t* card, size_t start_block, + size_t block_count, uint8_t flags, sdmmc_erase_arg_t arg) +{ + size_t block_size = card->csd.sector_size; + uint8_t *temp_buf = NULL; + uint8_t *pattern_buf = NULL; + size_t end_block = (start_block + block_count - 1); + + /* + * To ensure erase is successful/valid + * selected blocks after erase should have erase state data pattern + * data of blocks adjacent to selected region should remain intact + */ + TEST_ESP_OK((start_block + block_count) > card->csd.capacity); + + pattern_buf = (uint8_t *)heap_caps_malloc(block_size, MALLOC_CAP_DMA); + TEST_ASSERT_NOT_NULL(pattern_buf); + temp_buf = (uint8_t *)heap_caps_malloc(block_size, MALLOC_CAP_DMA); + TEST_ASSERT_NOT_NULL(temp_buf); + + // create pattern buffer + fill_buffer(PATTERN_SEED, pattern_buf, block_size / sizeof(uint32_t)); + + // check if it's not the first block of device & write/read/verify pattern + if ((flags & FLAG_ERASE_TEST_ADJACENT) && start_block) { + ensure_sector_written(card, (start_block - 1), pattern_buf, temp_buf); + } + + ensure_sector_written(card, start_block, pattern_buf, temp_buf); + + // check if it's not the last block of device & write/read/verify pattern + if ((flags & FLAG_ERASE_TEST_ADJACENT) && (end_block < (card->csd.capacity - 1))) { + ensure_sector_written(card, (end_block + 1), pattern_buf, temp_buf); + } + + // when block count is 1, start and end block is same, hence skip + if (block_count != 1) { + ensure_sector_written(card, end_block, pattern_buf, temp_buf); + } + + // fill pattern to (start_block + end_block)/2 in the erase range + if (block_count > 2) { + ensure_sector_written(card, (start_block + end_block) / 2, pattern_buf, temp_buf); + } + + float total_size = (block_count / 1024.0f) * block_size; + printf(" %10d | %10d | %8.1f ", start_block, block_count, total_size); + fflush(stdout); + + // erase the blocks + struct timeval t_start_er; + gettimeofday(&t_start_er, NULL); + TEST_ESP_OK(sdmmc_erase_sectors(card, start_block, block_count, arg)); + + struct timeval t_stop_wr; + gettimeofday(&t_stop_wr, NULL); + float time_er = 1e3f * (t_stop_wr.tv_sec - t_start_er.tv_sec) + 1e-3f * (t_stop_wr.tv_usec - t_start_er.tv_usec); + printf(" | %8.2f\n", time_er); + + // ensure adjacent blocks are not affected + // block before start_block + if ((flags & FLAG_ERASE_TEST_ADJACENT) && start_block) { + ensure_sector_intact(card, (start_block - 1), pattern_buf, temp_buf); + } + + // block after end_block + if ((flags & FLAG_ERASE_TEST_ADJACENT) && (end_block < (card->csd.capacity - 1))) { + ensure_sector_intact(card, (end_block + 1), pattern_buf, temp_buf); + } + + uint8_t erase_mem_byte = 0xFF; + // ensure all the blocks are erased and are up to after erase state. + if (!card->is_mmc) { + erase_mem_byte = card->scr.erase_mem_state ? 0xFF : 0x00; + } else { + erase_mem_byte = card->ext_csd.erase_mem_state ? 0xFF : 0x00; + } + + memset((void *)pattern_buf, erase_mem_byte, block_size); + + // as it is block by block comparison, a time taking process. Really long + // when you do erase and verify on complete device. + if (flags & FLAG_VERIFY_ERASE_STATE) { + for (size_t i = 0; i < block_count; i++) { + if (ensure_sector_erase(card, (start_block + i), pattern_buf, temp_buf)) { + printf("Error: Sector %d erase\n", (start_block + i)); + break; + } + } + } + + free(temp_buf); + free(pattern_buf); +} + +void sdmmc_test_sd_erase_blocks(sdmmc_card_t* card) +{ + printf("block size %d capacity %d\n", card->csd.sector_size, card->csd.capacity); + printf(" sector | count | size(kB) | er_time(ms) \n"); + /* + * bit-0: verify adjacent blocks of given range + * bit-1: verify erase state of blocks in range + */ + uint8_t flags = 0; + sdmmc_erase_arg_t arg = SDMMC_ERASE_ARG; + + //check for adjacent blocks and erase state of blocks + flags |= (uint8_t)FLAG_ERASE_TEST_ADJACENT | (uint8_t)FLAG_VERIFY_ERASE_STATE; + do_single_erase_test(card, 1, 16, flags, arg); + do_single_erase_test(card, 1, 13, flags, arg); + do_single_erase_test(card, 16, 32, flags, arg); + do_single_erase_test(card, 48, 64, flags, arg); + do_single_erase_test(card, 128, 128, flags, arg); + do_single_erase_test(card, card->csd.capacity - 64, 32, flags, arg); + do_single_erase_test(card, card->csd.capacity - 64, 64, flags, arg); + // single sector erase is failing on different make cards + do_single_erase_test(card, card->csd.capacity - 8, 1, flags, arg); + do_single_erase_test(card, card->csd.capacity / 2, 1, flags, arg); + do_single_erase_test(card, card->csd.capacity / 2, 4, flags, arg); + do_single_erase_test(card, card->csd.capacity / 2, 8, flags, arg); + do_single_erase_test(card, card->csd.capacity / 2, 16, flags, arg); + do_single_erase_test(card, card->csd.capacity / 2, 32, flags, arg); + do_single_erase_test(card, card->csd.capacity / 2, 64, flags, arg); + do_single_erase_test(card, card->csd.capacity / 2, 128, flags, arg); +#ifdef SDMMC_FULL_ERASE_TEST + /* + * check for adjacent blocks, do not check erase state of blocks as it is + * time taking process to verify all the blocks. + */ + flags &= ~(uint8_t)FLAG_VERIFY_ERASE_STATE; //comment this line to verify after-erase state + // erase complete card + do_single_erase_test(card, 0, card->csd.capacity, flags, arg); +#endif //SDMMC_FULL_ERASE_TEST +} diff --git a/components/esp_driver_sdspi/test_apps/sdspi/components/sdspi_tests/sdmmc_test_erase_common_spi.h b/components/esp_driver_sdspi/test_apps/sdspi/components/sdspi_tests/sdmmc_test_erase_common_spi.h new file mode 100644 index 0000000000..572c9e1f89 --- /dev/null +++ b/components/esp_driver_sdspi/test_apps/sdspi/components/sdspi_tests/sdmmc_test_erase_common_spi.h @@ -0,0 +1,30 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include "driver/sdmmc_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Test erase blocks performance of the card + * + * This function writes a buffer to the card, then erase all the buffers. + * The time taken for each operation is measured, and the throughput is calculated. + * The process is repeated for different buffer ranges. + * In this test, data is always written and then erase from the card + * + * This test function works both with SDMMC and SDSPI hosts. + * + * @param card Pointer to the card object, must be initialized before calling this function. + */ +void sdmmc_test_sd_erase_blocks(sdmmc_card_t* card); + +#ifdef __cplusplus +}; +#endif diff --git a/components/esp_driver_sdspi/test_apps/sdspi/components/sdspi_tests/sdmmc_test_erase_spi.c b/components/esp_driver_sdspi/test_apps/sdspi/components/sdspi_tests/sdmmc_test_erase_spi.c new file mode 100644 index 0000000000..5f1e3c10f3 --- /dev/null +++ b/components/esp_driver_sdspi/test_apps/sdspi/components/sdspi_tests/sdmmc_test_erase_spi.c @@ -0,0 +1,29 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include "unity.h" +#include "sdmmc_cmd.h" +#include "sdmmc_test_begin_end_spi.h" +#include "sdmmc_test_erase_common_spi.h" + +static void do_one_sdspi_erase(int slot, int freq_khz) +{ + sdmmc_card_t card; + sdmmc_test_spi_skip_if_board_incompatible(slot, freq_khz); + sdmmc_test_spi_begin(slot, freq_khz, &card); + sdmmc_card_print_info(stdout, &card); + sdmmc_test_sd_erase_blocks(&card); + sdmmc_test_spi_end(slot, &card); +} + +TEST_CASE("sdspi erase, slot 1", "[sdspi]") +{ + do_one_sdspi_erase(SLOT_1, SDMMC_FREQ_PROBING); + do_one_sdspi_erase(SLOT_1, SDMMC_FREQ_DEFAULT); +} diff --git a/components/esp_driver_sdspi/test_apps/sdspi/components/sdspi_tests/sdmmc_test_probe_spi.c b/components/esp_driver_sdspi/test_apps/sdspi/components/sdspi_tests/sdmmc_test_probe_spi.c index c9738ab236..42da8c1e93 100644 --- a/components/esp_driver_sdspi/test_apps/sdspi/components/sdspi_tests/sdmmc_test_probe_spi.c +++ b/components/esp_driver_sdspi/test_apps/sdspi/components/sdspi_tests/sdmmc_test_probe_spi.c @@ -8,6 +8,8 @@ #include "sdmmc_cmd.h" #include "sdmmc_test_begin_end_spi.h" +#define SDMMC_FREQ_CUSTOM_10M 10000 + static void do_one_sdspi_probe(int slot, int freq_khz) { sdmmc_card_t card; @@ -36,13 +38,15 @@ TEST_CASE("sdspi probe, slot 1", "[sdspi]") { do_one_sdspi_probe(SLOT_1, SDMMC_FREQ_PROBING); do_one_sdspi_probe(SLOT_1, SDMMC_FREQ_DEFAULT); + do_one_sdspi_probe(SLOT_1, SDMMC_FREQ_CUSTOM_10M); } #endif #if !CONFIG_IDF_TARGET_ESP32 && !CONFIG_IDF_TARGET_ESP32S3 //TODO: IDF-8749 +//here freq should be changed to SDMMC_FREQ_HIGHSPEED after fixing IDF-8749 TEST_CASE("sdspi probe, slot 1, HS", "[sdspi]") { - do_one_sdspi_probe(SLOT_1, SDMMC_FREQ_HIGHSPEED); + do_one_sdspi_probe(SLOT_1, SDMMC_FREQ_DEFAULT); } #endif diff --git a/components/esp_driver_sdspi/test_apps/sdspi/components/sdspi_tests/sdmmc_test_rw_spi.c b/components/esp_driver_sdspi/test_apps/sdspi/components/sdspi_tests/sdmmc_test_rw_spi.c index dcc3c98dd8..a45e5f0c13 100644 --- a/components/esp_driver_sdspi/test_apps/sdspi/components/sdspi_tests/sdmmc_test_rw_spi.c +++ b/components/esp_driver_sdspi/test_apps/sdspi/components/sdspi_tests/sdmmc_test_rw_spi.c @@ -28,9 +28,10 @@ TEST_CASE("sdspi read/write performance, slot 0", "[sdspi]") #if !CONFIG_IDF_TARGET_ESP32 && !CONFIG_IDF_TARGET_ESP32S3 //TODO: IDF-8749 +//here freq should be changed to SDMMC_FREQ_HIGHSPEED after fixing IDF-8749 TEST_CASE("sdspi read/write performance, slot 1", "[sdspi]") { - do_one_sdspi_perf_test(SLOT_1, SDMMC_FREQ_HIGHSPEED); + do_one_sdspi_perf_test(SLOT_1, SDMMC_FREQ_DEFAULT); } #endif @@ -53,9 +54,10 @@ TEST_CASE("sdspi read/write performance with offset, slot 0", "[sdspi]") #if !CONFIG_IDF_TARGET_ESP32 && !CONFIG_IDF_TARGET_ESP32S3 //TODO: IDF-8749 +//here freq should be changed to SDMMC_FREQ_HIGHSPEED after fixing IDF-8749 TEST_CASE("sdspi read/write performance with offset, slot 1", "[sdspi]") { - do_one_sdspi_rw_test_with_offset(SLOT_1, SDMMC_FREQ_HIGHSPEED); + do_one_sdspi_rw_test_with_offset(SLOT_1, SDMMC_FREQ_DEFAULT); } #endif diff --git a/components/sdmmc/test/CMakeLists.txt b/components/sdmmc/test/CMakeLists.txt deleted file mode 100644 index 0648951eec..0000000000 --- a/components/sdmmc/test/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -idf_component_register(SRC_DIRS "." - PRIV_INCLUDE_DIRS "." - PRIV_REQUIRES cmock sdmmc test_utils - ) diff --git a/components/sdmmc/test/test_sd.c b/components/sdmmc/test/test_sd.c deleted file mode 100644 index 775777d7aa..0000000000 --- a/components/sdmmc/test/test_sd.c +++ /dev/null @@ -1,1266 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include -#include -#include -#include "sdkconfig.h" -#include "unity.h" -#include "driver/gpio.h" -#include "soc/soc_caps.h" -#if SOC_SDMMC_HOST_SUPPORTED -#include "driver/sdmmc_host.h" -#endif -#include "driver/sdspi_host.h" -#include "driver/sdmmc_defs.h" -#include "sdmmc_cmd.h" -#include "esp_log.h" -#include "esp_heap_caps.h" -#include "esp_rom_gpio.h" -#include "test_utils.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "soc/gpio_sig_map.h" -#include "soc/gpio_reg.h" - -// Currently no runners for S3 -#define WITH_SD_TEST (SOC_SDMMC_HOST_SUPPORTED && !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S3)) -// Currently, no runners for S3, C2, and C6 -#define WITH_SDSPI_TEST (!TEMPORARY_DISABLED_FOR_TARGETS(ESP32S3, ESP32C2, ESP32C6, ESP32H2)) -// Can't test eMMC (slot 0) and PSRAM together -#define WITH_EMMC_TEST (SOC_SDMMC_HOST_SUPPORTED && !CONFIG_SPIRAM && !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S3)) - -/* power supply enable pin */ -#define SD_TEST_BOARD_VSEL_EN_GPIO 27 - -/* power supply voltage select pin */ -#define SD_TEST_BOARD_VSEL_GPIO 26 -#define SD_TEST_BOARD_VSEL_3V3 1 -#define SD_TEST_BOARD_VSEL_1V8 0 - -/* time to wait for reset / power-on */ -#define SD_TEST_BOARD_PWR_RST_DELAY_MS 5 -#define SD_TEST_BOARD_PWR_ON_DELAY_MS 50 - -/* gpio which is not connected to actual CD pin, used to simulate CD behavior */ -#define CD_WP_TEST_GPIO 18 - -/* default GPIO selection */ -#ifdef CONFIG_IDF_TARGET_ESP32S2 -#define SDSPI_TEST_MOSI_PIN GPIO_NUM_35 -#define SDSPI_TEST_MISO_PIN GPIO_NUM_37 -#define SDSPI_TEST_SCLK_PIN GPIO_NUM_36 -#define SDSPI_TEST_CS_PIN GPIO_NUM_34 -#elif defined(CONFIG_IDF_TARGET_ESP32C3) -#define SDSPI_TEST_MOSI_PIN GPIO_NUM_4 -#define SDSPI_TEST_MISO_PIN GPIO_NUM_6 -#define SDSPI_TEST_SCLK_PIN GPIO_NUM_5 -#define SDSPI_TEST_CS_PIN GPIO_NUM_1 -#else -#define SDSPI_TEST_MOSI_PIN GPIO_NUM_15 -#define SDSPI_TEST_MISO_PIN GPIO_NUM_2 -#define SDSPI_TEST_SCLK_PIN GPIO_NUM_14 -#define SDSPI_TEST_CS_PIN GPIO_NUM_13 -#endif - -#define GPIO_ACTIVE_LOW 0 -#define GPIO_ACTIVE_HIGH 1 - -TEST_CASE("MMC_RSP_BITS", "[sd]") -{ - uint32_t data[2] = { 0x01234567, 0x89abcdef }; - TEST_ASSERT_EQUAL_HEX32(0x7, MMC_RSP_BITS(data, 0, 4)); - TEST_ASSERT_EQUAL_HEX32(0x567, MMC_RSP_BITS(data, 0, 12)); - TEST_ASSERT_EQUAL_HEX32(0xf0, MMC_RSP_BITS(data, 28, 8)); - TEST_ASSERT_EQUAL_HEX32(0x3, MMC_RSP_BITS(data, 1, 3)); - TEST_ASSERT_EQUAL_HEX32(0x11, MMC_RSP_BITS(data, 59, 5)); -} - -#if WITH_SD_TEST || WITH_EMMC_TEST -static void sd_test_board_power_on(void) -{ - gpio_set_direction(SD_TEST_BOARD_VSEL_GPIO, GPIO_MODE_OUTPUT); - gpio_set_level(SD_TEST_BOARD_VSEL_GPIO, SD_TEST_BOARD_VSEL_3V3); - gpio_set_direction(SD_TEST_BOARD_VSEL_EN_GPIO, GPIO_MODE_OUTPUT); - gpio_set_level(SD_TEST_BOARD_VSEL_EN_GPIO, 0); - usleep(SD_TEST_BOARD_PWR_RST_DELAY_MS * 1000); - gpio_set_level(SD_TEST_BOARD_VSEL_EN_GPIO, 1); - usleep(SD_TEST_BOARD_PWR_ON_DELAY_MS * 1000); -} - -static void sd_test_board_power_off(void) -{ - gpio_set_level(SD_TEST_BOARD_VSEL_EN_GPIO, 0); - gpio_set_direction(SD_TEST_BOARD_VSEL_GPIO, GPIO_MODE_INPUT); - gpio_set_level(SD_TEST_BOARD_VSEL_GPIO, 0); - gpio_set_direction(SD_TEST_BOARD_VSEL_EN_GPIO, GPIO_MODE_INPUT); -} - -static void probe_sd(int slot, int width, int freq_khz, int ddr) -{ - sd_test_board_power_on(); - sdmmc_host_t config = SDMMC_HOST_DEFAULT(); - config.slot = slot; - config.max_freq_khz = freq_khz; - sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); - if (width == 1) { - config.flags = SDMMC_HOST_FLAG_1BIT; - slot_config.width = 1; - } else if (width == 4) { - config.flags &= ~SDMMC_HOST_FLAG_8BIT; - slot_config.width = 4; - } else { - assert(!ddr && "host driver does not support 8-line DDR mode yet"); - } - if (!ddr) { - config.flags &= ~SDMMC_HOST_FLAG_DDR; - } - TEST_ESP_OK(sdmmc_host_init()); - TEST_ESP_OK(sdmmc_host_init_slot(slot, &slot_config)); - sdmmc_card_t* card = malloc(sizeof(sdmmc_card_t)); - TEST_ASSERT_NOT_NULL(card); - TEST_ESP_OK(sdmmc_card_init(&config, card)); - sdmmc_card_print_info(stdout, card); - uint8_t* buffer = heap_caps_malloc(512, MALLOC_CAP_DMA); - TEST_ESP_OK(sdmmc_read_sectors(card, buffer, 0, 1)); - free(buffer); - TEST_ESP_OK(sdmmc_host_deinit()); - free(card); - sd_test_board_power_off(); -} - -extern void sdmmc_host_get_clk_dividers(const int freq_khz, int *host_div, int *card_div); - -static void sd_test_check_clk_dividers(const int freq_khz, const int expected_host_div, const int expected_card_div) -{ - printf(" %6d | %2d | %2d\n", freq_khz, expected_host_div, expected_card_div); - int host_divider, card_divider; - sdmmc_host_get_clk_dividers(freq_khz, &host_divider, &card_divider); - TEST_ASSERT_EQUAL(host_divider, expected_host_div); - TEST_ASSERT_EQUAL(card_divider, expected_card_div); -} -#endif //WITH_SD_TEST || WITH_EMMC_TEST - -#if WITH_SD_TEST -TEST_CASE("probe SD, slot 1, 4-bit", "[sd][test_env=UT_T1_SDMODE]") -{ - probe_sd(SDMMC_HOST_SLOT_1, 4, SDMMC_FREQ_PROBING, 0); - probe_sd(SDMMC_HOST_SLOT_1, 4, SDMMC_FREQ_DEFAULT, 0); - probe_sd(SDMMC_HOST_SLOT_1, 4, SDMMC_FREQ_HIGHSPEED, 0); - //custom frequency test - probe_sd(SDMMC_HOST_SLOT_1, 4, 10000, 0); -} - -TEST_CASE("probe SD, slot 1, 1-bit", "[sd][test_env=UT_T1_SDMODE]") -{ - probe_sd(SDMMC_HOST_SLOT_1, 1, SDMMC_FREQ_PROBING, 0); - probe_sd(SDMMC_HOST_SLOT_1, 1, SDMMC_FREQ_DEFAULT, 0); - probe_sd(SDMMC_HOST_SLOT_1, 1, SDMMC_FREQ_HIGHSPEED, 0); -} - -//No runners for slot 0 -TEST_CASE("probe SD, slot 0, 4-bit", "[sd][ignore]") -{ - probe_sd(SDMMC_HOST_SLOT_0, 4, SDMMC_FREQ_PROBING, 0); - probe_sd(SDMMC_HOST_SLOT_0, 4, SDMMC_FREQ_DEFAULT, 0); - probe_sd(SDMMC_HOST_SLOT_0, 4, SDMMC_FREQ_HIGHSPEED, 0); -} - -TEST_CASE("probe SD, slot 0, 1-bit", "[sd][ignore]") -{ - probe_sd(SDMMC_HOST_SLOT_0, 1, SDMMC_FREQ_PROBING, 0); - probe_sd(SDMMC_HOST_SLOT_0, 1, SDMMC_FREQ_DEFAULT, 0); - probe_sd(SDMMC_HOST_SLOT_0, 1, SDMMC_FREQ_HIGHSPEED, 0); -} - -TEST_CASE("SD clock dividers calculation", "[sd][test_env=UT_T1_SDMODE]") -{ - printf("Frequency (kHz) | Expected host.div | Expected card.div\n"); - sd_test_check_clk_dividers(SDMMC_FREQ_PROBING, 10, 20); - sd_test_check_clk_dividers(SDMMC_FREQ_DEFAULT, 8, 0); - sd_test_check_clk_dividers(SDMMC_FREQ_HIGHSPEED, 4, 0); - sd_test_check_clk_dividers(36000, 5, 0); - sd_test_check_clk_dividers(30000, 6, 0); - sd_test_check_clk_dividers(16000, 10, 0); - sd_test_check_clk_dividers(10000, 2, 4); - sd_test_check_clk_dividers(6000, 2, 7); - sd_test_check_clk_dividers(1000, 2, 40); - sd_test_check_clk_dividers(600, 2, 67); -} -#endif //WITH_SD_TEST - -#if WITH_EMMC_TEST -TEST_CASE("probe eMMC, slot 0, 4-bit", "[sd][test_env=EMMC][ignore]") -{ - //Test with SDR - probe_sd(SDMMC_HOST_SLOT_0, 4, SDMMC_FREQ_PROBING, 0); - probe_sd(SDMMC_HOST_SLOT_0, 4, SDMMC_FREQ_DEFAULT, 0); - probe_sd(SDMMC_HOST_SLOT_0, 4, SDMMC_FREQ_HIGHSPEED, 0); - //Test with DDR - probe_sd(SDMMC_HOST_SLOT_0, 4, SDMMC_FREQ_HIGHSPEED, 1); -} - -TEST_CASE("probe eMMC, slot 0, 8-bit", "[sd][test_env=EMMC][ignore]") -{ - //8-bit DDR not supported yet, test with SDR only - probe_sd(SDMMC_HOST_SLOT_0, 8, SDMMC_FREQ_PROBING, 0); - probe_sd(SDMMC_HOST_SLOT_0, 8, SDMMC_FREQ_DEFAULT, 0); - probe_sd(SDMMC_HOST_SLOT_0, 8, SDMMC_FREQ_HIGHSPEED, 0); -} -#endif // WITH_EMMC_TEST - -#if WITH_SDSPI_TEST - -#if !WITH_SD_TEST && !WITH_EMMC_TEST -static void sd_test_board_power_on(void) -{ - // do nothing -} - -static void sd_test_board_power_off(void) -{ - // do nothing -} -#endif - -static void test_sdspi_init_bus(spi_host_device_t host, int mosi_pin, int miso_pin, int clk_pin, int dma_chan) -{ - spi_bus_config_t bus_config = { - .mosi_io_num = mosi_pin, - .miso_io_num = miso_pin, - .sclk_io_num = clk_pin, - .quadwp_io_num = -1, - .quadhd_io_num = -1, - }; - esp_err_t err = spi_bus_initialize(host, &bus_config, dma_chan); - TEST_ESP_OK(err); -} - -static void test_sdspi_deinit_bus(spi_host_device_t host) -{ - esp_err_t err = spi_bus_free(host); - TEST_ESP_OK(err); -} - -static void probe_core(int slot, int freq_khz) -{ - sdmmc_host_t config = SDSPI_HOST_DEFAULT(); - config.slot = slot; - config.max_freq_khz = freq_khz; - - sdmmc_card_t* card = malloc(sizeof(sdmmc_card_t)); - TEST_ASSERT_NOT_NULL(card); - - TEST_ESP_OK(sdmmc_card_init(&config, card)); - sdmmc_card_print_info(stdout, card); - free(card); -} - -static void probe_spi(int freq_khz, int pin_miso, int pin_mosi, int pin_sck, int pin_cs) -{ - sd_test_board_power_on(); - - sdspi_dev_handle_t handle; - sdspi_device_config_t dev_config = SDSPI_DEVICE_CONFIG_DEFAULT(); - dev_config.gpio_cs = pin_cs; - test_sdspi_init_bus(dev_config.host_id, pin_mosi, pin_miso, pin_sck, SPI_DMA_CH_AUTO); - TEST_ESP_OK(sdspi_host_init()); - TEST_ESP_OK(sdspi_host_init_device(&dev_config, &handle)); - - probe_core(handle, freq_khz); - - TEST_ESP_OK(sdspi_host_deinit()); - test_sdspi_deinit_bus(dev_config.host_id); - sd_test_board_power_off(); -} - - -TEST_CASE("probe SD in SPI mode", "[sd][test_env=UT_T1_SPIMODE]") -{ - probe_spi(SDMMC_FREQ_DEFAULT, SDSPI_TEST_MISO_PIN, SDSPI_TEST_MOSI_PIN, SDSPI_TEST_SCLK_PIN, SDSPI_TEST_CS_PIN); - //custom frequency test - probe_spi(10000, SDSPI_TEST_MISO_PIN, SDSPI_TEST_MOSI_PIN, SDSPI_TEST_SCLK_PIN, SDSPI_TEST_CS_PIN); -} - -// No runner for this -TEST_CASE("probe SD in SPI mode, slot 0", "[sd][ignore]") -{ - probe_spi(SDMMC_FREQ_DEFAULT, 7, 11, 6, 10); -} -#endif //WITH_SDSPI_TEST - -#if WITH_SD_TEST || WITH_SDSPI_TEST || WITH_EMMC_TEST -// Fill buffer pointed to by 'dst' with 'count' 32-bit ints generated -// from 'rand' with the starting value of 'seed' -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)); - } -} - -// Check if the buffer pointed to by 'dst' contains 'count' 32-bit -// ints generated from 'rand' with the starting value of 'seed' -static void check_buffer(uint32_t seed, const uint8_t* src, size_t count) { - srand(seed); - for (size_t i = 0; i < count; ++i) { - uint32_t val; - memcpy(&val, src + i * sizeof(uint32_t), sizeof(val)); - TEST_ASSERT_EQUAL_HEX32(rand(), val); - } -} - -static void do_single_write_read_test(sdmmc_card_t* card, size_t start_block, - size_t block_count, size_t alignment, bool performance_log) -{ - size_t block_size = card->csd.sector_size; - size_t total_size = block_size * block_count; - printf(" %8d | %3d | %d | %4.1f ", start_block, block_count, alignment, total_size / 1024.0f); - - uint32_t* buffer = heap_caps_malloc(total_size + 4, MALLOC_CAP_DMA); - size_t offset = alignment % 4; - uint8_t* c_buffer = (uint8_t*) buffer + offset; - fill_buffer(start_block, c_buffer, total_size / sizeof(buffer[0])); - - struct timeval t_start_wr; - gettimeofday(&t_start_wr, NULL); - TEST_ESP_OK(sdmmc_write_sectors(card, c_buffer, start_block, block_count)); - struct timeval t_stop_wr; - gettimeofday(&t_stop_wr, NULL); - float time_wr = 1e3f * (t_stop_wr.tv_sec - t_start_wr.tv_sec) + 1e-3f * (t_stop_wr.tv_usec - t_start_wr.tv_usec); - - memset(buffer, 0xbb, total_size + 4); - - struct timeval t_start_rd; - gettimeofday(&t_start_rd, NULL); - TEST_ESP_OK(sdmmc_read_sectors(card, c_buffer, start_block, block_count)); - struct timeval t_stop_rd; - gettimeofday(&t_stop_rd, NULL); - float time_rd = 1e3f * (t_stop_rd.tv_sec - t_start_rd.tv_sec) + 1e-3f * (t_stop_rd.tv_usec - t_start_rd.tv_usec); - - printf(" | %6.2f | %5.2f | %6.2f | %5.2f\n", - time_wr, total_size / (time_wr / 1000) / (1024 * 1024), - time_rd, total_size / (time_rd / 1000) / (1024 * 1024)); - check_buffer(start_block, c_buffer, total_size / sizeof(buffer[0])); - free(buffer); - - if (performance_log) { - static const char wr_speed_str[] = "SDMMC_WR_SPEED"; - static const char rd_speed_str[] = "SDMMC_RD_SPEED"; - int aligned = ((alignment % 4) == 0)? 1: 0; - IDF_LOG_PERFORMANCE(wr_speed_str, "%d, blk_n: %d, aligned: %d", - (int)(total_size * 1000 / time_wr), block_count, aligned); - IDF_LOG_PERFORMANCE(rd_speed_str, "%d, blk_n: %d, aligned: %d", - (int)(total_size * 1000 / time_rd), block_count, aligned); - } -} - -typedef void (*sd_test_func_t)(sdmmc_card_t* card); - -static void test_read_write_performance(sdmmc_card_t* card) -{ - sdmmc_card_print_info(stdout, card); - printf(" sector | count | align | size(kB) | wr_time(ms) | wr_speed(MB/s) | rd_time(ms) | rd_speed(MB/s)\n"); - const int offset = 0; - const bool do_log = true; - //aligned - do_single_write_read_test(card, offset, 1, 4, do_log); - do_single_write_read_test(card, offset, 4, 4, do_log); - do_single_write_read_test(card, offset, 8, 4, do_log); - do_single_write_read_test(card, offset, 16, 4, do_log); - do_single_write_read_test(card, offset, 32, 4, do_log); - do_single_write_read_test(card, offset, 64, 4, do_log); - do_single_write_read_test(card, offset, 128, 4, do_log); - //unaligned - do_single_write_read_test(card, offset, 1, 1, do_log); - do_single_write_read_test(card, offset, 8, 1, do_log); - do_single_write_read_test(card, offset, 128, 1, do_log); -} - -static void test_read_write_with_offset(sdmmc_card_t* card) -{ - sdmmc_card_print_info(stdout, card); - printf(" sector | count | align | size(kB) | wr_time(ms) | wr_speed(MB/s) | rd_time(ms) | rd_speed(MB/s)\n"); - const bool no_log = false;; - //aligned - do_single_write_read_test(card, 1, 16, 4, no_log); - do_single_write_read_test(card, 16, 32, 4, no_log); - do_single_write_read_test(card, 48, 64, 4, no_log); - do_single_write_read_test(card, 128, 128, 4, no_log); - do_single_write_read_test(card, card->csd.capacity - 64, 32, 4, no_log); - do_single_write_read_test(card, card->csd.capacity - 64, 64, 4, no_log); - do_single_write_read_test(card, card->csd.capacity - 8, 1, 4, no_log); - do_single_write_read_test(card, card->csd.capacity/2, 1, 4, no_log); - do_single_write_read_test(card, card->csd.capacity/2, 4, 4, no_log); - do_single_write_read_test(card, card->csd.capacity/2, 8, 4, no_log); - do_single_write_read_test(card, card->csd.capacity/2, 16, 4, no_log); - do_single_write_read_test(card, card->csd.capacity/2, 32, 4, no_log); - do_single_write_read_test(card, card->csd.capacity/2, 64, 4, no_log); - do_single_write_read_test(card, card->csd.capacity/2, 128, 4, no_log); - //unaligned - do_single_write_read_test(card, card->csd.capacity/2, 1, 1, no_log); - do_single_write_read_test(card, card->csd.capacity/2, 8, 1, no_log); - do_single_write_read_test(card, card->csd.capacity/2, 128, 1, no_log); -} -#endif //WITH_SD_TEST || WITH_SDSPI_TEST || WITH_EMMC_TEST - -#if WITH_SD_TEST || WITH_EMMC_TEST -void sd_test_rw_blocks(int slot, int width, sd_test_func_t test_func) -{ - sdmmc_host_t config = SDMMC_HOST_DEFAULT(); - config.max_freq_khz = SDMMC_FREQ_HIGHSPEED; - config.slot = slot; - sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); - if (width != 0) { - slot_config.width = width; - } - if (slot_config.width == 8) { - config.flags &= ~SDMMC_HOST_FLAG_DDR; - } - TEST_ESP_OK(sdmmc_host_init()); - TEST_ESP_OK(sdmmc_host_init_slot(slot, &slot_config)); - sdmmc_card_t* card = malloc(sizeof(sdmmc_card_t)); - TEST_ASSERT_NOT_NULL(card); - TEST_ESP_OK(sdmmc_card_init(&config, card)); - test_func(card); - free(card); - TEST_ESP_OK(sdmmc_host_deinit()); -} -#endif //WITH_SD_TEST || WITH_EMMC_TEST - -#if WITH_SD_TEST -TEST_CASE("SDMMC performance test (SD slot 1, 4 line)", "[sd][test_env=UT_T1_SDMODE]") -{ - sd_test_board_power_on(); - sd_test_rw_blocks(1, 4, test_read_write_performance); - sd_test_board_power_off(); -} - -TEST_CASE("SDMMC performance test (SD slot 1, 1 line)", "[sd][test_env=UT_T1_SDMODE]") -{ - sd_test_board_power_on(); - sd_test_rw_blocks(1, 1, test_read_write_performance); - sd_test_board_power_off(); -} - -TEST_CASE("SDMMC test read/write with offset (SD slot 1)", "[sd][test_env=UT_T1_SDMODE]") -{ - sd_test_board_power_on(); - sd_test_rw_blocks(1, 4, test_read_write_with_offset); - sd_test_board_power_off(); -} -#endif //WITH_SD_TEST - -#if WITH_EMMC_TEST -TEST_CASE("SDMMC performance test (eMMC slot 0, 4 line DDR)", "[sd][test_env=EMMC][ignore]") -{ - sd_test_board_power_on(); - sd_test_rw_blocks(0, 4, test_read_write_performance); - sd_test_board_power_off(); -} - -TEST_CASE("SDMMC test read/write with offset (eMMC slot 0, 4 line DDR)", "[sd][test_env=EMMC][ignore]") -{ - sd_test_board_power_on(); - sd_test_rw_blocks(0, 4, test_read_write_with_offset); - sd_test_board_power_off(); -} - -TEST_CASE("SDMMC performance test (eMMC slot 0, 8 line)", "[sd][test_env=EMMC][ignore]") -{ - sd_test_board_power_on(); - sd_test_rw_blocks(0, 8, test_read_write_performance); - sd_test_board_power_off(); -} - -TEST_CASE("SDMMC test read/write with offset (eMMC slot 0, 8 line)", "[sd][test_env=EMMC][ignore]") -{ - sd_test_board_power_on(); - sd_test_rw_blocks(0, 8, test_read_write_with_offset); - sd_test_board_power_off(); -} -#endif // WITH_EMMC_TEST - -#if WITH_SDSPI_TEST -void sdspi_test_rw_blocks(sd_test_func_t test_func) -{ - sd_test_board_power_on(); - - sdmmc_host_t config = SDSPI_HOST_DEFAULT(); - sdspi_dev_handle_t handle; - sdspi_device_config_t dev_config = SDSPI_DEVICE_CONFIG_DEFAULT(); - dev_config.host_id = config.slot; - dev_config.gpio_cs = SDSPI_TEST_CS_PIN; - test_sdspi_init_bus(dev_config.host_id, SDSPI_TEST_MOSI_PIN, SDSPI_TEST_MISO_PIN, SDSPI_TEST_SCLK_PIN, SPI_DMA_CH_AUTO); - TEST_ESP_OK(sdspi_host_init()); - TEST_ESP_OK(sdspi_host_init_device(&dev_config, &handle)); - - // This test can only run under 20MHz on ESP32, because the runner connects the card to - // non-IOMUX pins of HSPI. - - sdmmc_card_t* card = malloc(sizeof(sdmmc_card_t)); - TEST_ASSERT_NOT_NULL(card); - TEST_ESP_OK(sdmmc_card_init(&config, card)); - test_func(card); - TEST_ESP_OK(sdspi_host_deinit()); - free(card); - test_sdspi_deinit_bus(dev_config.host_id); - sd_test_board_power_off(); -} - -TEST_CASE("SDMMC performance (SPI mode)", "[sdspi][test_env=UT_T1_SPIMODE]") -{ - sdspi_test_rw_blocks(test_read_write_performance); -} - -TEST_CASE("SDMMC test read/write with offset (SPI mode)", "[sdspi][test_env=UT_T1_SPIMODE]") -{ - sdspi_test_rw_blocks(test_read_write_with_offset); -} -#endif //WITH_SDSPI_TEST - -#if WITH_SD_TEST -TEST_CASE("reads and writes with an unaligned buffer", "[sd][test_env=UT_T1_SDMODE]") -{ - sd_test_board_power_on(); - sdmmc_host_t config = SDMMC_HOST_DEFAULT(); - sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); - TEST_ESP_OK(sdmmc_host_init()); - - TEST_ESP_OK(sdmmc_host_init_slot(SDMMC_HOST_SLOT_1, &slot_config)); - sdmmc_card_t* card = malloc(sizeof(sdmmc_card_t)); - TEST_ASSERT_NOT_NULL(card); - TEST_ESP_OK(sdmmc_card_init(&config, card)); - - const size_t buffer_size = 4096; - const size_t block_count = buffer_size / 512; - const size_t extra = 4; - uint8_t* buffer = heap_caps_malloc(buffer_size + extra, MALLOC_CAP_DMA); - - // Check read behavior: do aligned write, then unaligned read - const uint32_t seed = 0x89abcdef; - fill_buffer(seed, buffer, buffer_size / sizeof(uint32_t)); - TEST_ESP_OK(sdmmc_write_sectors(card, buffer, 0, block_count)); - memset(buffer, 0xcc, buffer_size + extra); - TEST_ESP_OK(sdmmc_read_sectors(card, buffer + 1, 0, block_count)); - check_buffer(seed, buffer + 1, buffer_size / sizeof(uint32_t)); - - // Check write behavior: do unaligned write, then aligned read - fill_buffer(seed, buffer + 1, buffer_size / sizeof(uint32_t)); - TEST_ESP_OK(sdmmc_write_sectors(card, buffer + 1, 8, block_count)); - memset(buffer, 0xcc, buffer_size + extra); - TEST_ESP_OK(sdmmc_read_sectors(card, buffer, 8, block_count)); - check_buffer(seed, buffer, buffer_size / sizeof(uint32_t)); - - free(buffer); - free(card); - TEST_ESP_OK(sdmmc_host_deinit()); - sd_test_board_power_off(); -} -#endif //WITH_SD_TEST - -#if WITH_SD_TEST || WITH_SDSPI_TEST -static void test_cd_input(int gpio_cd_num, const sdmmc_host_t* config) -{ - sdmmc_card_t* card = malloc(sizeof(sdmmc_card_t)); - TEST_ASSERT_NOT_NULL(card); - - // SDMMC host should have configured CD as input. - // Enable output as well (not using the driver, to avoid touching input - // enable bits). - esp_rom_gpio_connect_out_signal(gpio_cd_num, SIG_GPIO_OUT_IDX, false, false); - REG_WRITE(GPIO_ENABLE_W1TS_REG, BIT(gpio_cd_num)); - - // Check that card initialization fails if CD is high - REG_WRITE(GPIO_OUT_W1TS_REG, BIT(gpio_cd_num)); - usleep(10000); - TEST_ESP_ERR(ESP_ERR_NOT_FOUND, sdmmc_card_init(config, card)); - - // Check that card initialization succeeds if CD is low - REG_WRITE(GPIO_OUT_W1TC_REG, BIT(gpio_cd_num)); - usleep(10000); - esp_err_t err = sdmmc_card_init(config, card); - if (err != ESP_OK) { - usleep(10000); - // Try again, in case the card was not ready yet - err = sdmmc_card_init(config, card); - } - TEST_ESP_OK(err); - - free(card); -} - -static void test_wp_input(int gpio_wp_num, bool gpio_wp_polarity, const sdmmc_host_t* config) -{ - sdmmc_card_t* card = malloc(sizeof(sdmmc_card_t)); - TEST_ASSERT_NOT_NULL(card); - - // SDMMC host should have configured WP as input. - // Enable output as well (not using the driver, to avoid touching input - // enable bits). - esp_rom_gpio_connect_out_signal(gpio_wp_num, SIG_GPIO_OUT_IDX, false, false); - REG_WRITE(GPIO_ENABLE_W1TS_REG, BIT(gpio_wp_num)); - - // Check that the card can be initialized with WP low - REG_WRITE(GPIO_OUT_W1TC_REG, BIT(gpio_wp_num)); - TEST_ESP_OK(sdmmc_card_init(config, card)); - - uint32_t* data = heap_caps_calloc(1, 512, MALLOC_CAP_DMA); - - // Check that card write succeeds if WP is high - REG_WRITE((gpio_wp_polarity? GPIO_OUT_W1TC_REG : GPIO_OUT_W1TS_REG), BIT(gpio_wp_num)); - usleep(1000); - TEST_ESP_OK(sdmmc_write_sectors(card, &data, 0, 1)); - - // Check that write fails if WP is low - REG_WRITE((gpio_wp_polarity? GPIO_OUT_W1TS_REG : GPIO_OUT_W1TC_REG), BIT(gpio_wp_num)); - usleep(1000); - TEST_ESP_ERR(ESP_ERR_INVALID_STATE, sdmmc_write_sectors(card, &data, 0, 1)); - // ...but reads still work - TEST_ESP_OK(sdmmc_read_sectors(card, &data, 0, 1)); - - free(data); - free(card); -} -#endif //WITH_SD_TEST || WITH_SDSPI_TEST - -#if WITH_SD_TEST -TEST_CASE("CD input works in SD mode", "[sd][test_env=UT_T1_SDMODE]") -{ - sd_test_board_power_on(); - sdmmc_host_t config = SDMMC_HOST_DEFAULT(); - sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); - slot_config.gpio_cd = CD_WP_TEST_GPIO; - TEST_ESP_OK(sdmmc_host_init()); - usleep(10000); - TEST_ESP_OK(sdmmc_host_init_slot(SDMMC_HOST_SLOT_1, &slot_config)); - - test_cd_input(CD_WP_TEST_GPIO, &config); - - TEST_ESP_OK(sdmmc_host_deinit()); - sd_test_board_power_off(); -} - -TEST_CASE("WP input works in SD mode", "[sd][test_env=UT_T1_SDMODE]") -{ - sd_test_board_power_on(); - sdmmc_host_t config = SDMMC_HOST_DEFAULT(); - sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); - slot_config.gpio_wp = CD_WP_TEST_GPIO; - bool gpio_wp_polarity = GPIO_ACTIVE_LOW; - if (gpio_wp_polarity) { - slot_config.flags |= SDMMC_SLOT_FLAG_WP_ACTIVE_HIGH; - } else { - slot_config.flags &= ~(SDMMC_SLOT_FLAG_WP_ACTIVE_HIGH); - } - TEST_ESP_OK(sdmmc_host_init()); - usleep(10000); - TEST_ESP_OK(sdmmc_host_init_slot(SDMMC_HOST_SLOT_1, &slot_config)); - - test_wp_input(slot_config.gpio_wp, gpio_wp_polarity, &config); - - TEST_ESP_OK(sdmmc_host_deinit()); - sd_test_board_power_off(); -} -#endif //WITH_SD_TEST - -#if WITH_SDSPI_TEST -TEST_CASE("CD input works in SPI mode", "[sd][test_env=UT_T1_SPIMODE]") -{ - sd_test_board_power_on(); - - sdmmc_host_t config = SDSPI_HOST_DEFAULT(); - sdspi_dev_handle_t handle; - sdspi_device_config_t dev_config = SDSPI_DEVICE_CONFIG_DEFAULT(); - dev_config.host_id = config.slot; - dev_config.gpio_cs = SDSPI_TEST_CS_PIN; - dev_config.gpio_cd = CD_WP_TEST_GPIO; - test_sdspi_init_bus(dev_config.host_id, SDSPI_TEST_MOSI_PIN, SDSPI_TEST_MISO_PIN, SDSPI_TEST_SCLK_PIN, SPI_DMA_CH_AUTO); - TEST_ESP_OK(sdspi_host_init()); - TEST_ESP_OK(sdspi_host_init_device(&dev_config, &handle)); - - config.slot = handle; - - test_cd_input(CD_WP_TEST_GPIO, &config); - - TEST_ESP_OK(sdspi_host_deinit()); - test_sdspi_deinit_bus(dev_config.host_id); - sd_test_board_power_off(); -} - -TEST_CASE("WP input works in SPI mode", "[sd][test_env=UT_T1_SPIMODE]") -{ - sd_test_board_power_on(); - - sdmmc_host_t config = SDSPI_HOST_DEFAULT(); - sdspi_dev_handle_t handle; - sdspi_device_config_t dev_config = SDSPI_DEVICE_CONFIG_DEFAULT(); - dev_config.host_id = config.slot; - dev_config.gpio_cs = SDSPI_TEST_CS_PIN; - dev_config.gpio_wp = CD_WP_TEST_GPIO; - dev_config.gpio_wp_polarity = GPIO_ACTIVE_LOW; - test_sdspi_init_bus(dev_config.host_id, SDSPI_TEST_MOSI_PIN, SDSPI_TEST_MISO_PIN, SDSPI_TEST_SCLK_PIN, SPI_DMA_CH_AUTO); - - TEST_ESP_OK(sdspi_host_init()); - TEST_ESP_OK(sdspi_host_init_device(&dev_config, &handle)); - - config.slot = handle; - - test_wp_input(dev_config.gpio_wp, dev_config.gpio_wp_polarity, &config); - - TEST_ESP_OK(sdspi_host_deinit()); - test_sdspi_deinit_bus(dev_config.host_id); - sd_test_board_power_off(); -} -#endif //WITH_SDSPI_TEST - -#if WITH_SD_TEST || WITH_EMMC_TEST - -#define PATTERN_SEED 0x12345678 -#define FLAG_ERASE_TEST_ADJACENT (1 << 0) -#define FLAG_VERIFY_ERASE_STATE (1 << 1) -bool do_sanitize_flag = false; -static void ensure_sector_written(sdmmc_card_t* card, size_t sector, - uint8_t *pattern_buf, uint8_t *temp_buf) -{ - size_t block_size = card->csd.sector_size; - TEST_ESP_OK(sdmmc_write_sectors(card, pattern_buf, sector, 1)); - memset((void *)temp_buf, 0x00, block_size); - TEST_ESP_OK(sdmmc_read_sectors(card, temp_buf, sector, 1)); - check_buffer(PATTERN_SEED, temp_buf, block_size / sizeof(uint32_t)); -} - -static void ensure_sector_intact(sdmmc_card_t* card, size_t sector, - uint8_t *pattern_buf, uint8_t *temp_buf) -{ - size_t block_size = card->csd.sector_size; - memset((void *)temp_buf, 0x00, block_size); - TEST_ESP_OK(sdmmc_read_sectors(card, temp_buf, sector, 1)); - check_buffer(PATTERN_SEED, temp_buf, block_size / sizeof(uint32_t)); -} - -static int32_t ensure_sector_erase(sdmmc_card_t* card, size_t sector, - uint8_t *pattern_buf, uint8_t *temp_buf) -{ - size_t block_size = card->csd.sector_size; - memset((void *)temp_buf, 0, block_size); - TEST_ESP_OK(sdmmc_read_sectors(card, temp_buf, sector, 1)); - return memcmp(pattern_buf, temp_buf, block_size); -} - -static void do_single_erase_test(sdmmc_card_t* card, size_t start_block, - size_t block_count, uint8_t flags, sdmmc_erase_arg_t arg) -{ - size_t block_size = card->csd.sector_size; - uint8_t *temp_buf = NULL; - uint8_t *pattern_buf = NULL; - size_t end_block = (start_block + block_count - 1); - - /* - * To ensure erase is successful/valid - * selected blocks after erase should have erase state data pattern - * data of blocks adjacent to selected region should remain intact - */ - TEST_ESP_OK((start_block + block_count) > card->csd.capacity); - - pattern_buf = (uint8_t *)heap_caps_malloc(block_size, MALLOC_CAP_DMA); - TEST_ASSERT_NOT_NULL(pattern_buf); - temp_buf = (uint8_t *)heap_caps_malloc(block_size, MALLOC_CAP_DMA); - TEST_ASSERT_NOT_NULL(temp_buf); - - // create pattern buffer - fill_buffer(PATTERN_SEED, pattern_buf, block_size / sizeof(uint32_t)); - - // check if it's not the first block of device & write/read/verify pattern - if ((flags & FLAG_ERASE_TEST_ADJACENT) && start_block) { - ensure_sector_written(card, (start_block - 1), pattern_buf, temp_buf); - } - - ensure_sector_written(card, start_block, pattern_buf, temp_buf); - - // check if it's not the last block of device & write/read/verify pattern - if ((flags & FLAG_ERASE_TEST_ADJACENT) && (end_block < (card->csd.capacity - 1))) { - ensure_sector_written(card, (end_block + 1), pattern_buf, temp_buf); - } - - // when block count is 1, start and end block is same, hence skip - if (block_count != 1) { - ensure_sector_written(card, end_block, pattern_buf, temp_buf); - } - - // fill pattern to (start_block + end_block)/2 in the erase range - if(block_count > 2) { - ensure_sector_written(card, (start_block + end_block)/2, pattern_buf, temp_buf); - } - - float total_size = (block_count/1024.0f) * block_size; - printf(" %10d | %10d | %8.1f ", start_block, block_count, total_size); - fflush(stdout); - - // erase the blocks - struct timeval t_start_er; - gettimeofday(&t_start_er, NULL); - TEST_ESP_OK(sdmmc_erase_sectors(card, start_block, block_count, arg)); - if (do_sanitize_flag) { - TEST_ESP_OK(sdmmc_mmc_sanitize(card, block_count * 500)); - } - struct timeval t_stop_wr; - gettimeofday(&t_stop_wr, NULL); - float time_er = 1e3f * (t_stop_wr.tv_sec - t_start_er.tv_sec) + 1e-3f * (t_stop_wr.tv_usec - t_start_er.tv_usec); - printf(" | %8.2f\n", time_er); - - // ensure adjacent blocks are not affected - // block before start_block - if ((flags & FLAG_ERASE_TEST_ADJACENT) && start_block) { - ensure_sector_intact(card, (start_block - 1), pattern_buf, temp_buf); - } - - // block after end_block - if ((flags & FLAG_ERASE_TEST_ADJACENT) && (end_block < (card->csd.capacity - 1))) { - ensure_sector_intact(card, (end_block + 1), pattern_buf, temp_buf); - } - - uint8_t erase_mem_byte = 0xFF; - // ensure all the blocks are erased and are up to after erase state. - if (!card->is_mmc) { - erase_mem_byte = card->scr.erase_mem_state ? 0xFF : 0x00; - } else { - erase_mem_byte = card->ext_csd.erase_mem_state ? 0xFF : 0x00; - } - - memset((void *)pattern_buf, erase_mem_byte, block_size); - - // as it is block by block comparison, a time taking process. Really long - // when you do erase and verify on complete device. - if (flags & FLAG_VERIFY_ERASE_STATE) { - for (size_t i = 0; i < block_count; i++) { - if (ensure_sector_erase(card, (start_block + i), pattern_buf, temp_buf)) { - printf("Error: Sector %d erase\n", (start_block + i)); - break; - } - } - } - - free(temp_buf); - free(pattern_buf); -} -#endif // WITH_SD_TEST || WITH_EMMC_TEST - -#if WITH_SDSPI_TEST -static void test_sdspi_erase_blocks(size_t start_block, size_t block_count) -{ - sd_test_board_power_on(); - sdmmc_host_t config = SDSPI_HOST_DEFAULT(); - sdspi_dev_handle_t handle; - sdspi_device_config_t dev_config = SDSPI_DEVICE_CONFIG_DEFAULT(); - dev_config.host_id = config.slot; - dev_config.gpio_cs = SDSPI_TEST_CS_PIN; - test_sdspi_init_bus(dev_config.host_id, SDSPI_TEST_MOSI_PIN, SDSPI_TEST_MISO_PIN, SDSPI_TEST_SCLK_PIN, SPI_DMA_CH_AUTO); - TEST_ESP_OK(sdspi_host_init()); - TEST_ESP_OK(sdspi_host_init_device(&dev_config, &handle)); - - // This test can only run under 20MHz on ESP32, because the runner connects the card to - // non-IOMUX pins of HSPI. - - sdmmc_card_t* card = malloc(sizeof(sdmmc_card_t)); - TEST_ASSERT_NOT_NULL(card); - TEST_ESP_OK(sdmmc_card_init(&config, card)); - sdmmc_card_print_info(stdout, card); - - // Ensure discard operation is not supported in sdspi - TEST_ESP_ERR(ESP_ERR_NOT_SUPPORTED, sdmmc_erase_sectors(card, start_block, block_count, SDMMC_DISCARD_ARG)); - - printf("block size %d capacity %d\n", card->csd.sector_size, card->csd.capacity); - printf("Erasing sectors %d-%d\n", start_block, (start_block + block_count -1)); - size_t block_size = card->csd.sector_size; - uint8_t *pattern_buf = (uint8_t *)heap_caps_malloc(block_size, MALLOC_CAP_DMA); - TEST_ASSERT_NOT_NULL(pattern_buf); - uint8_t *temp_buf = (uint8_t *)heap_caps_malloc(block_size, MALLOC_CAP_DMA); - TEST_ASSERT_NOT_NULL(temp_buf); - - struct timeval t_start_er; - gettimeofday(&t_start_er, NULL); - TEST_ESP_OK(sdmmc_erase_sectors(card, start_block, block_count, SDMMC_ERASE_ARG)); - struct timeval t_stop_wr; - gettimeofday(&t_stop_wr, NULL); - float time_er = 1e3f * (t_stop_wr.tv_sec - t_start_er.tv_sec) + 1e-3f * (t_stop_wr.tv_usec - t_start_er.tv_usec); - printf("Erase duration: %.2fms\n", time_er); - - printf("Verifying erase state...\n"); - uint8_t erase_mem_byte = 0xFF; - // ensure all the blocks are erased and are up to after erase state. - if (!card->is_mmc) { - erase_mem_byte = card->scr.erase_mem_state ? 0xFF : 0x00; - } else { - erase_mem_byte = card->ext_csd.erase_mem_state ? 0xFF : 0x00; - } - - memset((void *)pattern_buf, erase_mem_byte, block_size); - - size_t i; - for (i = 0; i < block_count; i++) { - memset((void *)temp_buf, 0, block_size); - TEST_ESP_OK(sdmmc_read_sectors(card, temp_buf, (start_block + i), 1)); - if (memcmp(pattern_buf, temp_buf, block_size)) { - printf("Error: Sector %d erase\n", (start_block + i)); - break; - } - } - if (i == block_count) { - printf("Sectors erase success\n"); - } - TEST_ESP_OK(sdspi_host_deinit()); - test_sdspi_deinit_bus(dev_config.host_id); - free(card); - free(temp_buf); - free(pattern_buf); - sd_test_board_power_off(); -} - -TEST_CASE("SDMMC erase (SPI mode)", "[sdspi][test_env=UT_T1_SPIMODE]") -{ - test_sdspi_erase_blocks(0, 16); -} -#endif // WITH_SDSPI_TEST - -#if WITH_SD_TEST -static void test_sd_erase_blocks(sdmmc_card_t* card) -{ - sdmmc_card_print_info(stdout, card); - printf("block size %d capacity %d\n", card->csd.sector_size, card->csd.capacity); - printf(" sector | count | size(kB) | er_time(ms) \n"); - /* - * bit-0: verify adjacent blocks of given range - * bit-1: verify erase state of blocks in range - */ - uint8_t flags = 0; - sdmmc_erase_arg_t arg = SDMMC_ERASE_ARG; - - //check for adjacent blocks and erase state of blocks - flags |= (uint8_t)FLAG_ERASE_TEST_ADJACENT | (uint8_t)FLAG_VERIFY_ERASE_STATE; - do_single_erase_test(card, 1, 16, flags, arg); - do_single_erase_test(card, 1, 13, flags, arg); - do_single_erase_test(card, 16, 32, flags, arg); - do_single_erase_test(card, 48, 64, flags, arg); - do_single_erase_test(card, 128, 128, flags, arg); - do_single_erase_test(card, card->csd.capacity - 64, 32, flags, arg); - do_single_erase_test(card, card->csd.capacity - 64, 64, flags, arg); - // single sector erase is failing on different make cards - do_single_erase_test(card, card->csd.capacity - 8, 1, flags, arg); - do_single_erase_test(card, card->csd.capacity/2, 1, flags, arg); - do_single_erase_test(card, card->csd.capacity/2, 4, flags, arg); - do_single_erase_test(card, card->csd.capacity/2, 8, flags, arg); - do_single_erase_test(card, card->csd.capacity/2, 16, flags, arg); - do_single_erase_test(card, card->csd.capacity/2, 32, flags, arg); - do_single_erase_test(card, card->csd.capacity/2, 64, flags, arg); - do_single_erase_test(card, card->csd.capacity/2, 128, flags, arg); -#ifdef SDMMC_FULL_ERASE_TEST - /* - * check for adjacent blocks, do not check erase state of blocks as it is - * time taking process to verify all the blocks. - */ - flags &= ~(uint8_t)FLAG_VERIFY_ERASE_STATE; //comment this line to verify after-erase state - // erase complete card - do_single_erase_test(card, 0, card->csd.capacity, flags, arg); -#endif //SDMMC_FULL_ERASE_TEST -} - -static void test_sd_discard_blocks(sdmmc_card_t* card) -{ - /* MMC discard applies to write blocks */ - sdmmc_card_print_info(stdout, card); - /* - * bit-0: verify adjacent blocks of given range - * bit-1: verify erase state of blocks in range - */ - uint8_t flags = 0; - sdmmc_erase_arg_t arg = SDMMC_DISCARD_ARG; - - /* - * This test does run two tests - * test-1: check, sdmmc_erase_sectors to return ESP_ERR_NOT_SUPPORTED - * when arguments are condition not met. This test runs either the card - * supports discard or not. - * - * test-2: If card supports discard, perform the test accordingly and - * validate the behavior. - * - */ - uint32_t prev_discard_support = card->ssr.discard_support; - // overwrite discard_support as not-supported for -ve test - card->ssr.discard_support = 0; - TEST_ESP_ERR(ESP_ERR_NOT_SUPPORTED, sdmmc_erase_sectors(card, 0, 32, arg)); - // restore discard_support - card->ssr.discard_support = prev_discard_support; - if (sdmmc_can_discard(card) != ESP_OK ) { - printf("Card/device do not support discard\n"); - return; - } - - printf("block size %d capacity %d\n", card->csd.sector_size, card->csd.capacity); - printf(" sector | count | size(kB) | er_time(ms) \n"); - /* - * Check for adjacent blocks only. - * After discard operation, the original data may be remained partially or - * fully accessible to the host dependent on device. Hence do not verify - * the erased state of the blocks. - */ - flags |= (uint8_t)FLAG_ERASE_TEST_ADJACENT; - do_single_erase_test(card, 1, 16, flags, arg); - do_single_erase_test(card, 1, 13, flags, arg); - do_single_erase_test(card, 16, 32, flags, arg); - do_single_erase_test(card, 48, 64, flags, arg); - do_single_erase_test(card, 128, 128, flags, arg); - do_single_erase_test(card, card->csd.capacity - 64, 32, flags, arg); - do_single_erase_test(card, card->csd.capacity - 64, 64, flags, arg); - do_single_erase_test(card, card->csd.capacity - 8, 1, flags, arg); - do_single_erase_test(card, card->csd.capacity/2, 1, flags, arg); - do_single_erase_test(card, card->csd.capacity/2, 4, flags, arg); - do_single_erase_test(card, card->csd.capacity/2, 8, flags, arg); - do_single_erase_test(card, card->csd.capacity/2, 16, flags, arg); - do_single_erase_test(card, card->csd.capacity/2, 32, flags, arg); - do_single_erase_test(card, card->csd.capacity/2, 64, flags, arg); - do_single_erase_test(card, card->csd.capacity/2, 128, flags, arg); -} - -TEST_CASE("SDMMC erase test (SD slot 1, 1 line)", "[sd][test_env=UT_T1_SDMODE]") -{ - sd_test_board_power_on(); - sd_test_rw_blocks(1, 1, test_sd_erase_blocks); - sd_test_board_power_off(); -} - -TEST_CASE("SDMMC erase test (SD slot 1, 4 line)", "[sd][test_env=UT_T1_SDMODE]") -{ - sd_test_board_power_on(); - sd_test_rw_blocks(1, 4, test_sd_erase_blocks); - sd_test_board_power_off(); -} - -TEST_CASE("SDMMC discard test (SD slot 1, 4 line)", "[sd][test_env=UT_T1_SDMODE]") -{ - sd_test_board_power_on(); - sd_test_rw_blocks(1, 4, test_sd_discard_blocks); - sd_test_board_power_off(); -} -#endif //WITH_SD_TEST - -#if WITH_SD_TEST -TEST_CASE("sdmmc read/write/erase sector shoud return ESP_OK with sector count == 0", "[sd][test_env=UT_T1_SDMODE]") -{ - sd_test_board_power_on(); - sdmmc_host_t config = SDMMC_HOST_DEFAULT(); - sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); - TEST_ESP_OK(sdmmc_host_init()); - - TEST_ESP_OK(sdmmc_host_init_slot(SDMMC_HOST_SLOT_1, &slot_config)); - sdmmc_card_t* card = malloc(sizeof(sdmmc_card_t)); - TEST_ASSERT_NOT_NULL(card); - TEST_ESP_OK(sdmmc_card_init(&config, card)); - - TEST_ESP_OK(sdmmc_write_sectors(card, NULL, 0, 0)); - TEST_ESP_OK(sdmmc_read_sectors(card, NULL, 0, 0)); - TEST_ESP_OK(sdmmc_erase_sectors(card, 0, 0, SDMMC_ERASE_ARG)); - - free(card); - TEST_ESP_OK(sdmmc_host_deinit()); - sd_test_board_power_off(); -} -#endif //WITH_SD_TEST - -#if WITH_EMMC_TEST -static void test_mmc_sanitize_blocks(sdmmc_card_t* card) -{ - /* MMC discard applies to write blocks */ - sdmmc_card_print_info(stdout, card); - printf("block size %d capacity %d\n", card->csd.sector_size, card->csd.capacity); - - if (sdmmc_mmc_can_sanitize(card)) { - printf("Card/device do not support sanitize\n"); - return; - } - printf(" sector | count | size(kB) | er_time(ms) \n"); - /* - * bit-0: verify adjacent blocks of given range - * bit-1: verify erase state of blocks in range - */ - uint8_t flags = 0; - sdmmc_erase_arg_t arg = SDMMC_DISCARD_ARG; - do_sanitize_flag = true; - - /* - * Check for adjacent blocks only. - * After discard operation, the original data may be remained partially or - * fully accessible to the host dependent on device. Hence do not verify - * the erased state of the blocks. - * - * Note: After sanitize blocks has to be in erased state - */ - flags |= (uint8_t)FLAG_ERASE_TEST_ADJACENT | (uint8_t)FLAG_VERIFY_ERASE_STATE; - do_single_erase_test(card, 1, 16, flags, arg); - do_single_erase_test(card, 1, 13, flags, arg); - do_single_erase_test(card, 16, 32, flags, arg); - do_single_erase_test(card, 48, 64, flags, arg); - do_single_erase_test(card, 128, 128, flags, arg); - do_single_erase_test(card, card->csd.capacity - 64, 32, flags, arg); - do_single_erase_test(card, card->csd.capacity - 64, 64, flags, arg); - do_single_erase_test(card, card->csd.capacity - 8, 1, flags, arg); - do_single_erase_test(card, card->csd.capacity/2, 1, flags, arg); - do_single_erase_test(card, card->csd.capacity/2, 4, flags, arg); - do_single_erase_test(card, card->csd.capacity/2, 8, flags, arg); - do_single_erase_test(card, card->csd.capacity/2, 16, flags, arg); - do_single_erase_test(card, card->csd.capacity/2, 32, flags, arg); - do_single_erase_test(card, card->csd.capacity/2, 64, flags, arg); - do_single_erase_test(card, card->csd.capacity/2, 128, flags, arg); - do_sanitize_flag = false; -} - -static void test_mmc_discard_blocks(sdmmc_card_t* card) -{ - /* MMC discard applies to write blocks */ - sdmmc_card_print_info(stdout, card); - printf("block size %d capacity %d\n", card->csd.sector_size, card->csd.capacity); - - sdmmc_erase_arg_t arg = SDMMC_DISCARD_ARG; - uint32_t prev_ext_csd = card->ext_csd.rev; - // overwrite discard_support as not-supported for -ve test - card->ext_csd.rev = 0; - TEST_ESP_ERR(ESP_ERR_NOT_SUPPORTED, sdmmc_erase_sectors(card, 0, 32, arg)); - // restore discard_support - card->ext_csd.rev = prev_ext_csd; - if (sdmmc_can_discard(card) != ESP_OK) { - printf("Card/device do not support discard\n"); - return; - } - - printf(" sector | count | size(kB) | er_time(ms) \n"); - /* - * bit-0: verify adjacent blocks of given range - * bit-1: verify erase state of blocks in range - */ - uint8_t flags = 0; - - /* - * Check for adjacent blocks only. - * After discard operation, the original data may be remained partially or - * fully accessible to the host dependent on device. Hence do not verify - * the erased state of the blocks. - */ - flags |= (uint8_t)FLAG_ERASE_TEST_ADJACENT; - do_single_erase_test(card, 1, 16, flags, arg); - do_single_erase_test(card, 1, 13, flags, arg); - do_single_erase_test(card, 16, 32, flags, arg); - do_single_erase_test(card, 48, 64, flags, arg); - do_single_erase_test(card, 128, 128, flags, arg); - do_single_erase_test(card, card->csd.capacity - 64, 32, flags, arg); - do_single_erase_test(card, card->csd.capacity - 64, 64, flags, arg); - do_single_erase_test(card, card->csd.capacity - 8, 1, flags, arg); - do_single_erase_test(card, card->csd.capacity/2, 1, flags, arg); - do_single_erase_test(card, card->csd.capacity/2, 4, flags, arg); - do_single_erase_test(card, card->csd.capacity/2, 8, flags, arg); - do_single_erase_test(card, card->csd.capacity/2, 16, flags, arg); - do_single_erase_test(card, card->csd.capacity/2, 32, flags, arg); - do_single_erase_test(card, card->csd.capacity/2, 64, flags, arg); - do_single_erase_test(card, card->csd.capacity/2, 128, flags, arg); -} - -static void test_mmc_trim_blocks(sdmmc_card_t* card) -{ - /* MMC trim applies to write blocks */ - sdmmc_card_print_info(stdout, card); - printf("block size %d capacity %d\n", card->csd.sector_size, card->csd.capacity); - sdmmc_erase_arg_t arg = SDMMC_ERASE_ARG; - uint8_t prev_sec_feature = card->ext_csd.sec_feature; - // overwrite sec_feature - card->ext_csd.sec_feature &= ~(EXT_CSD_SEC_GB_CL_EN); - TEST_ESP_ERR(ESP_ERR_NOT_SUPPORTED, sdmmc_erase_sectors(card, 0, 32, arg)); - // restore sec_feature - card->ext_csd.sec_feature = prev_sec_feature; - if (sdmmc_can_trim(card) != ESP_OK) { - printf("Card/device do not support trim\n"); - return; - } - printf(" sector | count | size(kB) | er_time(ms) \n"); - /* - * bit-0: verify adjacent blocks of given range - * bit-1: verify erase state of blocks in range - */ - uint8_t flags = 0; - - //check for adjacent blocks and erase state of blocks - flags |= (uint8_t)FLAG_ERASE_TEST_ADJACENT | (uint8_t)FLAG_VERIFY_ERASE_STATE; - do_single_erase_test(card, 1, 16, flags, arg); - do_single_erase_test(card, 1, 13, flags, arg); - do_single_erase_test(card, 16, 32, flags, arg); - do_single_erase_test(card, 48, 64, flags, arg); - do_single_erase_test(card, 128, 128, flags, arg); - do_single_erase_test(card, card->csd.capacity - 64, 32, flags, arg); - do_single_erase_test(card, card->csd.capacity - 64, 64, flags, arg); - do_single_erase_test(card, card->csd.capacity - 8, 1, flags, arg); - do_single_erase_test(card, card->csd.capacity/2, 1, flags, arg); - do_single_erase_test(card, card->csd.capacity/2, 4, flags, arg); - do_single_erase_test(card, card->csd.capacity/2, 8, flags, arg); - do_single_erase_test(card, card->csd.capacity/2, 16, flags, arg); - do_single_erase_test(card, card->csd.capacity/2, 32, flags, arg); - do_single_erase_test(card, card->csd.capacity/2, 64, flags, arg); - do_single_erase_test(card, card->csd.capacity/2, 128, flags, arg); -#ifdef SDMMC_FULL_ERASE_TEST - /* - * check for adjacent blocks, do not check erase state of blocks as it is - * time taking process to verify all the blocks. - */ - flags &= ~(uint8_t)FLAG_VERIFY_ERASE_STATE; //comment this line to verify after erase state - // erase complete card - do_single_erase_test(card, 0, card->csd.capacity, flags, arg); -#endif //SDMMC_FULL_ERASE_TEST -} - -TEST_CASE("SDMMC trim test (eMMC slot 0, 4 line)", "[sd][test_env=EMMC][ignore]") -{ - sd_test_board_power_on(); - sd_test_rw_blocks(0, 4, test_mmc_trim_blocks); - sd_test_board_power_off(); -} - -TEST_CASE("SDMMC trim test (eMMC slot 0, 8 line)", "[sd][test_env=EMMC][ignore]") -{ - sd_test_board_power_on(); - sd_test_rw_blocks(0, 8, test_mmc_trim_blocks); - sd_test_board_power_off(); -} - -TEST_CASE("SDMMC discard test (eMMC slot 0, 4 line)", "[sd][test_env=EMMC][ignore]") -{ - sd_test_board_power_on(); - sd_test_rw_blocks(0, 4, test_mmc_discard_blocks); - sd_test_board_power_off(); -} - -TEST_CASE("SDMMC discard test (eMMC slot 0, 8 line)", "[sd][test_env=EMMC][ignore]") -{ - sd_test_board_power_on(); - sd_test_rw_blocks(0, 8, test_mmc_discard_blocks); - sd_test_board_power_off(); -} - -TEST_CASE("SDMMC sanitize test (eMMC slot 0, 4 line)", "[sd][test_env=EMMC][ignore]") -{ - sd_test_board_power_on(); - sd_test_rw_blocks(0, 4, test_mmc_sanitize_blocks); - sd_test_board_power_off(); -} - -TEST_CASE("SDMMC sanitize test (eMMC slot 0, 8 line)", "[sd][test_env=EMMC][ignore]") -{ - sd_test_board_power_on(); - sd_test_rw_blocks(0, 8, test_mmc_sanitize_blocks); - sd_test_board_power_off(); -} -#endif //WITH_EMMC_TEST diff --git a/components/sdmmc/test/test_sdio.c b/components/sdmmc/test/test_sdio.c deleted file mode 100644 index 953aba7c35..0000000000 --- a/components/sdmmc/test/test_sdio.c +++ /dev/null @@ -1,381 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "soc/soc_caps.h" -#if SOC_SDMMC_HOST_SUPPORTED - -#include -#include -#include -#include "esp_log.h" -#include "esp_heap_caps.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "driver/gpio.h" -#include "driver/sdmmc_host.h" -#include "driver/sdmmc_defs.h" -#include "sdmmc_cmd.h" -#include "unity.h" -#include "soc/gpio_reg.h" - -/* Second ESP32 board attached as follows: - * Master Slave - * IO18 EN - * IO19 IO0 - * IO14 SD_CLK - * IO15 SD_CMD - * IO2 SD_D0 - * IO4 SD_D1 - * IO12 SD_D2 - * IO13 SD_D3 - */ - - -/* TODO: add SDIO slave header files, remove these definitions */ - -#define DR_REG_SLC_MASK 0xfffffc00 - -#define SLCCONF1 (DR_REG_SLC_BASE + 0x60) -#define SLC_SLC0_RX_STITCH_EN (BIT(6)) -#define SLC_SLC0_TX_STITCH_EN (BIT(5)) - -#define SLC0TX_LINK (DR_REG_SLC_BASE + 0x40) -#define SLC_SLC0_TXLINK_PARK (BIT(31)) -#define SLC_SLC0_TXLINK_RESTART (BIT(30)) -#define SLC_SLC0_TXLINK_START (BIT(29)) - -#define DR_REG_SLCHOST_MASK 0xfffffc00 -#define SLCHOST_STATE_W0 (DR_REG_SLCHOST_BASE + 0x64) -#define SLCHOST_CONF_W0 (DR_REG_SLCHOST_BASE + 0x6C) -#define SLCHOST_CONF_W5 (DR_REG_SLCHOST_BASE + 0x80) -#define SLCHOST_WIN_CMD (DR_REG_SLCHOST_BASE + 0x84) - -#define SLC_WIN_CMD_READ 0x80 -#define SLC_WIN_CMD_WRITE 0xC0 -#define SLC_WIN_CMD_S 8 - -#define SLC_THRESHOLD_ADDR 0x1f800 - -static const char* TAG = "sdio_test"; - -static esp_err_t slave_slchost_reg_read(sdmmc_card_t* card, uint32_t addr, uint32_t* out_val) -{ - if ((addr & DR_REG_SLCHOST_MASK) != DR_REG_SLCHOST_BASE) { - ESP_LOGW(TAG, "%s: invalid addr 0x%08x", __func__, addr); - return ESP_ERR_INVALID_ARG; - } - return sdmmc_io_read_bytes(card, 1, addr & (~DR_REG_SLCHOST_MASK), out_val, sizeof(*out_val)); -} - -static esp_err_t slave_slchost_reg_write(sdmmc_card_t* card, uint32_t addr, uint32_t val) -{ - if ((addr & DR_REG_SLCHOST_MASK) != DR_REG_SLCHOST_BASE) { - ESP_LOGW(TAG, "%s: invalid addr 0x%08x", __func__, addr); - return ESP_ERR_INVALID_ARG; - } - return sdmmc_io_write_bytes(card, 1, addr & (~DR_REG_SLCHOST_MASK), &val, sizeof(val)); -} - -static esp_err_t slave_slc_reg_read(sdmmc_card_t* card, uint32_t addr, uint32_t* val) -{ - if ((addr & DR_REG_SLC_MASK) != DR_REG_SLC_BASE) { - ESP_LOGW(TAG, "%s: invalid addr 0x%08x", __func__, addr); - return ESP_ERR_INVALID_ARG; - } - uint32_t word = (addr - DR_REG_SLC_BASE) / 4; - if (word > INT8_MAX) { - return ESP_ERR_INVALID_ARG; - } - - uint32_t window_command = word | (SLC_WIN_CMD_READ << SLC_WIN_CMD_S); - esp_err_t err = slave_slchost_reg_write(card, SLCHOST_WIN_CMD, window_command); - if (err != ESP_OK) { - return err; - } - - return slave_slchost_reg_read(card, SLCHOST_STATE_W0, val); -} - -static esp_err_t slave_slc_reg_write(sdmmc_card_t* card, uint32_t addr, uint32_t val) -{ - if ((addr & DR_REG_SLC_MASK) != DR_REG_SLC_BASE) { - ESP_LOGW(TAG, "%s: invalid addr 0x%08x", __func__, addr); - return ESP_ERR_INVALID_ARG; - } - uint32_t word = (addr - DR_REG_SLC_BASE) / 4; - if (word > INT8_MAX) { - return ESP_ERR_INVALID_ARG; - } - - esp_err_t err = slave_slchost_reg_write(card, SLCHOST_CONF_W5, val); - if (err != ESP_OK) { - return err; - } - - uint32_t window_command = word | (SLC_WIN_CMD_WRITE << SLC_WIN_CMD_S); - return slave_slchost_reg_write(card, SLCHOST_WIN_CMD, window_command); -} - -/** Reset and put slave into download mode */ -static void reset_slave(void) -{ - const int pin_en = 18; - const int pin_io0 = 19; - gpio_config_t gpio_cfg = { - .pin_bit_mask = BIT64(pin_en) | BIT64(pin_io0), - .mode = GPIO_MODE_OUTPUT_OD, - }; - TEST_ESP_OK(gpio_config(&gpio_cfg)); - gpio_set_level(pin_en, 0); - gpio_set_level(pin_io0, 0); - vTaskDelay(10 / portTICK_PERIOD_MS); - gpio_set_level(pin_en, 1); - vTaskDelay(10 / portTICK_PERIOD_MS); - gpio_set_level(pin_io0, 1); -} - -static void sdio_slave_common_init(sdmmc_card_t* card) -{ - uint8_t card_cap; - esp_err_t err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_CARD_CAP, &card_cap); - TEST_ESP_OK(err); - printf("CAP: 0x%02x\n", card_cap); - - uint8_t hs; - err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_HIGHSPEED, &hs); - TEST_ESP_OK(err); - printf("HS: 0x%02x\n", hs); - - -#define FUNC1_EN_MASK (BIT(1)) - - uint8_t ioe; - err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_FN_ENABLE, &ioe); - TEST_ESP_OK(err); - printf("IOE: 0x%02x\n", ioe); - - uint8_t ior = 0; - err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_FN_READY, &ior); - TEST_ESP_OK(err); - printf("IOR: 0x%02x\n", ior); - - // enable function 1 - ioe |= FUNC1_EN_MASK; - err = sdmmc_io_write_byte(card, 0, SD_IO_CCCR_FN_ENABLE, ioe, NULL); - TEST_ESP_OK(err); - - err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_FN_ENABLE, &ioe); - TEST_ESP_OK(err); - printf("IOE: 0x%02x\n", ioe); - - // wait for the card to become ready - while ( (ior & FUNC1_EN_MASK) == 0 ) { - err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_FN_READY, &ior); - TEST_ESP_OK(err); - printf("IOR: 0x%02x\n", ior); - } - - // get interrupt status - uint8_t ie; - err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_INT_ENABLE, &ie); - TEST_ESP_OK(err); - printf("IE: 0x%02x\n", ie); - - // enable interrupts for function 1&2 and master enable - ie |= BIT(0) | FUNC1_EN_MASK; - err = sdmmc_io_write_byte(card, 0, SD_IO_CCCR_INT_ENABLE, ie, NULL); - TEST_ESP_OK(err); - - err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_INT_ENABLE, &ie); - TEST_ESP_OK(err); - printf("IE: 0x%02x\n", ie); -} - -/** Common for all SDIO devices, set block size for specific function */ -static void sdio_slave_set_blocksize(sdmmc_card_t* card, int function, uint16_t bs) -{ - const uint8_t* bs_u8 = (const uint8_t*) &bs; - uint16_t bs_read = 0; - uint8_t* bs_read_u8 = (uint8_t*) &bs_read; - uint32_t offset = SD_IO_FBR_START * function; - TEST_ESP_OK( sdmmc_io_write_byte(card, 0, offset + SD_IO_CCCR_BLKSIZEL, bs_u8[0], NULL)); - TEST_ESP_OK( sdmmc_io_write_byte(card, 0, offset + SD_IO_CCCR_BLKSIZEH, bs_u8[1], NULL)); - TEST_ESP_OK( sdmmc_io_read_byte(card, 0, offset + SD_IO_CCCR_BLKSIZEL, &bs_read_u8[0])); - TEST_ESP_OK( sdmmc_io_read_byte(card, 0, offset + SD_IO_CCCR_BLKSIZEH, &bs_read_u8[1])); - TEST_ASSERT_EQUAL_HEX16(bs, bs_read); -} - -/** - * ESP32 ROM code does not set some SDIO slave registers to the defaults - * we need, this function clears/sets some bits. - */ -static void esp32_slave_init_extra(sdmmc_card_t* card) -{ - printf("Initialize some ESP32 SDIO slave registers\n"); - - uint32_t reg_val; - TEST_ESP_OK( slave_slc_reg_read(card, SLCCONF1, ®_val) ); - reg_val &= ~(SLC_SLC0_RX_STITCH_EN | SLC_SLC0_TX_STITCH_EN); - TEST_ESP_OK( slave_slc_reg_write(card, SLCCONF1, reg_val) ); - - TEST_ESP_OK( slave_slc_reg_read(card, SLC0TX_LINK, ®_val) ); - reg_val |= SLC_SLC0_TXLINK_START; - TEST_ESP_OK( slave_slc_reg_write(card, SLC0TX_LINK, reg_val) ); -} - -/** - * ESP32 bootloader implements "SIP" protocol which can be used to exchange - * some commands, events, and data packets between the host and the slave. - * This function sends a SIP command, testing CMD53 block writes along the way. - */ -static void esp32_send_sip_command(sdmmc_card_t* card) -{ - printf("Test block write using CMD53\n"); - const size_t block_size = 512; - uint8_t* data = heap_caps_calloc(1, block_size, MALLOC_CAP_DMA); - struct sip_cmd_bootup { - uint32_t boot_addr; - uint32_t discard_link; - }; - struct sip_cmd_write_reg { - uint32_t addr; - uint32_t val; - }; - struct sip_hdr { - uint8_t fc[2]; - uint16_t len; - uint32_t cmdid; - uint32_t seq; - }; - - struct sip_hdr* hdr = (struct sip_hdr*) data; - size_t len; - -#define SEND_WRITE_REG_CMD - -#ifdef SEND_WRITE_REG_CMD - struct sip_cmd_write_reg *write_reg = (struct sip_cmd_write_reg*) (data + sizeof(*hdr)); - len = sizeof(*hdr) + sizeof(*write_reg); - hdr->cmdid = 3; /* SIP_CMD_WRITE_REG */ - write_reg->addr = GPIO_ENABLE_W1TS_REG; - write_reg->val = BIT(0) | BIT(2) | BIT(4); /* Turn of RGB LEDs on WROVER-KIT */ -#else - struct sip_cmd_bootup *bootup = (struct sip_cmd_bootup*) (data + sizeof(*hdr)); - len = sizeof(*hdr) + sizeof(*bootup); - hdr->cmdid = 5; /* SIP_CMD_BOOTUP */ - bootup->boot_addr = 0x4005a980; /* start_tb_console function in ROM */ - bootup->discard_link = 1; -#endif - hdr->len = len; - - TEST_ESP_OK( sdmmc_io_write_blocks(card, 1, SLC_THRESHOLD_ADDR - len, data, block_size) ); - free(data); -} - -static void test_cmd52_read_write_single_byte(sdmmc_card_t* card) -{ - esp_err_t err; - printf("Write bytes to slave's W0_REG using CMD52\n"); - const size_t scratch_area_reg = SLCHOST_CONF_W0 - DR_REG_SLCHOST_BASE; - - const uint8_t test_byte_1 = 0xa5; - const uint8_t test_byte_2 = 0xb6; - // used to check Read-After-Write - uint8_t test_byte_1_raw; - uint8_t test_byte_2_raw; - uint8_t val = 0; - err = sdmmc_io_write_byte(card, 1, scratch_area_reg, test_byte_1, &test_byte_1_raw); - TEST_ESP_OK(err); - TEST_ASSERT_EQUAL_UINT8(test_byte_1, test_byte_1_raw); - err = sdmmc_io_write_byte(card, 1, scratch_area_reg + 1, test_byte_2, &test_byte_2_raw); - TEST_ESP_OK(err); - TEST_ASSERT_EQUAL_UINT8(test_byte_2, test_byte_2_raw); - - printf("Read back bytes using CMD52\n"); - TEST_ESP_OK(sdmmc_io_read_byte(card, 1, scratch_area_reg, &val)); - TEST_ASSERT_EQUAL_UINT8(test_byte_1, val); - - TEST_ESP_OK(sdmmc_io_read_byte(card, 1, scratch_area_reg + 1, &val)); - TEST_ASSERT_EQUAL_UINT8(test_byte_2, val); -} - -static void test_cmd53_read_write_multiple_bytes(sdmmc_card_t* card, size_t n_bytes) -{ - printf("Write multiple bytes using CMD53\n"); - const size_t scratch_area_reg = SLCHOST_CONF_W0 - DR_REG_SLCHOST_BASE; - - uint8_t* src = heap_caps_malloc(512, MALLOC_CAP_DMA); - uint32_t* src_32 = (uint32_t*) src; - - for (size_t i = 0; i < (n_bytes + 3) / 4; ++i) { - src_32[i] = rand(); - } - - TEST_ESP_OK(sdmmc_io_write_bytes(card, 1, scratch_area_reg, src, n_bytes)); - ESP_LOG_BUFFER_HEX(TAG, src, n_bytes); - - printf("Read back using CMD52\n"); - uint8_t* dst = heap_caps_malloc(512, MALLOC_CAP_DMA); - for (size_t i = 0; i < n_bytes; ++i) { - TEST_ESP_OK(sdmmc_io_read_byte(card, 1, scratch_area_reg + i, &dst[i])); - } - ESP_LOG_BUFFER_HEX(TAG, dst, n_bytes); - TEST_ASSERT_EQUAL_UINT8_ARRAY(src, dst, n_bytes); - - printf("Read back using CMD53\n"); - TEST_ESP_OK(sdmmc_io_read_bytes(card, 1, scratch_area_reg, dst, n_bytes)); - ESP_LOG_BUFFER_HEX(TAG, dst, n_bytes); - TEST_ASSERT_EQUAL_UINT8_ARRAY(src, dst, n_bytes); - - free(src); - free(dst); -} - - -TEST_CASE("can probe and talk to ESP32 SDIO slave", "[sdio][ignore]") -{ - reset_slave(); - - /* Probe */ - sdmmc_host_t config = SDMMC_HOST_DEFAULT(); - config.flags = SDMMC_HOST_FLAG_1BIT; - config.max_freq_khz = SDMMC_FREQ_PROBING; - - sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); - (sdmmc_host_init()); - (sdmmc_host_init_slot(SDMMC_HOST_SLOT_1, &slot_config)); - sdmmc_card_t* card = malloc(sizeof(sdmmc_card_t)); - TEST_ASSERT_NOT_NULL(card); - TEST_ESP_OK(sdmmc_card_init(&config, card)); - sdmmc_card_print_info(stdout, card); - - /* Set up standard SDIO registers */ - sdio_slave_common_init(card); - - srand(0); - for (int repeat = 0; repeat < 4; ++repeat) { - test_cmd52_read_write_single_byte(card); - test_cmd53_read_write_multiple_bytes(card, 1); - test_cmd53_read_write_multiple_bytes(card, 2); - test_cmd53_read_write_multiple_bytes(card, 3); - test_cmd53_read_write_multiple_bytes(card, 4); - test_cmd53_read_write_multiple_bytes(card, 5); - test_cmd53_read_write_multiple_bytes(card, 23); - test_cmd53_read_write_multiple_bytes(card, 24); - } - - sdio_slave_set_blocksize(card, 0, 512); - sdio_slave_set_blocksize(card, 1, 512); - - esp32_slave_init_extra(card); - - esp32_send_sip_command(card); - - TEST_ESP_OK(sdmmc_host_deinit()); - free(card); -} - -#endif //SOC_SDMMC_HOST_SUPPORTED diff --git a/tools/test_apps/storage/sdmmc_console/partitions.csv b/tools/test_apps/storage/sdmmc_console/partitions.csv index 1c79321a10..d4fe8bd49f 100644 --- a/tools/test_apps/storage/sdmmc_console/partitions.csv +++ b/tools/test_apps/storage/sdmmc_console/partitions.csv @@ -3,4 +3,4 @@ nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 1M, -storage, data, fat, , 1M, +storage, data, fat, , 528K, diff --git a/tools/test_apps/storage/sdmmc_console/sdkconfig.defaults b/tools/test_apps/storage/sdmmc_console/sdkconfig.defaults index 051b5e29ec..b5480d96ba 100644 --- a/tools/test_apps/storage/sdmmc_console/sdkconfig.defaults +++ b/tools/test_apps/storage/sdmmc_console/sdkconfig.defaults @@ -1,5 +1,5 @@ CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y -CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y CONFIG_HEAP_POISONING_COMPREHENSIVE=y CONFIG_COMPILER_STACK_CHECK_MODE_STRONG=y diff --git a/tools/test_apps/storage/sdmmc_console/sdkconfig.defaults.esp32h2 b/tools/test_apps/storage/sdmmc_console/sdkconfig.defaults.esp32h2 new file mode 100644 index 0000000000..bd38a2886d --- /dev/null +++ b/tools/test_apps/storage/sdmmc_console/sdkconfig.defaults.esp32h2 @@ -0,0 +1,5 @@ +CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y +CONFIG_SDMMC_BOARD_CUSTOM_MISO=0 +CONFIG_SDMMC_BOARD_CUSTOM_MOSI=5 +CONFIG_SDMMC_BOARD_CUSTOM_SCK=4 +CONFIG_SDMMC_BOARD_CUSTOM_CS=1