refactor(sdmmc): added component pytest cases and enabled them on CI

pull/12702/head
Armando 2023-11-27 19:55:53 +08:00
rodzic 7ab678873c
commit 9b0d75f2df
26 zmienionych plików z 1739 dodań i 10 usunięć

Wyświetl plik

@ -715,6 +715,24 @@ pytest_components_esp32_adc:
artifacts: false
tags: [ esp32, adc ]
pytest_components_esp32_sdmmc:
extends:
- .pytest_components_dir_template
- .rules:test:component_ut-esp32
needs:
- job: build_pytest_components_esp32
artifacts: false
tags: [ esp32, sdcard ]
pytest_components_esp32s3_sdmmc:
extends:
- .pytest_components_dir_template
- .rules:test:component_ut-esp32s3
needs:
- job: build_pytest_components_esp32s3
artifacts: false
tags: [ esp32s3, sdcard ]
pytest_components_esp32_sdio:
extends:
- .pytest_components_dir_template
@ -1171,15 +1189,6 @@ pytest_components_esp32c3_flash_multi:
artifacts: false
tags: [ esp32c3, flash_multi ]
pytest_components_esp32_sdmmc:
extends:
- .pytest_components_dir_template
- .rules:test:component_ut-esp32
needs:
- job: build_pytest_components_esp32
artifacts: false
tags: [ esp32, sdcard_sdmode ]
pytest_components_esp32_sdspi:
extends:
- .pytest_components_dir_template

Wyświetl plik

@ -0,0 +1,6 @@
components/esp_driver_sdmmc/test_apps/sdmmc:
disable:
- if: SOC_SDMMC_HOST_SUPPORTED != 1
depends_components:
- sdmmc
- esp_driver_sdmmc

Wyświetl plik

@ -0,0 +1,9 @@
set(srcs "sdmmc_test_cd_wp_common.c" "sdmmc_test_rw_common.c")
set(public_include "include")
idf_component_register(
SRCS ${srcs}
INCLUDE_DIRS ${public_include}
PRIV_REQUIRES sdmmc unity test_utils
)

Wyświetl plik

@ -0,0 +1,37 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "sd_protocol_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Test card detect functionality
*
* Common part of CD test, works with both SDMMC and SDSPI hosts.
* Called from sdmmc_test_cd_wp_sd.c and sdmmc_test_cd_wp_spi.c.
*
* @param gpio_cd_num GPIO number used for the test. Must not be connected to anything on the board.
* @param config Pointer to the host configuration structure.
*/
void sdmmc_test_cd_input(int gpio_cd_num, const sdmmc_host_t* config);
/**
* @brief Test write protect functionality
*
* Common part of WP test, works with both SDMMC and SDSPI hosts.
* Called from sdmmc_test_cd_wp_sd.c and sdmmc_test_cd_wp_spi.c.
*
* @param gpio_wp_num GPIO number used for the test. Must not be connected to anything on the board.
* @param config Pointer to the host configuration structure.
*/
void sdmmc_test_wp_input(int gpio_wp_num, const sdmmc_host_t* config);
#ifdef __cplusplus
};
#endif

Wyświetl plik

@ -0,0 +1,55 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "sd_protocol_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Test read/write performance of the card
*
* This function writes a buffer to the card, then reads it back.
* The time taken for each operation is measured, and the throughput is calculated.
* The process is repeated for different buffer sizes and card offsets.
* In this test, data is always written and read at the beginning of 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.
* @param perf_log If not null, additional "performance log" lines are written to this file.
* These lines are in a format recognized by pytest-embedded.
*/
void sdmmc_test_rw_performance(sdmmc_card_t *card, FILE *perf_log);
/**
* @brief Test read/write with unaligned buffer
*
* This function verifies that the driver deals with unaligned source/destination buffers correctly.
*
* 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_rw_unaligned_buffer(sdmmc_card_t* card);
/**
* @brief Test read/write with offset
*
* Similar to sdmmc_test_rw_performance, but this time data is written at different
* offsets on 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_rw_with_offset(sdmmc_card_t* card);
#ifdef __cplusplus
};
#endif

Wyświetl plik

@ -0,0 +1,75 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <unistd.h>
#include "unity.h"
#include "esp_rom_gpio.h"
#include "hal/gpio_hal.h"
#include "sdmmc_cmd.h"
#include "sdmmc_test_cd_wp_common.h"
void sdmmc_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).
gpio_hal_context_t gpio_hal = {
.dev = GPIO_HAL_GET_HW(GPIO_PORT_0)
};
esp_rom_gpio_connect_out_signal(gpio_cd_num, SIG_GPIO_OUT_IDX, false, false);
gpio_hal_output_enable(&gpio_hal, gpio_cd_num);
// Check that card initialization fails if CD is high
gpio_hal_set_level(&gpio_hal, gpio_cd_num, 1);
usleep(1000);
TEST_ESP_ERR(ESP_ERR_NOT_FOUND, sdmmc_card_init(config, card));
// Check that card initialization succeeds if CD is low
gpio_hal_set_level(&gpio_hal, gpio_cd_num, 0);
usleep(1000);
TEST_ESP_OK(sdmmc_card_init(config, card));
free(card);
}
void sdmmc_test_wp_input(int gpio_wp_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 WP as input.
// Enable output as well (not using the driver, to avoid touching input
// enable bits).
gpio_hal_context_t gpio_hal = {
.dev = GPIO_HAL_GET_HW(GPIO_PORT_0)
};
esp_rom_gpio_connect_out_signal(gpio_wp_num, SIG_GPIO_OUT_IDX, false, false);
gpio_hal_output_enable(&gpio_hal, gpio_wp_num);
// Check that the card can be initialized with WP low
gpio_hal_set_level(&gpio_hal, gpio_wp_num, 0);
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
gpio_hal_set_level(&gpio_hal, gpio_wp_num, 1);
usleep(1000);
TEST_ESP_OK(sdmmc_write_sectors(card, &data, 0, 1));
// Check that write fails if WP is low
gpio_hal_set_level(&gpio_hal, gpio_wp_num, 0);
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);
}

Wyświetl plik

@ -0,0 +1,158 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include "test_utils.h"
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#include "unity.h"
#include "sd_protocol_defs.h"
#include "sdmmc_cmd.h"
#include "sdmmc_test_rw_common.h"
static void do_single_rw_perf_test(sdmmc_card_t* card, size_t start_block,
size_t block_count, size_t alignment, FILE* performance_log);
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_rw_perf_test(sdmmc_card_t* card, size_t start_block,
size_t block_count, size_t alignment, FILE* 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) {
FILE* old_stdout = stdout;
stdout = 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);
stdout = old_stdout;
}
}
void sdmmc_test_rw_unaligned_buffer(sdmmc_card_t* 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);
}
void sdmmc_test_rw_performance(sdmmc_card_t *card, FILE *perf_log)
{
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;
/* aligned */
do_single_rw_perf_test(card, offset, 1, 4, perf_log);
do_single_rw_perf_test(card, offset, 4, 4, perf_log);
do_single_rw_perf_test(card, offset, 8, 4, perf_log);
do_single_rw_perf_test(card, offset, 16, 4, perf_log);
do_single_rw_perf_test(card, offset, 32, 4, perf_log);
do_single_rw_perf_test(card, offset, 64, 4, perf_log);
do_single_rw_perf_test(card, offset, 128, 4, perf_log);
/* unaligned */
do_single_rw_perf_test(card, offset, 1, 1, perf_log);
do_single_rw_perf_test(card, offset, 8, 1, perf_log);
do_single_rw_perf_test(card, offset, 128, 1, perf_log);
}
void sdmmc_test_rw_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");
/* aligned */
do_single_rw_perf_test(card, 1, 16, 4, NULL);
do_single_rw_perf_test(card, 16, 32, 4, NULL);
do_single_rw_perf_test(card, 48, 64, 4, NULL);
do_single_rw_perf_test(card, 128, 128, 4, NULL);
do_single_rw_perf_test(card, card->csd.capacity - 64, 32, 4, NULL);
do_single_rw_perf_test(card, card->csd.capacity - 64, 64, 4, NULL);
do_single_rw_perf_test(card, card->csd.capacity - 8, 1, 4, NULL);
do_single_rw_perf_test(card, card->csd.capacity / 2, 1, 4, NULL);
do_single_rw_perf_test(card, card->csd.capacity / 2, 4, 4, NULL);
do_single_rw_perf_test(card, card->csd.capacity / 2, 8, 4, NULL);
do_single_rw_perf_test(card, card->csd.capacity / 2, 16, 4, NULL);
do_single_rw_perf_test(card, card->csd.capacity / 2, 32, 4, NULL);
do_single_rw_perf_test(card, card->csd.capacity / 2, 64, 4, NULL);
do_single_rw_perf_test(card, card->csd.capacity / 2, 128, 4, NULL);
/* unaligned */
do_single_rw_perf_test(card, card->csd.capacity / 2, 1, 1, NULL);
do_single_rw_perf_test(card, card->csd.capacity / 2, 8, 1, NULL);
do_single_rw_perf_test(card, card->csd.capacity / 2, 128, 1, NULL);
}

Wyświetl plik

@ -0,0 +1,3 @@
idf_component_register(SRCS sdmmc_test_board.c sdmmc_test_board_defs.c
INCLUDE_DIRS include
REQUIRES esp_driver_sdmmc esp_driver_sdspi esp_driver_gpio)

Wyświetl plik

@ -0,0 +1,138 @@
menu "SDMMC Test Board Configuration"
choice SDMMC_BOARD
prompt "Board type"
help
Select development board used for running the test.
config SDMMC_BOARD_ESP32_WROVER_KIT
bool "ESP32 WROVER-KIT"
depends on IDF_TARGET_ESP32
config SDMMC_BOARD_ESP32_EMMC_TEST
bool "ESP32 eMMC Test Board v1"
depends on IDF_TARGET_ESP32
config SDMMC_BOARD_ESP32S2_S3_USB_OTG
bool "ESP32-S2/S3 USB-OTG"
depends on IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
config SDMMC_BOARD_ESP32S3_EMMC_TEST
bool "ESP32-S3 eMMC Test Board v1"
depends on IDF_TARGET_ESP32S3
config SDMMC_BOARD_ESP32S3_EYE
bool "ESP32-S3 EYE v2.1"
depends on IDF_TARGET_ESP32S3
config SDMMC_BOARD_ESP32C3_BREAKOUT
bool "ESP32-C3 breakout board"
depends on IDF_TARGET_ESP32C3
config SDMMC_BOARD_CUSTOM_SD
depends on SOC_SDMMC_HOST_SUPPORTED
bool "Custom SD (choose pins)"
config SDMMC_BOARD_CUSTOM_SPI
bool "Custom SPI (choose pins)"
menu "Custom pins"
if SDMMC_BOARD_CUSTOM_SD
# just a dummy option to prevent the Kconfig checker from complaining
# about the option name prefix
config SDMMC_BOARD_CUSTOM_DUMMY
int
choice SDMMC_BOARD_CUSTOM_BUS_WIDTH
prompt "Bus width"
config SDMMC_BOARD_CUSTOM_4BIT
bool "4-bit"
config SDMMC_BOARD_CUSTOM_1BIT
bool "1-bit"
endchoice
config SDMMC_BOARD_CUSTOM_BUS_WIDTH
int
default 4 if SDMMC_BOARD_CUSTOM_4BIT
default 1
if SOC_SDMMC_USE_GPIO_MATRIX
config SDMMC_BOARD_CUSTOM_CMD
int "CMD GPIO"
default 1
config SDMMC_BOARD_CUSTOM_CLK
int "CLK GPIO"
default 2
config SDMMC_BOARD_CUSTOM_D0
int "D0 GPIO"
default 3
if SDMMC_BOARD_CUSTOM_4BIT
config SDMMC_BOARD_CUSTOM_D1
int
prompt "D1 GPIO" if SDMMC_BOARD_CUSTOM_4BIT
default 4 if SDMMC_BOARD_CUSTOM_4BIT
default -1
config SDMMC_BOARD_CUSTOM_D2
int
prompt "D2 GPIO" if SDMMC_BOARD_CUSTOM_4BIT
default 5 if SDMMC_BOARD_CUSTOM_4BIT
default -1
config SDMMC_BOARD_CUSTOM_D3
int
prompt "D3 GPIO" if SDMMC_BOARD_CUSTOM_4BIT
default 6 if SDMMC_BOARD_CUSTOM_4BIT
default -1
endif # SDMMC_BOARD_CUSTOM_4BIT
endif # SOC_SDMMC_USE_GPIO_MATRIX
endif # SDMMC_BOARD_CUSTOM_SD
if SDMMC_BOARD_CUSTOM_SPI
config SDMMC_BOARD_CUSTOM_MISO
int "MISO GPIO"
default 1
config SDMMC_BOARD_CUSTOM_MOSI
int "MOSI GPIO"
default 2
config SDMMC_BOARD_CUSTOM_SCK
int "SCK GPIO"
default 3
config SDMMC_BOARD_CUSTOM_CS
int "CS GPIO"
default 4
endif # SDMMC_BOARD_CUSTOM_SPI
config SDMMC_BOARD_CUSTOM_CD
int "Card Detect GPIO"
default -1
config SDMMC_BOARD_CUSTOM_WP
int "Write Protect GPIO"
default -1
config SDMMC_BOARD_CUSTOM_UNUSED
int "GPIO not routed on the board"
default -1
endmenu
endchoice # SDMMC_BOARD
endmenu

Wyświetl plik

@ -0,0 +1,8 @@
# SDMMC Test Boards
This component is a test utility component for test board info:
- SDMMC test boards (e.g. ESP32_WROVER_KIT, ESP32S3_USB_OTG, etc.)
- eMMC test boards
- SDMMC with SD breakout adapter board
- SDSPI with SD breakout adapter board
- ...

Wyświetl plik

@ -0,0 +1,129 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdbool.h>
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#include "driver/sdspi_host.h"
#if SOC_SDMMC_HOST_SUPPORTED
#include "driver/sdmmc_host.h"
#endif
#include "driver/gpio.h"
#include "driver/spi_common.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file sdmmc_test.h
* This file contains APIs to get the board specific information (pin mappings) for SDMMC tests.
*/
/**
* @brief Information about a slot on the test board
*/
typedef struct {
bool slot_exists; /*< Whether the slot exists on the dev board */
bool is_emmc; /*< True if this slot is connected to eMMC */
int bus_width; /*< SD interface width (1, 4 or 8) */
int max_freq_khz; /*< Max frequency (kHz) of SD interface, supported by the board */
gpio_num_t clk; /*< CLK pin number */
gpio_num_t cmd_mosi; /*< CMD pin number (SD mode) or MOSI (SPI mode) */
gpio_num_t d0_miso; /*< D0 pin number (SD mode) or MISO (SPI mode) */
gpio_num_t d1; /*< D1 pin number */
gpio_num_t d2; /*< D2 pin number */
gpio_num_t d3_cs; /*< D3 pin number (SD mode) or CS (SPI mode) */
gpio_num_t d4; /*< D4 pin number */
gpio_num_t d5; /*< D5 pin number */
gpio_num_t d6; /*< D6 pin number */
gpio_num_t d7; /*< D7 pin number */
gpio_num_t cd; /*< Card detect pin number */
gpio_num_t wp; /*< Write protect pin number */
gpio_num_t unused_pin; /*< Pin not routed on the board, for CD/WP loopback tests */
} sdmmc_test_board_slot_info_t;
#define SDMMC_TEST_BOARD_MAX_SLOTS 2 /*< Number of slots we need to support on one test board */
typedef struct {
const char* name; /*< name of the board */
sdmmc_test_board_slot_info_t slot[SDMMC_TEST_BOARD_MAX_SLOTS]; /*< array of information about slots */
void (*card_power_set)(bool); /*< function to turn card power on or off */
} sdmmc_test_board_info_t;
/**
* @brief Get information about the test board
* @return Pointer to the board information structure
*/
const sdmmc_test_board_info_t* sdmmc_test_board_get_info(void);
/**
* @brief Get information about a slot on the test board
* @param slot_index Index of the slot (0 to SDMMC_TEST_BOARD_MAX_SLOTS-1)
* @return Pointer to the slot information structure
*/
const sdmmc_test_board_slot_info_t* sdmmc_test_board_get_slot_info(int slot_index);
#if SOC_SDMMC_HOST_SUPPORTED
/**
* @brief Fill SDMMC host and slot configuration structures with information about a slot on the test board
* @note Before calling this function, initialize the host/slot configuration structures using default initializer macros.
* @param slot_index Index of the slot (0 to SDMMC_TEST_BOARD_MAX_SLOTS-1)
* @param[out] out_host_config Output, pointer to the host configuration structure to be filled.
* @param[out] out_slot_config Output, pointer to the slot configuration structure to be filled.
*/
void sdmmc_test_board_get_config_sdmmc(int slot_index, sdmmc_host_t *out_host_config, sdmmc_slot_config_t *out_slot_config);
#endif
/**
* @brief Fill SDSPI host, bus and device configuration structures with information about a slot on the test board
* @note Before calling this function, initialize the these configuration structures using default initializer macros.
* @param slot_index Index of the slot (0 to SDMMC_TEST_BOARD_MAX_SLOTS-1)
* @param out_host_config Output, pointer to the host configuration structure to be filled.
* @param out_spi_bus_config Output, pointer to the SPI bus configuration structure to be filled.
* @param out_dev_config Output, pointer to the device configuration structure to be filled.
*/
void sdmmc_test_board_get_config_sdspi(int slot_index, sdmmc_host_t *out_host_config,
spi_bus_config_t *out_spi_bus_config, sdspi_device_config_t *out_dev_config);
/**
* @brief Set card power on or off
* For boards with card power control circuit, this function allows powering the card up or down.
* @param enable True to turn power on, false to turn power off
*/
void sdmmc_test_board_card_power_set(bool enable);
/**
* @brief Check if a slot exists on the test board
* "Exists" here means that something (card slot or eMMC) is connected to that slot.
* @param slot_index Index of the slot (0 to SDMMC_TEST_BOARD_MAX_SLOTS-1)
* @return True if the slot exists on the board
*/
bool sdmmc_test_board_has_slot(int slot_index);
/**
* @brief Check if a slot is connected to eMMC
*
* Note that this function simply returns what the board definitions in sdmmc_test_board_defs.c say.
* It does not check if the card is actually eMMC.
* The main purpose of this function is to prevent SPI-related tests
* from being run on slots which are known to be connected to eMMC.
*
* @param slot_index Index of the slot (0 to SDMMC_TEST_BOARD_MAX_SLOTS-1)
* @return True if the slot is connected to eMMC
*/
bool sdmmc_test_board_slot_is_emmc(int slot_index);
/**
* @brief Print information about the test board (pin mapping)
*/
void sdmmc_test_board_print_info(void);
#ifdef __cplusplus
}
#endif

Wyświetl plik

@ -0,0 +1,115 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "sdmmc_test_board.h"
#include "sdkconfig.h"
#include "soc/soc_caps.h"
const sdmmc_test_board_slot_info_t* sdmmc_test_board_get_slot_info(int slot_index)
{
assert(slot_index >= 0 && slot_index < SDMMC_TEST_BOARD_MAX_SLOTS);
return &sdmmc_test_board_get_info()->slot[slot_index];
}
#if SOC_SDMMC_HOST_SUPPORTED
void sdmmc_test_board_get_config_sdmmc(int slot_index, sdmmc_host_t *out_host_config, sdmmc_slot_config_t *out_slot_config)
{
const sdmmc_test_board_slot_info_t* slot = sdmmc_test_board_get_slot_info(slot_index);
assert(slot->slot_exists);
out_host_config->slot = slot_index;
if (slot->bus_width < 8) {
out_host_config->flags &= ~SDMMC_HOST_FLAG_8BIT;
}
if (slot->bus_width < 4) {
out_host_config->flags &= ~SDMMC_HOST_FLAG_4BIT;
}
if (slot->max_freq_khz > 0) {
out_host_config->max_freq_khz = slot->max_freq_khz;
}
#if SOC_SDMMC_USE_GPIO_MATRIX
out_slot_config->clk = slot->clk;
out_slot_config->cmd = slot->cmd_mosi;
out_slot_config->d0 = slot->d0_miso;
out_slot_config->d1 = slot->d1;
out_slot_config->d2 = slot->d2;
out_slot_config->d3 = slot->d3_cs;
out_slot_config->d4 = slot->d4;
out_slot_config->d5 = slot->d5;
out_slot_config->d6 = slot->d6;
out_slot_config->d7 = slot->d7;
#endif // SOC_SDMMC_USE_GPIO_MATRIX
out_slot_config->wp = slot->wp;
out_slot_config->cd = slot->cd;
out_slot_config->width = slot->bus_width;
}
#endif // SOC_SDMMC_HOST_SUPPORTED
void sdmmc_test_board_get_config_sdspi(int slot_index, sdmmc_host_t *out_host_config, spi_bus_config_t *out_spi_bus_config, sdspi_device_config_t *out_dev_config)
{
const sdmmc_test_board_slot_info_t* slot = sdmmc_test_board_get_slot_info(slot_index);
assert(slot->slot_exists);
if (slot->max_freq_khz > 0) {
out_host_config->max_freq_khz = slot->max_freq_khz;
}
out_spi_bus_config->mosi_io_num = slot->cmd_mosi;
out_spi_bus_config->miso_io_num = slot->d0_miso;
out_spi_bus_config->sclk_io_num = slot->clk;
out_dev_config->gpio_cs = slot->d3_cs;
out_dev_config->gpio_cd = slot->cd;
out_dev_config->gpio_wp = slot->wp;
}
void sdmmc_test_board_card_power_set(bool enable)
{
const sdmmc_test_board_info_t* board = sdmmc_test_board_get_info();
if (board->card_power_set != NULL) {
board->card_power_set(enable);
}
}
bool sdmmc_test_board_has_slot(int slot_index)
{
return sdmmc_test_board_get_slot_info(slot_index)->slot_exists;
}
bool sdmmc_test_board_slot_is_emmc(int slot_index)
{
return sdmmc_test_board_get_slot_info(slot_index)->is_emmc;
}
void sdmmc_test_board_print_info()
{
const sdmmc_test_board_info_t *board = sdmmc_test_board_get_info();
printf("\nTest app built for %s\n", board->name);
for (int slot_index = 0; slot_index < SDMMC_TEST_BOARD_MAX_SLOTS; ++slot_index) {
const sdmmc_test_board_slot_info_t *slot = sdmmc_test_board_get_slot_info(slot_index);
if (!slot->slot_exists) {
printf("- Slot %d: not present\n", slot_index);
continue;
}
printf("- Slot %d: %d-bit", slot_index, slot->bus_width);
if (slot->max_freq_khz > 0) {
printf(", freq limit: %d kHz", slot->max_freq_khz);
}
if (slot->is_emmc > 0) {
printf(", eMMC");
}
printf("\n");
printf(" CMD/MOSI: %2d\n CLK: %2d\n D0/MISO: %2d\n", slot->cmd_mosi, slot->clk, slot->d0_miso);
if (slot->bus_width > 1 || slot->d3_cs) {
printf(" D1: %2d\n D2: %2d\n D3/CS: %2d\n", slot->d1, slot->d2, slot->d3_cs);
}
if (slot->bus_width > 4) {
printf(" D4: %2d\n D5: %2d\n D6: %2d\n D7: %2d\n", slot->d4, slot->d5, slot->d6, slot->d7);
}
}
}

Wyświetl plik

@ -0,0 +1,391 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <unistd.h>
#include "sdmmc_test_board.h"
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#include "driver/gpio.h"
#if SOC_SDMMC_HOST_SUPPORTED
#include "soc/sdmmc_pins.h"
#endif
#if CONFIG_SDMMC_BOARD_ESP32_WROVER_KIT
static const sdmmc_test_board_info_t s_board_info = {
.name = "ESP32-WROVER-KIT",
.slot = {
{
.slot_exists = false
},
{
.slot_exists = true,
.bus_width = 4,
.clk = SDMMC_SLOT1_IOMUX_PIN_NUM_CLK,
.cmd_mosi = SDMMC_SLOT1_IOMUX_PIN_NUM_CMD,
.d0_miso = SDMMC_SLOT1_IOMUX_PIN_NUM_D0,
.d1 = SDMMC_SLOT1_IOMUX_PIN_NUM_D1,
.d2 = SDMMC_SLOT1_IOMUX_PIN_NUM_D2,
.d3_cs = SDMMC_SLOT1_IOMUX_PIN_NUM_D3,
.d4 = GPIO_NUM_NC,
.d5 = GPIO_NUM_NC,
.d6 = GPIO_NUM_NC,
.d7 = GPIO_NUM_NC,
.cd = GPIO_NUM_NC,
.wp = GPIO_NUM_NC,
.unused_pin = 18,
}
},
};
#elif CONFIG_SDMMC_BOARD_ESP32_EMMC_TEST
#define SD_TEST_BOARD_VSEL_GPIO 26
#define SD_TEST_BOARD_VSEL_3V3 1
#define SD_TEST_BOARD_VSEL_1V8 0
#define SD_TEST_BOARD_EN_GPIO 27
#define SD_TEST_BOARD_EN_LEVEL 1
#define SD_TEST_BOARD_PWR_RST_DELAY_MS 5
#define SD_TEST_BOARD_PWR_ON_DELAY_MS 50
static void card_power_set_esp32_emmc(bool en)
{
if (en) {
/* set voltage */
gpio_set_direction(SD_TEST_BOARD_VSEL_GPIO, GPIO_MODE_OUTPUT);
gpio_set_level(SD_TEST_BOARD_VSEL_GPIO, SD_TEST_BOARD_VSEL_3V3);
/* power off to make sure card is reset */
gpio_set_direction(SD_TEST_BOARD_EN_GPIO, GPIO_MODE_OUTPUT);
gpio_set_level(SD_TEST_BOARD_EN_GPIO, !SD_TEST_BOARD_EN_LEVEL);
usleep(SD_TEST_BOARD_PWR_RST_DELAY_MS * 1000);
/* power on */
gpio_set_level(SD_TEST_BOARD_EN_GPIO, SD_TEST_BOARD_EN_LEVEL);
usleep(SD_TEST_BOARD_PWR_ON_DELAY_MS * 1000);
} else {
gpio_set_level(SD_TEST_BOARD_EN_GPIO, !SD_TEST_BOARD_EN_LEVEL);
gpio_set_level(SD_TEST_BOARD_VSEL_GPIO, 0);
gpio_set_direction(SD_TEST_BOARD_VSEL_GPIO, GPIO_MODE_INPUT);
gpio_set_direction(SD_TEST_BOARD_EN_GPIO, GPIO_MODE_INPUT);
}
}
static const sdmmc_test_board_info_t s_board_info = {
.name = "ESP32 eMMC test board v1",
.slot = {
{
.slot_exists = true,
.is_emmc = true,
.bus_width = 8,
.clk = SDMMC_SLOT0_IOMUX_PIN_NUM_CLK,
.cmd_mosi = SDMMC_SLOT0_IOMUX_PIN_NUM_CMD,
.d0_miso = SDMMC_SLOT0_IOMUX_PIN_NUM_D0,
.d1 = SDMMC_SLOT0_IOMUX_PIN_NUM_D1,
.d2 = SDMMC_SLOT0_IOMUX_PIN_NUM_D2,
.d3_cs = SDMMC_SLOT0_IOMUX_PIN_NUM_D3,
.d4 = SDMMC_SLOT0_IOMUX_PIN_NUM_D4,
.d5 = SDMMC_SLOT0_IOMUX_PIN_NUM_D5,
.d6 = SDMMC_SLOT0_IOMUX_PIN_NUM_D6,
.d7 = SDMMC_SLOT0_IOMUX_PIN_NUM_D7,
.cd = GPIO_NUM_NC,
.wp = GPIO_NUM_NC,
.unused_pin = 18,
},
{
.slot_exists = true,
.bus_width = 4,
.clk = SDMMC_SLOT1_IOMUX_PIN_NUM_CLK,
.cmd_mosi = SDMMC_SLOT1_IOMUX_PIN_NUM_CMD,
.d0_miso = SDMMC_SLOT1_IOMUX_PIN_NUM_D0,
.d1 = SDMMC_SLOT1_IOMUX_PIN_NUM_D1,
.d2 = SDMMC_SLOT1_IOMUX_PIN_NUM_D2,
.d3_cs = SDMMC_SLOT1_IOMUX_PIN_NUM_D3,
.d4 = GPIO_NUM_NC,
.d5 = GPIO_NUM_NC,
.d6 = GPIO_NUM_NC,
.d7 = GPIO_NUM_NC,
.cd = GPIO_NUM_NC,
.wp = GPIO_NUM_NC,
.unused_pin = 18,
}
},
.card_power_set = card_power_set_esp32_emmc
};
#elif CONFIG_SDMMC_BOARD_ESP32S2_S3_USB_OTG
static const sdmmc_test_board_info_t s_board_info = {
.name = "ESP32-S2/ESP32-S3 USB_OTG",
.slot = {
{
.slot_exists = false
},
{
.slot_exists = true,
.bus_width = 4,
.clk = 36,
.cmd_mosi = 35,
.d0_miso = 37,
.d1 = 38,
.d2 = 33,
.d3_cs = 34,
.d4 = GPIO_NUM_NC,
.d5 = GPIO_NUM_NC,
.d6 = GPIO_NUM_NC,
.d7 = GPIO_NUM_NC,
.cd = GPIO_NUM_NC,
.wp = GPIO_NUM_NC,
.unused_pin = 2,
}
},
};
#elif CONFIG_SDMMC_BOARD_ESP32S3_EMMC_TEST
#define SD_TEST_BOARD_EN_GPIO 47
#define SD_TEST_BOARD_EN_LEVEL 0
// Pin pulled down to discharge VDD_SDIO capacitors. CMD pin used here.
#define SD_TEST_BOARD_DISCHARGE_GPIO 4
#define SD_TEST_BOARD_PWR_RST_DELAY_MS 100
#define SD_TEST_BOARD_PWR_ON_DELAY_MS 100
static void card_power_set_esp32s3_emmc(bool en)
{
if (en) {
/* power off to make sure the card is reset */
gpio_reset_pin(SD_TEST_BOARD_EN_GPIO);
gpio_set_direction(SD_TEST_BOARD_EN_GPIO, GPIO_MODE_OUTPUT);
gpio_set_level(SD_TEST_BOARD_EN_GPIO, !SD_TEST_BOARD_EN_LEVEL);
/* discharge capacitors on VDD_SDIO */
gpio_reset_pin(SD_TEST_BOARD_DISCHARGE_GPIO);
gpio_set_direction(SD_TEST_BOARD_DISCHARGE_GPIO, GPIO_MODE_OUTPUT);
gpio_set_level(SD_TEST_BOARD_DISCHARGE_GPIO, 0);
usleep(SD_TEST_BOARD_PWR_RST_DELAY_MS * 1000);
/* power on */
gpio_reset_pin(SD_TEST_BOARD_DISCHARGE_GPIO);
gpio_set_level(SD_TEST_BOARD_EN_GPIO, SD_TEST_BOARD_EN_LEVEL);
usleep(SD_TEST_BOARD_PWR_ON_DELAY_MS * 1000);
} else {
/* power off the card */
gpio_set_level(SD_TEST_BOARD_EN_GPIO, !SD_TEST_BOARD_EN_LEVEL);
gpio_set_direction(SD_TEST_BOARD_EN_GPIO, GPIO_MODE_INPUT);
/* discharge capacitors on VDD_SDIO */
gpio_reset_pin(SD_TEST_BOARD_DISCHARGE_GPIO);
gpio_set_direction(SD_TEST_BOARD_DISCHARGE_GPIO, GPIO_MODE_OUTPUT);
gpio_set_level(SD_TEST_BOARD_DISCHARGE_GPIO, 0);
usleep(SD_TEST_BOARD_PWR_RST_DELAY_MS * 1000);
/* reset the pin but leaving it floating so that VDD_SDIO won't be charged again */
gpio_reset_pin(SD_TEST_BOARD_DISCHARGE_GPIO);
gpio_pullup_dis(SD_TEST_BOARD_DISCHARGE_GPIO);
}
}
static const sdmmc_test_board_info_t s_board_info = {
.name = "ESP32-S3 eMMC test board v1",
.slot = {
{
.slot_exists = true,
.is_emmc = true,
.bus_width = 8,
.clk = 34,
.cmd_mosi = 33,
.d0_miso = 37,
.d1 = 38,
.d2 = 39,
.d3_cs = 36,
.d4 = 35,
.d5 = 40,
.d6 = 42,
.d7 = 41,
.cd = GPIO_NUM_NC,
.wp = GPIO_NUM_NC,
.unused_pin = 1,
},
{
.slot_exists = true,
.bus_width = 4,
.clk = 2,
.cmd_mosi = 4,
.d0_miso = 5,
.d1 = 6,
.d2 = 7,
.d3_cs = 8,
.d4 = GPIO_NUM_NC,
.d5 = GPIO_NUM_NC,
.d6 = GPIO_NUM_NC,
.d7 = GPIO_NUM_NC,
.cd = 21,
.wp = GPIO_NUM_NC,
.unused_pin = 1,
}
},
.card_power_set = card_power_set_esp32s3_emmc
};
#elif CONFIG_SDMMC_BOARD_ESP32S3_EYE
static const sdmmc_test_board_info_t s_board_info = {
.name = "ESP32-S3-EYE",
.slot = {
{
.slot_exists = false
},
{
.slot_exists = true,
.bus_width = 1,
.clk = 39,
.cmd_mosi = 38,
.d0_miso = 40,
.d1 = GPIO_NUM_NC,
.d2 = GPIO_NUM_NC,
.d3_cs = GPIO_NUM_NC,
.d4 = GPIO_NUM_NC,
.d5 = GPIO_NUM_NC,
.d6 = GPIO_NUM_NC,
.d7 = GPIO_NUM_NC,
.cd = GPIO_NUM_NC,
.wp = GPIO_NUM_NC,
.unused_pin = 1,
}
},
};
#elif CONFIG_SDMMC_BOARD_ESP32C3_BREAKOUT
#define SD_BREAKOUT_BOARD_EN_GPIO 10
#define SD_BREAKOUT_BOARD_EN_LEVEL 0
// Pin pulled down to discharge VDD_SDIO capacitors. CMD pin used here.
#define SD_TEST_BOARD_DISCHARGE_GPIO 4
#define SD_BREAKOUT_BOARD_PWR_RST_DELAY_MS 100
#define SD_BREAKOUT_BOARD_PWR_ON_DELAY_MS 100
static void card_power_set_esp32c3_breakout(bool en)
{
if (en) {
/* power off to make sure card is reset */
gpio_reset_pin(SD_BREAKOUT_BOARD_EN_GPIO);
gpio_set_direction(SD_BREAKOUT_BOARD_EN_GPIO, GPIO_MODE_OUTPUT);
gpio_set_level(SD_BREAKOUT_BOARD_EN_GPIO, !SD_BREAKOUT_BOARD_EN_LEVEL);
/* discharge capacitors on VDD_SDIO */
gpio_reset_pin(SD_TEST_BOARD_DISCHARGE_GPIO);
gpio_set_direction(SD_TEST_BOARD_DISCHARGE_GPIO, GPIO_MODE_OUTPUT);
gpio_set_level(SD_TEST_BOARD_DISCHARGE_GPIO, 0);
usleep(SD_BREAKOUT_BOARD_PWR_RST_DELAY_MS * 1000);
/* power on */
gpio_reset_pin(SD_TEST_BOARD_DISCHARGE_GPIO);
gpio_set_level(SD_BREAKOUT_BOARD_EN_GPIO, SD_BREAKOUT_BOARD_EN_LEVEL);
usleep(SD_BREAKOUT_BOARD_PWR_ON_DELAY_MS * 1000);
} else {
/* power off the card */
gpio_set_level(SD_BREAKOUT_BOARD_EN_GPIO, !SD_BREAKOUT_BOARD_EN_LEVEL);
gpio_set_direction(SD_BREAKOUT_BOARD_EN_GPIO, GPIO_MODE_INPUT);
/* set CMD low to discharge capacitors on VDD_SDIO */
gpio_reset_pin(SD_TEST_BOARD_DISCHARGE_GPIO);
gpio_set_direction(SD_TEST_BOARD_DISCHARGE_GPIO, GPIO_MODE_OUTPUT);
gpio_set_level(SD_TEST_BOARD_DISCHARGE_GPIO, 0);
usleep(SD_BREAKOUT_BOARD_PWR_RST_DELAY_MS * 1000);
/* reset the pin but leaving it floating so that VDD_SDIO won't be charged again */
gpio_reset_pin(SD_TEST_BOARD_DISCHARGE_GPIO);
gpio_reset_pin(SD_TEST_BOARD_DISCHARGE_GPIO);
}
}
static const sdmmc_test_board_info_t s_board_info = {
.name = "ESP32-C3 breakout board",
.slot = {
{
.slot_exists = false
},
{
.slot_exists = true,
.bus_width = 1,
.clk = 5,
.cmd_mosi = 4,
.d0_miso = 6,
.d1 = GPIO_NUM_NC,
.d2 = GPIO_NUM_NC,
.d3_cs = 1,
.d4 = GPIO_NUM_NC,
.d5 = GPIO_NUM_NC,
.d6 = GPIO_NUM_NC,
.d7 = GPIO_NUM_NC,
.cd = GPIO_NUM_NC,
.wp = GPIO_NUM_NC,
.unused_pin = 2,
}
},
.card_power_set = card_power_set_esp32c3_breakout
};
#elif CONFIG_SDMMC_BOARD_CUSTOM_SD
static const sdmmc_test_board_info_t s_board_info = {
.name = "Custom defined board (SD)",
.slot = {
{
.slot_exists = false
},
{
.slot_exists = true,
.bus_width = CONFIG_SDMMC_BOARD_CUSTOM_BUS_WIDTH,
#ifdef SOC_SDMMC_USE_GPIO_MATRIX
.clk = CONFIG_SDMMC_BOARD_CUSTOM_CLK,
.cmd_mosi = CONFIG_SDMMC_BOARD_CUSTOM_CMD,
.d0_miso = CONFIG_SDMMC_BOARD_CUSTOM_D0,
.d1 = CONFIG_SDMMC_BOARD_CUSTOM_D1,
.d2 = CONFIG_SDMMC_BOARD_CUSTOM_D2,
.d3_cs = CONFIG_SDMMC_BOARD_CUSTOM_D3,
#else // SOC_SDMMC_USE_GPIO_MATRIX
.clk = SDMMC_SLOT1_IOMUX_PIN_NUM_CLK,
.cmd_mosi = SDMMC_SLOT1_IOMUX_PIN_NUM_CMD,
.d0_miso = SDMMC_SLOT1_IOMUX_PIN_NUM_D0,
.d1 = SDMMC_SLOT1_IOMUX_PIN_NUM_D1,
.d2 = SDMMC_SLOT1_IOMUX_PIN_NUM_D2,
.d3_cs = SDMMC_SLOT1_IOMUX_PIN_NUM_D3,
#endif // SOC_SDMMC_USE_GPIO_MATRIX
.d4 = GPIO_NUM_NC,
.d5 = GPIO_NUM_NC,
.d6 = GPIO_NUM_NC,
.d7 = GPIO_NUM_NC,
.cd = CONFIG_SDMMC_BOARD_CUSTOM_CD,
.wp = CONFIG_SDMMC_BOARD_CUSTOM_WP,
.unused_pin = CONFIG_SDMMC_BOARD_CUSTOM_UNUSED,
}
},
};
#elif CONFIG_SDMMC_BOARD_CUSTOM_SPI
static const sdmmc_test_board_info_t s_board_info = {
.name = "Custom defined board (SPI)",
.slot = {
{
.slot_exists = false
},
{
.slot_exists = true,
.bus_width = 1,
.clk = CONFIG_SDMMC_BOARD_CUSTOM_SCK,
.cmd_mosi = CONFIG_SDMMC_BOARD_CUSTOM_MOSI,
.d0_miso = CONFIG_SDMMC_BOARD_CUSTOM_MISO,
.d1 = GPIO_NUM_NC,
.d2 = GPIO_NUM_NC,
.d3_cs = CONFIG_SDMMC_BOARD_CUSTOM_CS,
.d4 = GPIO_NUM_NC,
.d5 = GPIO_NUM_NC,
.d6 = GPIO_NUM_NC,
.d7 = GPIO_NUM_NC,
.cd = CONFIG_SDMMC_BOARD_CUSTOM_CD,
.wp = CONFIG_SDMMC_BOARD_CUSTOM_WP,
.unused_pin = CONFIG_SDMMC_BOARD_CUSTOM_UNUSED,
}
},
};
#endif // CONFIG_SDMMC_BOARD_*
const sdmmc_test_board_info_t* sdmmc_test_board_get_info(void)
{
return &s_board_info;
}

Wyświetl plik

@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 3.16)
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components")
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/components/esp_driver_sdmmc/test_apps/sd_test_utils/components")
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/components/esp_driver_sdmmc/test_apps/sdmmc_tests")
set(COMPONENTS main)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(sdmmc_test_console)

Wyświetl plik

@ -0,0 +1,108 @@
| Supported Targets | ESP32 | ESP32-P4 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- |
# SDMMC Test Application
This app is used to test the SDMMC protocol layer (in `sdmmc` component), as well as SDMMC and SDSPI drivers (in `driver` component).
The app serves two purposes:
1. It allows various Unity test cases for SDMMC protocol layer features: probing, data transfer, etc.
2. It also allows running lower level operations from the console, which makes it useful as a debugging/hacking/experimentation tool when investigating SDMMC issues.
- Initializing the SDMMC host in various modes
- Probing the card
- (more to come: sending commands, reading/writing data, etc.)
## SDMMC test app code overview
The app consists of several components:
- `main` — small amount of code to initialize the console and register all the commands.
- `components/cmd_unity` — console command to run Unity tests.
- `components/cmd_sdmmc` — console commands for SDMMC low-level operations.
- `components/sdmmc_test_board` — contains pin mappings for various development boards, and APIs for tests to access them.
- `components/sdmmc_test` — contains the actual test cases.
## Supported boards
* ESP32-WROVER-KIT
* ESP32 eMMC test board (black board with two SD card slots and eMMC)
* ESP32-S3 USB_OTG v1. (Also works with an older ESP32-S2 variant of the board.)
* ESP32-S3 eMMC test board (white board with two SD card slots and eMMC)
* ESP32-S3-EYE
* Breakout board for ESP32-C3 DevKitM-1
* Custom board definition: specify the pin mapping in `menuconfig`.
## Using the app
### Select the target, configure, build and flash the app
1. Choose the chip target, and open menuconfig:
```bash
idf.py set-target esp32
idf.py menuconfig
```
2. Select the development board in `SDMMC Test Board Configuration` menu. This will select the correct pins for the SD card slot on the board.
3. Save the configuration and exit menuconfig.
4. Build the app:
```bash
idf.py build
```
5. Flash and monitor:
```bash
idf.py flash monitor
```
### Advanced: multiple build configurations side-by-side
It is often useful to verify changes in `sdmmc` component on multiple chips or development boards. To do this, it is possible to build the app multiple times, with different configurations, keeping the builds in separate directories.
1. Build the app for the first target. This command does multiple things: selects the target, sets the build directory to `build_esp32`, and puts the sdkconfig file into the build directory:
```bash
idf.py -D IDF_TARGET=esp32 -B build_esp32 -D SDKCONFIG=build_esp32/sdkconfig build
```
2. Flash and monitor. Note that the build directory has to be specified with `-B` option:
```bash
idf.py -B build_esp32 flash monitor
```
3. Now you can build the app for the second target in another build directory:
```bash
idf.py -D IDF_TARGET=esp32s3 -B build_esp32s3 -D SDKCONFIG=build_esp32s3/sdkconfig build
```
4. Flash and monitor, again specifying the build directory:
```bash
idf.py -B build_esp32s3 flash monitor
```
Compared to the `idf.py set-target` approach, this method allows keeping multiple build configurations side-by-side, and switching between them easily. If you have multiple terminal windows open, you can use one window per board. Set ESPPORT environment variable to the correct serial port in each window, and flash and monitor the app in each window with the corresponding build directory (`-B`) argument.
### Console commands
The app supports the following console commands:
- Common system commands: `help`, `restart`, `version`, `free`, `heap`
- Log control: `log_level <tag> <level>` — dynamically change the log level for a given tag. For example, `log_level sdmmc_req debug` will enable debug logging in sdmmc_transaction.c
- Running unit tests: `test [index|name|tag|*]`.
- If no argument is given, prints the list of available tests.
- If a test index is given, runs the test with that index.
- If a test name is given, runs the test with that name.
- If a test tag is given, runs all tests with that tag. You can negate the tag by prefixing it with `!`, for example `test ![sdspi]` will run all tests except those tagged with `[sdspi]`.
- SDMMC low-level commands: `sdmmc_host_init`, `sdmmc_host_deinit`, `card_init`, `card_info`. Refer to the `help` output for more details.
As most other IDF console applications, the app supports line editing, commands history and tab completion.
### Running test cases
When running the tests, keep in mind that once an SD card has been initialized in SPI mode, it cannot be re-initalized in SD mode without first powering it off. This means that on boards without an SD card power control circuit, it is not possible to run all the tests in one go with `test *` command. Run SDMMC tests first, then SDSPI tests: `test [sdmmc]` and then `test [sdspi]`. If you need to run SDMMC test again, power cycle the card first.
On chips without an SDMMC host controller only SDSPI tests are compiled. In this case, `test *` can be used to run all tests.
### Skipped tests
To make the app compatible with various development boards without having lots of ifdefs in test cases, the tests will be ignored if the board is not compatible with the test case. For example, on boards with just one SD card slot (Slot 1), every test which uses Slot 0 is skipped.
For example, when running sdspi tests on ESP32-WROVER-KIT you will see something like this:
```
12 Tests 0 Failures 5 Ignored
```
This means that the 5 tests which use Slot 0 were skipped.

Wyświetl plik

@ -0,0 +1,13 @@
set(srcs "test_app_main.c")
set(priv_requires
# tests reside in this component, also available for `sdmmc_console`
sdmmc_tests
# general
unity
)
idf_component_register(SRCS ${srcs}
INCLUDE_DIRS "."
PRIV_REQUIRES ${priv_requires}
WHOLE_ARCHIVE TRUE)

Wyświetl plik

@ -0,0 +1,43 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*/
#include "unity.h"
#include "unity_test_utils.h"
#include "esp_heap_caps.h"
#include "sdkconfig.h"
#define TEST_MEMORY_LEAK_THRESHOLD (300)
void setUp(void)
{
unity_utils_record_free_mem();
}
void tearDown(void)
{
unity_utils_evaluate_leaks_direct(TEST_MEMORY_LEAK_THRESHOLD);
}
void app_main(void)
{
/*
_____ _ ______________ ______ ________
|_ _| | | / ___| _ \ \/ || \/ / __ \
| | ___ ___| |_ \ `--.| | | | . . || . . | / \/
| |/ _ \/ __| __| `--. \ | | | |\/| || |\/| | |
| | __/\__ \ |_ /\__/ / |/ /| | | || | | | \__/\
\_/\___||___/\__| \____/|___/ \_| |_/\_| |_/\____/
*/
printf(" _____ _ ______________ ______ ________\n");
printf("|_ _| | | / ___| _ \\ \\/ || \\/ / __ \\ \n");
printf(" | | ___ ___| |_ \\ `--.| | | | . . || . . | / \\/\n");
printf(" | |/ _ \\/ __| __| `--. \\ | | | |\\/| || |\\/| | |\n");
printf(" | | __/\\__ \\ |_ /\\__/ / |/ /| | | || | | | \\__/\\\n");
printf(" \\_/\\___||___/\\__| \\____/|___/ \\_| |_/\\_| |_/\\____/\n");
unity_run_menu();
}

Wyświetl plik

@ -0,0 +1,12 @@
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded_idf import IdfDut
@pytest.mark.esp32
@pytest.mark.esp32s3
@pytest.mark.sdcard
def test_sdmmc(dut: IdfDut) -> None:
dut.run_all_single_board_cases()

Wyświetl plik

@ -0,0 +1,2 @@
CONFIG_FREERTOS_HZ=1000
CONFIG_ESP_TASK_WDT_EN=n

Wyświetl plik

@ -0,0 +1,20 @@
set(srcs)
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")
endif()
set(priv_requires "sdmmc"
"esp_driver_sdmmc"
"sdmmc_test_boards"
"common_test_flows"
"unity"
)
idf_component_register(SRCS ${srcs}
PRIV_REQUIRES ${priv_requires}
WHOLE_ARCHIVE TRUE)

Wyświetl plik

@ -0,0 +1,53 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "sd_protocol_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Defines for readability */
#define SLOT_0 0
#define SLOT_1 1
#define NO_DDR 0
#define WITH_DDR 1
/* Helper functions to initialize/deinintalize the host (SDMMC/SDSPI) inside the test */
#if SOC_SDMMC_HOST_SUPPORTED
/**
* @brief Skip the test if the board is incompatible with the given slot, width, frequency and DDR mode
* This compares the requested values with the information from the board config, and skips the test
* (basically, exits it using TEST_IGNORE/longjmp) if the board is incompatible.
* @param slot Slot index (SLOT_0 or SLOT_1)
* @param width Slot width (1, 4 or 8)
* @param freq_khz Bus frequency in kHz
* @param ddr Whether to use DDR mode (NO_DDR or WITH_DDR)
*/
void sdmmc_test_sd_skip_if_board_incompatible(int slot, int width, int freq_khz, int ddr);
/**
* @brief Helper function to initialize the SDMMC host and slot for the test using the given settings
* @param slot Slot index (SLOT_0 or SLOT_1)
* @param width Slot width (1, 4 or 8)
* @param freq_khz Bus frequency in kHz
* @param ddr Whether to use DDR mode (NO_DDR or WITH_DDR)
* @param[out] out_card Output, pointer to the card structure to be filled by this function
*/
void sdmmc_test_sd_begin(int slot, int width, int freq_khz, int ddr, sdmmc_card_t *out_card);
/**
* @brief Helper function to deinitialize the SDMMC host and slot after the test
* @param card Pointer to the card structure to be deinitialized
*/
void sdmmc_test_sd_end(sdmmc_card_t *card);
#endif
#ifdef __cplusplus
};
#endif

Wyświetl plik

@ -0,0 +1,118 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <stdlib.h>
#include "esp_log.h"
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#include "unity.h"
#include "sdmmc_test_board.h"
#include "driver/sdmmc_host.h"
#include "sd_protocol_defs.h"
#include "sdmmc_cmd.h"
#include "sdmmc_test_begin_end.h"
#include "hal/gpio_hal.h"
void sdmmc_test_sd_skip_if_board_incompatible(int slot, int width, int freq_khz, int ddr)
{
sdmmc_host_t config = SDMMC_HOST_DEFAULT();
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
if (!sdmmc_test_board_has_slot(slot)) {
TEST_IGNORE_MESSAGE("Board doesn't have the required slot");
}
sdmmc_test_board_get_config_sdmmc(slot, &config, &slot_config);
int board_max_freq_khz = sdmmc_test_board_get_slot_info(slot)->max_freq_khz;
if (board_max_freq_khz > 0 && board_max_freq_khz < freq_khz) {
TEST_IGNORE_MESSAGE("Board doesn't support required max_freq_khz");
}
if (slot_config.width < width) {
TEST_IGNORE_MESSAGE("Board doesn't support required bus width");
}
}
void sdmmc_test_sd_begin(int slot, int width, int freq_khz, int ddr, sdmmc_card_t *out_card)
{
sdmmc_host_t config = SDMMC_HOST_DEFAULT();
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
/* Similar to the checks in sdmmc_test_sd_skip_if_board_incompatible, but
* we fail the test if we somehow got to this point with an incompatible board.
*/
if (!sdmmc_test_board_has_slot(slot)) {
TEST_FAIL_MESSAGE("Board doesn't have the required slot");
}
sdmmc_test_board_get_config_sdmmc(slot, &config, &slot_config);
int board_max_freq_khz = sdmmc_test_board_get_slot_info(slot)->max_freq_khz;
if (board_max_freq_khz > 0 && board_max_freq_khz < freq_khz) {
TEST_FAIL_MESSAGE("Board doesn't support required max_freq_khz");
}
if (slot_config.width < width) {
TEST_FAIL_MESSAGE("Board doesn't support required bus width");
}
config.max_freq_khz = freq_khz;
if (width == 1) {
config.flags = SDMMC_HOST_FLAG_1BIT;
slot_config.width = 1;
} else if (width == 4) {
config.flags = SDMMC_HOST_FLAG_4BIT;
slot_config.width = 4;
} else {
config.flags = SDMMC_HOST_FLAG_8BIT;
slot_config.width = 8;
assert(!ddr && "host driver does not support 8-line DDR mode yet");
}
/* Note, not checking sdmmc_test_board_slot_is_emmc here,
* to let us test DDR mode with eMMC breakout boards in SD slots.
*/
if (ddr) {
config.flags |= SDMMC_HOST_FLAG_DDR;
}
sdmmc_test_board_card_power_set(true);
TEST_ESP_OK(sdmmc_host_init());
TEST_ESP_OK(sdmmc_host_init_slot(slot, &slot_config));
TEST_ESP_OK(sdmmc_card_init(&config, out_card));
}
void sdmmc_test_sd_end(sdmmc_card_t *card)
{
TEST_ESP_OK(sdmmc_host_deinit());
// Reset all GPIOs to their default states
int slot = card->host.slot;
const sdmmc_test_board_slot_info_t *slot_info = sdmmc_test_board_get_slot_info(slot);
const int pins[] = {
slot_info->clk,
slot_info->cmd_mosi,
slot_info->d0_miso,
slot_info->d1,
slot_info->d2,
slot_info->d3_cs,
slot_info->d4,
slot_info->d5,
slot_info->d6,
slot_info->d7,
slot_info->cd,
slot_info->wp,
};
const int num_pins = sizeof(pins) / sizeof(pins[0]);
// Silence logging in gpio_reset_pin, which logs at INFO level
esp_log_level_t old_level = esp_log_level_get("gpio");
esp_log_level_set("gpio", ESP_LOG_WARN);
for (int i = 0; i < num_pins; i++) {
if (pins[i] >= 0) {
gpio_reset_pin(pins[i]);
gpio_pullup_dis(pins[i]);
}
}
esp_log_level_set("gpio", old_level);
//Need to reset GPIO first, otherrwise cannot discharge VDD of card completely.
sdmmc_test_board_card_power_set(false);
}

Wyświetl plik

@ -0,0 +1,48 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stddef.h>
#include "unity.h"
#include "sdmmc_cmd.h"
#include "driver/sdmmc_host.h"
#include "sdmmc_test_cd_wp_common.h"
#include "sdmmc_test_board.h"
//TODO: IDF-8734
#if !CONFIG_IDF_TARGET_ESP32 && !CONFIG_IDF_TARGET_ESP32S3
TEST_CASE("CD input works in SD mode", "[sdmmc]")
{
sdmmc_host_t config = SDMMC_HOST_DEFAULT();
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
sdmmc_test_board_get_config_sdmmc(SDMMC_HOST_SLOT_1, &config, &slot_config);
const int test_gpio = sdmmc_test_board_get_slot_info(SDMMC_HOST_SLOT_1)->unused_pin;
slot_config.gpio_cd = test_gpio;
sdmmc_test_board_card_power_set(true);
TEST_ESP_OK(sdmmc_host_init());
TEST_ESP_OK(sdmmc_host_init_slot(SDMMC_HOST_SLOT_1, &slot_config));
sdmmc_test_cd_input(test_gpio, &config);
TEST_ESP_OK(sdmmc_host_deinit());
sdmmc_test_board_card_power_set(false);
}
TEST_CASE("WP input works in SD mode", "[sdmmc]")
{
sdmmc_test_board_card_power_set(true);
sdmmc_host_t config = SDMMC_HOST_DEFAULT();
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
sdmmc_test_board_get_config_sdmmc(SDMMC_HOST_SLOT_1, &config, &slot_config);
const int test_gpio = sdmmc_test_board_get_slot_info(SDMMC_HOST_SLOT_1)->unused_pin;
slot_config.gpio_wp = test_gpio;
TEST_ESP_OK(sdmmc_host_init());
TEST_ESP_OK(sdmmc_host_init_slot(SDMMC_HOST_SLOT_1, &slot_config));
sdmmc_test_wp_input(test_gpio, &config);
TEST_ESP_OK(sdmmc_host_deinit());
sdmmc_test_board_card_power_set(false);
}
#endif

Wyświetl plik

@ -0,0 +1,66 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stddef.h>
#include "unity.h"
#include "sdmmc_cmd.h"
#include "sdmmc_test_begin_end.h"
static void do_one_sdmmc_probe_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);
uint8_t* buffer = heap_caps_calloc(512, 1, MALLOC_CAP_DMA);
TEST_ESP_OK(sdmmc_read_sectors(&card, buffer, 0, 1));
free(buffer);
sdmmc_test_sd_end(&card);
}
TEST_CASE("sdmmc probe, slot 0, 1-bit", "[sdmmc]")
{
do_one_sdmmc_probe_test(SLOT_0, 1, SDMMC_FREQ_PROBING, NO_DDR);
do_one_sdmmc_probe_test(SLOT_0, 1, SDMMC_FREQ_DEFAULT, NO_DDR);
do_one_sdmmc_probe_test(SLOT_0, 1, SDMMC_FREQ_HIGHSPEED, NO_DDR);
}
TEST_CASE("sdmmc probe, slot 0, 4-bit", "[sdmmc]")
{
do_one_sdmmc_probe_test(SLOT_0, 4, SDMMC_FREQ_PROBING, NO_DDR);
do_one_sdmmc_probe_test(SLOT_0, 4, SDMMC_FREQ_DEFAULT, NO_DDR);
do_one_sdmmc_probe_test(SLOT_0, 4, SDMMC_FREQ_HIGHSPEED, NO_DDR);
}
TEST_CASE("sdmmc probe, slot 0, 4-bit DDR", "[sdmmc]")
{
do_one_sdmmc_probe_test(SLOT_0, 4, SDMMC_FREQ_HIGHSPEED, WITH_DDR);
}
TEST_CASE("sdmmc probe, slot 0, 8-bit", "[sdmmc]")
{
do_one_sdmmc_probe_test(SLOT_0, 8, SDMMC_FREQ_PROBING, NO_DDR);
do_one_sdmmc_probe_test(SLOT_0, 8, SDMMC_FREQ_DEFAULT, NO_DDR);
do_one_sdmmc_probe_test(SLOT_0, 8, SDMMC_FREQ_HIGHSPEED, NO_DDR);
}
TEST_CASE("sdmmc probe, slot 1, 1-bit", "[sdmmc]")
{
do_one_sdmmc_probe_test(SLOT_1, 1, SDMMC_FREQ_PROBING, NO_DDR);
do_one_sdmmc_probe_test(SLOT_1, 1, SDMMC_FREQ_DEFAULT, NO_DDR);
do_one_sdmmc_probe_test(SLOT_1, 1, SDMMC_FREQ_HIGHSPEED, NO_DDR);
}
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);
}
TEST_CASE("sdmmc probe, slot 1, 4-bit DDR", "[sdmmc]")
{
do_one_sdmmc_probe_test(SLOT_1, 4, SDMMC_FREQ_HIGHSPEED, WITH_DDR);
}

Wyświetl plik

@ -0,0 +1,103 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <stddef.h>
#include "unity.h"
#include "sdmmc_cmd.h"
#include "sdmmc_test_begin_end.h"
#include "sdmmc_test_rw_common.h"
/* ========== Read/write performance tests, SD ========== */
static void do_one_sdmmc_perf_test(int slot, int width, int freq_khz, int ddr, FILE* perf_log)
{
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_rw_performance(&card, perf_log);
sdmmc_test_sd_end(&card);
}
TEST_CASE("sdmmc read/write performance, slot 0, 4-bit", "[sdmmc]")
{
do_one_sdmmc_perf_test(SLOT_0, 4, SDMMC_FREQ_HIGHSPEED, NO_DDR, NULL);
}
TEST_CASE("sdmmc read/write performance, slot 0, 4-bit DDR", "[sdmmc]")
{
do_one_sdmmc_perf_test(SLOT_0, 4, SDMMC_FREQ_HIGHSPEED, WITH_DDR, NULL);
}
TEST_CASE("sdmmc read/write performance, slot 0, 8-bit", "[sdmmc]")
{
do_one_sdmmc_perf_test(SLOT_0, 8, SDMMC_FREQ_HIGHSPEED, NO_DDR, NULL);
}
TEST_CASE("sdmmc read/write performance, slot 1, 4-bit", "[sdmmc]")
{
/* Set up in-memory file for collecting performance logs */
char *perf_log_buf = NULL;
size_t perf_log_size = 0;
FILE* perf_log = open_memstream(&perf_log_buf, &perf_log_size);
/* Run the actual tests */
do_one_sdmmc_perf_test(SLOT_1, 4, SDMMC_FREQ_HIGHSPEED, NO_DDR, perf_log);
/* Dump the contents of the performance log to stdout */
fclose(perf_log);
fwrite(perf_log_buf, perf_log_size, 1, stdout);
free(perf_log_buf);
}
TEST_CASE("sdmmc read/write performance, slot 1, 4-bit DDR", "[sdmmc]")
{
do_one_sdmmc_perf_test(SLOT_1, 4, SDMMC_FREQ_HIGHSPEED, WITH_DDR, NULL);
}
/* ========== Read/write tests with offset, SD ========== */
static void do_one_sdmmc_rw_test_with_offset(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_rw_with_offset(&card);
sdmmc_test_sd_end(&card);
}
TEST_CASE("sdmmc read/write performance with offset, slot 0, 4-bit", "[sdmmc]")
{
do_one_sdmmc_rw_test_with_offset(SLOT_0, 4, SDMMC_FREQ_HIGHSPEED, 0);
}
TEST_CASE("sdmmc read/write performance with offset, slot 1, 4-bit", "[sdmmc]")
{
do_one_sdmmc_rw_test_with_offset(SLOT_1, 4, SDMMC_FREQ_HIGHSPEED, 0);
}
/* ========== Read/write tests with unaligned source/destination buffer, SD ========== */
static void do_one_sdmmc_rw_test_unaligned_buffer(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_rw_unaligned_buffer(&card);
sdmmc_test_sd_end(&card);
}
TEST_CASE("sdmmc read/write using unaligned buffer, slot 0, 4-bit", "[sdmmc]")
{
do_one_sdmmc_rw_test_unaligned_buffer(SLOT_0, 4, SDMMC_FREQ_DEFAULT, 0);
}
TEST_CASE("sdmmc read/write using unaligned buffer, slot 1, 4-bit", "[sdmmc]")
{
do_one_sdmmc_rw_test_unaligned_buffer(SLOT_1, 4, SDMMC_FREQ_DEFAULT, 0);
}

Wyświetl plik

@ -77,9 +77,10 @@ ENV_MARKERS = {
'xtal_26mhz': 'runner with 26MHz xtal on board',
'xtal_40mhz': 'runner with 40MHz xtal on board',
'external_flash': 'external flash memory connected via VSPI (FSPI)',
'sdcard_sdmode': 'sdcard running in SD mode',
'sdcard_sdmode': 'sdcard running in SD mode, to be removed after test migration',
'sdcard_spimode': 'sdcard running in SPI mode',
'emmc': 'eMMC card',
'sdcard': 'sdcard runner',
'MSPI_F8R8': 'runner with Octal Flash and Octal PSRAM',
'MSPI_F4R8': 'runner with Quad Flash and Octal PSRAM',
'MSPI_F4R4': 'runner with Quad Flash and Quad PSRAM',