Merge branch 'refactor/esp_driver_sdio' into 'master'

refactor(sdio): place sdio slave driver into a new component

Closes IDF-8373

See merge request espressif/esp-idf!27125
This commit is contained in:
Armando (Dou Yiwen)
2023-11-22 21:13:00 +08:00
30 changed files with 71 additions and 80 deletions

View File

@@ -92,16 +92,6 @@ components/driver/test_apps/rs485:
temporary: true
reason: lack of runners
components/driver/test_apps/sdio/sdio_common_tests/host_sdmmc:
enable:
- if: IDF_TARGET == "esp32"
temporary: false
reason: always use ESP32 SDMMC as host
components/driver/test_apps/sdio/sdio_common_tests/sdio:
disable:
- if: SOC_SDIO_SLAVE_SUPPORTED != 1
components/driver/test_apps/sigma_delta:
disable:
- if: SOC_SDM_SUPPORTED != 1

View File

@@ -1,7 +0,0 @@
# SDIO Cross Chips Test Apps
This folder contains SDIO related tests. This folder contains two sub-folders:
- host_sdmmc: this fodler contains the ESP32 SDMMC test app which works as the host to test the SDIO Slave peripheral
- sdio: this fodler contains the ESP SDIO Slave test apps
Tests in this folder are all dual-board tests.

View File

@@ -1,13 +0,0 @@
# This is the project CMakeLists.txt file for the test subproject
cmake_minimum_required(VERSION 3.16)
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
set(COMPONENTS main)
set(EXTRA_COMPONENT_DIRS
"$ENV{IDF_PATH}/tools/unit-test-app/components"
"$ENV{IDF_PATH}/components/driver/test_apps/components"
)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(host_sdmmc)

View File

@@ -1,6 +0,0 @@
| Supported Targets | ESP32 |
| ----------------- | ----- |
# SDIO Cross Chips Test Apps: SDMMC Host App
This test app is using ESP32 SDMMC as the host to test the SDIO Slave peripherals among ESP chips.

View File

@@ -1,6 +0,0 @@
set(srcs "test_app_main.c"
"test_sdio_sdhost.c")
idf_component_register(SRCS ${srcs}
PRIV_REQUIRES unity test_driver_utils driver esp_serial_slave_link sdmmc test_utils esp_timer
WHOLE_ARCHIVE)

View File

@@ -1,2 +0,0 @@
dependencies:
ccomp_timer: "^1.0.0"

View File

@@ -1,52 +0,0 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include "unity.h"
#include "unity_test_utils.h"
#include "esp_heap_caps.h"
// Some resources are lazy allocated, the threadhold is left for that case
#define TEST_MEMORY_LEAK_THRESHOLD (700)
static size_t before_free_8bit;
static size_t before_free_32bit;
void setUp(void)
{
before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
}
void tearDown(void)
{
size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
unity_utils_check_leak(before_free_8bit, after_free_8bit, "8BIT", TEST_MEMORY_LEAK_THRESHOLD);
unity_utils_check_leak(before_free_32bit, after_free_32bit, "32BIT", TEST_MEMORY_LEAK_THRESHOLD);
}
void app_main(void)
{
/* _____ ____ ________ _____ ____ __ _____ _________
/ ___// __ \/ _/ __ \ / ___// __ \/ |/ / |/ / ____/
\__ \/ / / // // / / / \__ \/ / / / /|_/ / /|_/ / /
___/ / /_/ // // /_/ / ___/ / /_/ / / / / / / / /___
/____/_____/___/\____/ /____/_____/_/ /_/_/ /_/\____/
*/
printf(" _____ ____ ________ _____ ____ __ _____ _________\n");
printf(" / ___// __ \\/ _/ __ \\ / ___// __ \\/ |/ / |/ / ____/\n");
printf(" \\__ \\/ / / // // / / / \\__ \\/ / / / /|_/ / /|_/ / / \n");
printf(" ___/ / /_/ // // /_/ / ___/ / /_/ / / / / / / / /___ \n");
printf("/____/_____/___/\\____/ /____/_____/_/ /_/_/ /_/\\____/ \n");
printf(" \n");
unity_run_menu();
}

View File

@@ -1,359 +0,0 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* This file uses ESP32 SDMMC peripheral to test SDIO Slave peripheral SD modes
*/
#include "unity.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_timer.h"
#include "ccomp_timer.h"
#include "sdmmc_cmd.h"
#include "driver/sdmmc_host.h"
#include "esp_serial_slave_link/essl_sdio.h"
#include "soc/soc_caps.h"
#include "test_utils.h"
#include "idf_performance.h"
#include "test_dualboard_utils.h"
#include "../../sdio_common_test.h"
static const char *TAG = "test_sdio_sdhost";
#define TEST_HEX_LOG_LEVEL ESP_LOG_DEBUG
#define TEST_INT_MASK_ALL 0xff
#define TEST_REG_ADDR_MAX 60
#define TEST_TIMEOUT_MAX UINT32_MAX
typedef struct {
uint32_t host_flags;
uint32_t max_freq_khz;
bool check_data;
} test_sdio_param_t;
/*---------------------------------------------------------------
Host Init Settings
---------------------------------------------------------------*/
static sdmmc_card_t s_card;
static void s_master_init(test_sdio_param_t *host_param, essl_handle_t *out_handle)
{
sdmmc_host_t host_config = (sdmmc_host_t)SDMMC_HOST_DEFAULT();
host_config.flags = host_param->host_flags;
if (host_config.flags == SDMMC_HOST_FLAG_4BIT) {
ESP_LOGI(TAG, "Probe using SD 4-bit...");
} else if (host_config.flags == SDMMC_HOST_FLAG_1BIT) {
ESP_LOGI(TAG, "Probe using SD 1-bit...");
}
host_config.max_freq_khz = host_param->max_freq_khz;
ESP_LOGI(TAG, "Host max_freq_khz: %d", host_config.max_freq_khz);
//init sdmmc host
TEST_ESP_OK(sdmmc_host_init());
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
TEST_ESP_OK(sdmmc_host_init_slot(SDMMC_HOST_SLOT_1, &slot_config));
//host init slave
sdmmc_card_t *card = &s_card;
//wait for at least 5 seconds
int retry_times = 5;
do {
if (sdmmc_card_init(&host_config, card) == ESP_OK) {
break;
}
ESP_LOGW(TAG, "slave init failed, retry...");
vTaskDelay(1000 / portTICK_PERIOD_MS);
} while (--retry_times);
TEST_ASSERT_MESSAGE(retry_times != 0, "Initializing slave failed.");
//init essl sdmmc host
essl_sdio_config_t essl_sdio_config = {
.card = card,
.recv_buffer_size = TEST_RX_BUFFER_SIZE,
};
TEST_ESP_OK(essl_sdio_init_dev(out_handle, &essl_sdio_config));
TEST_ESP_OK(essl_init(*out_handle, TEST_TIMEOUT_MAX));
}
//trigger event 7 to indicate Slave to stop the test
static void s_send_finish_test(essl_handle_t handle)
{
//the slave needs a signal to quite the test
essl_send_slave_intr(handle, BIT(7), TEST_TIMEOUT_MAX);
}
/*---------------------------------------------------------------
Function Tests
---------------------------------------------------------------*/
/*---------------------------------------------------------------
SDMMC_SDIO: test interrupt
---------------------------------------------------------------*/
TEST_CASE("SDIO_SDMMC: test interrupt", "[sdio]")
{
esp_err_t ret = ESP_FAIL;
essl_handle_t handle = NULL;
test_sdio_param_t test_param = {
.host_flags = SDMMC_HOST_FLAG_4BIT,
.max_freq_khz = SDMMC_FREQ_HIGHSPEED,
};
//essl init and sdmmc init
s_master_init(&test_param, &handle);
TEST_ESP_OK(essl_set_intr_ena(handle, TEST_INT_MASK_ALL, TEST_TIMEOUT_MAX));
ret = essl_wait_int(handle, 0);
TEST_ASSERT_EQUAL_HEX(ESP_ERR_TIMEOUT, ret);
//tests all 8 interrupts of the slave, in which int 7 is used to terminate the test on the slave.
for (int i = 0; i < 8; i ++) {
esp_rom_printf("to essl_send_slave_intr\n");
TEST_ESP_OK(essl_send_slave_intr(handle, BIT(i), TEST_TIMEOUT_MAX));
//the slave should return interrupt with the same bit in 10 ms
TEST_ESP_OK(essl_wait_int(handle, 10));
uint32_t int_st;
TEST_ESP_OK(essl_get_intr(handle, NULL, &int_st, TEST_TIMEOUT_MAX));
//check and clear the returned interrupt
TEST_ASSERT_EQUAL_HEX(BIT(i), int_st);
TEST_ESP_OK(essl_clear_intr(handle, int_st, TEST_TIMEOUT_MAX));
}
sdmmc_host_deinit();
}
/*---------------------------------------------------------------
SDMMC_SDIO: test register
---------------------------------------------------------------*/
TEST_CASE("SDIO_SDMMC: test register", "[sdio]")
{
essl_handle_t handle = NULL;
test_sdio_param_t test_param = {
.host_flags = SDMMC_HOST_FLAG_4BIT,
.max_freq_khz = SDMMC_FREQ_HIGHSPEED,
};
//essl init and sdmmc init
s_master_init(&test_param, &handle);
uint32_t init_val = 30;
srand(850);
//initialize the registers
for (int i = 0; i < TEST_REG_ADDR_MAX; i++) {
TEST_ESP_OK(essl_write_reg(handle, i, init_val, NULL, 10));
}
for (int i = 0; i < TEST_REG_ADDR_MAX; i++) {
uint8_t data_write = rand() % 0xFF;
TEST_ESP_OK(essl_write_reg(handle, i, data_write, NULL, 10));
uint8_t data_read = 0;
TEST_ESP_OK(essl_read_reg(handle, i, &data_read, 10));
TEST_ASSERT_EQUAL_HEX8(data_write, data_read);
}
s_send_finish_test(handle);
sdmmc_host_deinit();
}
/*---------------------------------------------------------------
SDMMC_SDIO: test reset
---------------------------------------------------------------*/
TEST_CASE("SDIO_SDMMC: test reset", "[sdio]")
{
essl_handle_t handle = NULL;
test_sdio_param_t test_param = {
.host_flags = SDMMC_HOST_FLAG_4BIT,
.max_freq_khz = SDMMC_FREQ_HIGHSPEED,
};
//essl init and sdmmc init
s_master_init(&test_param, &handle);
//wait for the slave to stop, reset and start again
vTaskDelay(10);
//rx
WORD_ALIGNED_ATTR uint8_t slave_tx_buffer[TEST_RESET_DATA_LEN] = {};
WORD_ALIGNED_ATTR uint8_t host_rx_buffer[TEST_RESET_DATA_LEN] = {};
size_t read_len = 0;
for (int i = 0; i < TEST_RESET_BUF_NUMS; i++) {
test_fill_random_to_buffer(i, slave_tx_buffer, TEST_RESET_DATA_LEN);
esp_err_t ret = essl_get_packet(handle, host_rx_buffer, TEST_RESET_DATA_LEN, &read_len, portMAX_DELAY);
if (ret == ESP_ERR_NOT_FINISHED) {
printf("not finished\n");
ret = ESP_OK;
}
TEST_ESP_OK(ret);
TEST_ASSERT_EQUAL(TEST_RESET_DATA_LEN, read_len);
TEST_ASSERT_EQUAL_HEX8_ARRAY(slave_tx_buffer, host_rx_buffer, read_len);
}
//tx
WORD_ALIGNED_ATTR uint8_t host_tx_buffer[TEST_RESET_BUF_NUMS][TEST_RESET_DATA_LEN] = {};
for (int i = 0; i < TEST_RESET_BUF_NUMS; i++) {
test_fill_random_to_buffer(i, host_tx_buffer[i], TEST_RESET_DATA_LEN);
TEST_ESP_OK(essl_send_packet(handle, host_tx_buffer[i], TEST_RESET_DATA_LEN, TEST_TIMEOUT_MAX));
}
s_send_finish_test(handle);
sdmmc_host_deinit();
}
/*---------------------------------------------------------------
Transaction Tests
---------------------------------------------------------------*/
test_sdio_param_t test_param_lists[TEST_TARNS_PARAM_NUMS] = {
{
.host_flags = SDMMC_HOST_FLAG_4BIT,
.max_freq_khz = SDMMC_FREQ_HIGHSPEED,
},
{
.host_flags = SDMMC_HOST_FLAG_1BIT,
.max_freq_khz = SDMMC_FREQ_HIGHSPEED,
},
};
/*---------------------------------------------------------------
SDMMC_SDIO: test from host
---------------------------------------------------------------*/
static void test_from_host(bool check_data)
{
test_prepare_buffer_pool(TEST_RX_BUFFER_SIZE * 4, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT | MALLOC_CAP_DMA);
for (int i = 0; i < TEST_TARNS_PARAM_NUMS; i++) {
ESP_LOGI(TAG, "host mode: %s", (test_param_lists[i].host_flags == SDMMC_HOST_FLAG_4BIT) ? "4BIT Mode" : "1BIT Mode");
ESP_LOGI(TAG, "host speed: %"PRIu32" kHz", test_param_lists[i].max_freq_khz);
essl_handle_t handle = NULL;
s_master_init(&test_param_lists[i], &handle);
// Two counters are used. The `esp_timer_get_time()` is for the typical time, and the
// `ccomp_timer` is for performance test to reduce influence caused by cache miss.
int64_t pre_us = esp_timer_get_time();
TEST_ESP_OK(ccomp_timer_start());
uint32_t expected_length = TEST_TRANS_NUMS * TEST_RX_BUFFER_SIZE;
void *tx_buf_ptr = NULL;
for (int j = 0; j < TEST_TRANS_NUMS; j++) {
ESP_LOGD(TAG, "j: %d", j);
test_get_buffer_from_pool(j, TEST_RX_BUFFER_SIZE, &tx_buf_ptr);
ESP_LOG_BUFFER_HEX_LEVEL(TAG, tx_buf_ptr, TEST_RX_BUFFER_SIZE, TEST_HEX_LOG_LEVEL);
TEST_ESP_OK(essl_send_packet(handle, tx_buf_ptr, TEST_RX_BUFFER_SIZE, TEST_TIMEOUT_MAX));
}
int64_t c_time_ms = ccomp_timer_stop() / 1000;
int64_t end_us = esp_timer_get_time();
uint32_t total_time_ms = (end_us - pre_us) / 1000;
ESP_LOGI(TAG, "test done, total time: %" PRIu32 " ms (%d ms compensated), bytes transferred: %"PRIu32, total_time_ms, (int)c_time_ms, expected_length);
uint32_t throughput_byte_per_ms = expected_length / c_time_ms;
ESP_LOGI(TAG, "Throughput: compensated %"PRIu32"KB/s (%.2lf MB/s), typical %.2lf MB/s",
throughput_byte_per_ms, throughput_byte_per_ms / 1000., expected_length / (total_time_ms * 1000.));
esp_rom_delay_us(50 * 1000);
s_send_finish_test(handle);
sdmmc_host_deinit();
}
test_destroy_buffer_pool();
}
TEST_CASE("SDIO_SDMMC: test from host", "[sdio]")
{
test_from_host(true);
}
TEST_CASE("SDIO_SDMMC: test from host (Performance)", "[sdio_speed]")
{
test_from_host(false);
}
static void test_to_host(bool check_data)
{
//prepare buffer
test_prepare_buffer_pool(TEST_RX_BUFFER_SIZE * 21, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT | MALLOC_CAP_DMA);
int recv_size = 4096;
uint8_t *host_rx_buffer = (uint8_t *)heap_caps_calloc(1, recv_size, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT | MALLOC_CAP_DMA);
for (int i = 0; i < TEST_TARNS_PARAM_NUMS; i++) {
ESP_LOGI(TAG, "host mode: %s", (test_param_lists[i].host_flags == SDMMC_HOST_FLAG_4BIT) ? "4BIT Mode" : "1BIT Mode");
ESP_LOGI(TAG, "host speed: %"PRIu32" kHz", test_param_lists[i].max_freq_khz);
essl_handle_t handle = NULL;
s_master_init(&test_param_lists[i], &handle);
esp_err_t ret;
int offset = 0;
void *tx_buf_ptr = NULL;
uint32_t expected_length = TEST_TRANS_NUMS * TEST_RX_BUFFER_SIZE;
int remain_length = expected_length;
// Two counters are used. The `esp_timer_get_time()` is for the typical time, and the
// `ccomp_timer` is for performance test to reduce influence caused by cache miss.
int64_t pre_us = esp_timer_get_time();
TEST_ESP_OK(ccomp_timer_start());
do {
size_t rcv_len;
ret = essl_get_packet(handle, host_rx_buffer, recv_size, &rcv_len, TEST_TIMEOUT_MAX);
TEST_ASSERT(ret == ESP_OK || ret == ESP_ERR_NOT_FINISHED);
TEST_ASSERT_LESS_OR_EQUAL(remain_length, rcv_len);
if (check_data) {
size_t compared_len = 0;
do {
test_get_buffer_from_pool(offset, TEST_RX_BUFFER_SIZE, &tx_buf_ptr);
TEST_ASSERT_EQUAL_HEX8_ARRAY(tx_buf_ptr, &host_rx_buffer[compared_len], TEST_RX_BUFFER_SIZE);
compared_len += TEST_RX_BUFFER_SIZE;
offset += TEST_RX_BUFFER_SIZE;
} while (compared_len < rcv_len);
}
remain_length -= rcv_len;
} while (remain_length > 0);
int64_t c_time_ms = ccomp_timer_stop()/1000;
int64_t end_us = esp_timer_get_time();
uint32_t total_time_ms = (end_us - pre_us)/1000;
ESP_LOGI(TAG, "test done, total time: %" PRIu32 " ms (%d ms compensated), bytes transferred: %"PRIu32, total_time_ms, (int)c_time_ms, expected_length);
uint32_t throughput_byte_per_ms = expected_length / c_time_ms;
ESP_LOGI(TAG, "Throughput: compensated %"PRIu32"KB/s %.2lf MB/s, typical %.2lf MB/s",
throughput_byte_per_ms, throughput_byte_per_ms/1000., expected_length/(total_time_ms*1000.));
esp_rom_delay_us(50 * 1000);
s_send_finish_test(handle);
sdmmc_host_deinit();
}
free(host_rx_buffer);
test_destroy_buffer_pool();
}
TEST_CASE("SDIO_SDMMC: test to host", "[sdio]")
{
test_to_host(true);
}
TEST_CASE("SDIO_SDMMC: test to host (Performance)", "[sdio_speed]")
{
test_to_host(false);
}

View File

@@ -1,2 +0,0 @@
# don't delete.
# used for CI to compile a default config when 'sdkconfig.ci.xxxx' is exist

View File

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

View File

@@ -1,133 +0,0 @@
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import os.path
from typing import Tuple
import pytest
from pytest_embedded_idf import IdfDut
# Normal tests
def test_sdio_flow(dut:Tuple[IdfDut, IdfDut]) -> None:
dut[1].expect('Press ENTER to see the list of tests')
dut[1].write('[sdio]')
dut[1].expect('test_sdio: slave ready')
dut[0].expect('Press ENTER to see the list of tests')
dut[0].write('[sdio]')
dut[1].expect_unity_test_output()
dut[0].expect_unity_test_output()
@pytest.mark.esp32c6
@pytest.mark.sdio_multidev_32_c6
@pytest.mark.parametrize('count', [2,], indirect=True)
@pytest.mark.parametrize('app_path, target', [
pytest.param(
f'{os.path.join(os.path.dirname(__file__), "host_sdmmc")}|{os.path.join(os.path.dirname(__file__), "sdio")}',
'esp32|esp32c6'),
], indirect=True)
def test_sdio_esp32_esp32c6(dut:Tuple[IdfDut, IdfDut]) -> None:
test_sdio_flow(dut)
@pytest.mark.esp32
@pytest.mark.sdio_master_slave
@pytest.mark.parametrize('count', [2,], indirect=True)
@pytest.mark.parametrize('app_path, target', [
pytest.param(
f'{os.path.join(os.path.dirname(__file__), "host_sdmmc")}|{os.path.join(os.path.dirname(__file__), "sdio")}',
'esp32|esp32'),
], indirect=True)
def test_sdio_esp32_esp32(dut:Tuple[IdfDut, IdfDut]) -> None:
test_sdio_flow(dut)
# From host speed tests
def test_sdio_speed_frhost_flow(dut:Tuple[IdfDut, IdfDut], expected_4b_speed:int, expected_1b_speed:int) -> None:
dut[1].expect('Press ENTER to see the list of tests')
dut[1].write('"SDIO_Slave: test from host (Performance)"')
dut[1].expect('test_sdio: slave ready')
dut[0].expect('Press ENTER to see the list of tests')
dut[0].write('"SDIO_SDMMC: test from host (Performance)"')
dut[0].expect('Probe using SD 4-bit')
res = dut[0].expect(r'Throughput: compensated (\d+)')
frhost_speed_4bit = res.group(1).decode('utf8')
assert (int(frhost_speed_4bit) > expected_4b_speed)
dut[0].expect('Probe using SD 1-bit')
res = dut[0].expect(r'Throughput: compensated (\d+)')
frhost_speed_1bit = res.group(1).decode('utf8')
assert (int(frhost_speed_1bit) > expected_1b_speed)
@pytest.mark.esp32c6
@pytest.mark.sdio_multidev_32_c6
@pytest.mark.parametrize('count', [2,], indirect=True)
@pytest.mark.parametrize('app_path, target', [
pytest.param(
f'{os.path.join(os.path.dirname(__file__), "host_sdmmc")}|{os.path.join(os.path.dirname(__file__), "sdio")}',
'esp32|esp32c6'),
], indirect=True)
def test_sdio_speed_frhost_esp32_esp32c6(dut:Tuple[IdfDut, IdfDut]) -> None:
test_sdio_speed_frhost_flow(dut, 10000, 4000)
@pytest.mark.esp32
@pytest.mark.sdio_master_slave
@pytest.mark.parametrize('count', [2,], indirect=True)
@pytest.mark.parametrize('app_path, target', [
pytest.param(
f'{os.path.join(os.path.dirname(__file__), "host_sdmmc")}|{os.path.join(os.path.dirname(__file__), "sdio")}',
'esp32|esp32'),
], indirect=True)
def test_sdio_speed_frhost_esp32_esp32(dut:Tuple[IdfDut, IdfDut]) -> None:
test_sdio_speed_frhost_flow(dut, 12200, 4000)
# To host speed tests
def test_sdio_speed_tohost_flow(dut:Tuple[IdfDut, IdfDut], expected_4b_speed:int, expected_1b_speed:int) -> None:
dut[1].expect('Press ENTER to see the list of tests')
dut[1].write('"SDIO_Slave: test to host (Performance)"')
dut[1].expect('test_sdio: slave ready')
dut[0].expect('Press ENTER to see the list of tests')
dut[0].write('"SDIO_SDMMC: test to host (Performance)"')
dut[0].expect('Probe using SD 4-bit')
res = dut[0].expect(r'Throughput: compensated (\d+)')
tohost_speed_4bit = res.group(1).decode('utf8')
assert (int(tohost_speed_4bit) > expected_4b_speed)
dut[0].expect('Probe using SD 1-bit')
res = dut[0].expect(r'Throughput: compensated (\d+)')
tohost_speed_1bit = res.group(1).decode('utf8')
assert (int(tohost_speed_1bit) > expected_1b_speed)
@pytest.mark.esp32c6
@pytest.mark.sdio_multidev_32_c6
@pytest.mark.parametrize('count', [2,], indirect=True)
@pytest.mark.parametrize('app_path, target', [
pytest.param(
f'{os.path.join(os.path.dirname(__file__), "host_sdmmc")}|{os.path.join(os.path.dirname(__file__), "sdio")}',
'esp32|esp32c6'),
], indirect=True)
def test_sdio_speed_tohost_esp32_esp32c6(dut:Tuple[IdfDut, IdfDut]) -> None:
test_sdio_speed_tohost_flow(dut, 9000, 4000)
@pytest.mark.esp32
@pytest.mark.sdio_master_slave
@pytest.mark.parametrize('count', [2,], indirect=True)
@pytest.mark.parametrize('app_path, target', [
pytest.param(
f'{os.path.join(os.path.dirname(__file__), "host_sdmmc")}|{os.path.join(os.path.dirname(__file__), "sdio")}',
'esp32|esp32'),
], indirect=True)
def test_sdio_speed_tohost_esp32_esp32(dut:Tuple[IdfDut, IdfDut]) -> None:
test_sdio_speed_tohost_flow(dut, 12200, 4000)

View File

@@ -1,13 +0,0 @@
# This is the project CMakeLists.txt file for the test subproject
cmake_minimum_required(VERSION 3.16)
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
set(COMPONENTS main)
set(EXTRA_COMPONENT_DIRS
"$ENV{IDF_PATH}/tools/unit-test-app/components"
"$ENV{IDF_PATH}/components/driver/test_apps/components"
)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(sdio)

View File

@@ -1,6 +0,0 @@
| Supported Targets | ESP32 | ESP32-C6 |
| ----------------- | ----- | -------- |
# SDIO Cross Chips Test Apps: SDIO Slave App
This test app is to test ESP SDIO Slave peripheral.

View File

@@ -1,6 +0,0 @@
set(srcs "test_app_main.c"
"test_sdio_slave.c")
idf_component_register(SRCS ${srcs}
PRIV_REQUIRES test_driver_utils driver
WHOLE_ARCHIVE)

View File

@@ -1,50 +0,0 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include "unity.h"
#include "unity_test_utils.h"
#include "esp_heap_caps.h"
// Some resources are lazy allocated, the threadhold is left for that case
#define TEST_MEMORY_LEAK_THRESHOLD (300)
static size_t before_free_8bit;
static size_t before_free_32bit;
void setUp(void)
{
before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
}
void tearDown(void)
{
size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
unity_utils_check_leak(before_free_8bit, after_free_8bit, "8BIT", TEST_MEMORY_LEAK_THRESHOLD);
unity_utils_check_leak(before_free_32bit, after_free_32bit, "32BIT", TEST_MEMORY_LEAK_THRESHOLD);
}
void app_main(void)
{
/*
_____ ____ ________ _____ __
/ ___// __ \/ _/ __ \ / ___// /___ __ _____
\__ \/ / / // // / / / \__ \/ / __ `/ | / / _ \
___/ / /_/ // // /_/ / ___/ / / /_/ /| |/ / __/
/____/_____/___/\____/ /____/_/\__,_/ |___/\___/
*/
printf(" _____ ____ ________ _____ __ \n");
printf(" / ___// __ \\/ _/ __ \\ / ___// /___ __ _____ \n");
printf(" \\__ \\/ / / // // / / / \\__ \\/ / __ `/ | / / _ \\\n");
printf(" ___/ / /_/ // // /_/ / ___/ / / /_/ /| |/ / __/\n");
printf("/____/_____/___/\\____/ /____/_/\\__,_/ |___/\\___/\n");
unity_run_menu();
}

View File

@@ -1,303 +0,0 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* This file uses ESP32 SDMMC peripheral to test SDIO Slave peripheral SD modes
*/
#include "unity.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/sdio_slave.h"
#include "soc/soc_caps.h"
#include "soc/sdio_slave_pins.h"
#include "test_dualboard_utils.h"
#include "../../sdio_common_test.h"
#define TEST_HEX_LOG_LEVEL ESP_LOG_DEBUG
#define TEST_SDIO_SLAVE_QUEUE_SIZE 20
static const char *TAG = "test_sdio";
/*---------------------------------------------------------------
Slave Init Settings
---------------------------------------------------------------*/
typedef struct {
int queued_cnt;
bool s_finished;
} s_test_slv_ctx_t;
static s_test_slv_ctx_t s_test_slv_ctx;
//callback to event 7, indicating test finish in these tests
static void s_event_cb(uint8_t event)
{
ESP_EARLY_LOGI(TAG, "event: %d", event);
sdio_slave_send_host_int(event);
if (event == 7) {
s_test_slv_ctx.s_finished = true;
}
}
static void wait_for_finish(s_test_slv_ctx_t *ctx)
{
while (!ctx->s_finished) {
vTaskDelay(10);
}
//wait for host to read the respond from slave
vTaskDelay(10);
}
static void s_slave_init(sdio_slave_sending_mode_t mode)
{
s_test_slv_ctx.s_finished = false;
s_test_slv_ctx.queued_cnt = 0;
sdio_slave_config_t slave_config = {
.sending_mode = mode,
.send_queue_size = TEST_SDIO_SLAVE_QUEUE_SIZE,
.recv_buffer_size = TEST_RX_BUFFER_SIZE,
.event_cb = s_event_cb,
};
TEST_ESP_OK(sdio_slave_initialize(&slave_config));
}
#include "esp_rom_sys.h"
/*---------------------------------------------------------------
Function Tests
---------------------------------------------------------------*/
/*---------------------------------------------------------------
SDMMC_SDIO: test interrupt
---------------------------------------------------------------*/
TEST_CASE("SDIO_Slave: test interrupt", "[sdio]")
{
s_slave_init(SDIO_SLAVE_SEND_STREAM);
TEST_ESP_OK(sdio_slave_start());
ESP_LOGI(TAG, "slave ready");
wait_for_finish(&s_test_slv_ctx);
sdio_slave_stop();
sdio_slave_deinit();
}
/*---------------------------------------------------------------
SDMMC_SDIO: test register
---------------------------------------------------------------*/
TEST_CASE("SDIO_Slave: test register", "[sdio]")
{
s_slave_init(SDIO_SLAVE_SEND_STREAM);
TEST_ESP_OK(sdio_slave_start());
ESP_LOGI(TAG, "slave ready");
wait_for_finish(&s_test_slv_ctx);
sdio_slave_stop();
sdio_slave_deinit();
}
/*---------------------------------------------------------------
SDMMC_SDIO: test reset
---------------------------------------------------------------*/
TEST_CASE("SDIO_Slave: test reset", "[sdio]")
{
s_slave_init(SDIO_SLAVE_SEND_PACKET);
TEST_ESP_OK(sdio_slave_start());
ESP_LOGI(TAG, "slave ready");
sdio_slave_stop();
TEST_ESP_OK(sdio_slave_reset());
TEST_ESP_OK(sdio_slave_start());
//tx
WORD_ALIGNED_ATTR uint8_t slave_tx_buffer[TEST_RESET_BUF_NUMS][TEST_RESET_DATA_LEN] = {};
for (int i = 0; i < TEST_RESET_BUF_NUMS; i++) {
test_fill_random_to_buffer(i, slave_tx_buffer[i], TEST_RESET_DATA_LEN);
TEST_ESP_OK(sdio_slave_send_queue(slave_tx_buffer[i], TEST_RESET_DATA_LEN, (void *)i, portMAX_DELAY));
}
//rx
sdio_slave_buf_handle_t buf_handle[TEST_RESET_BUF_NUMS] = {};
WORD_ALIGNED_ATTR uint8_t slave_rx_buffer[TEST_RESET_BUF_NUMS][TEST_RESET_DATA_LEN] = {};
for (int i = 0; i < TEST_RESET_BUF_NUMS; i++) {
buf_handle[i] = sdio_slave_recv_register_buf(slave_rx_buffer[i]);
TEST_ASSERT(buf_handle[i]);
TEST_ESP_OK(sdio_slave_recv_load_buf(buf_handle[i]));
}
for (int i = 0; i < TEST_RESET_BUF_NUMS; i++) {
void* arg;
TEST_ESP_OK(sdio_slave_send_get_finished(&arg, portMAX_DELAY));
TEST_ASSERT_EQUAL(i, arg);
}
WORD_ALIGNED_ATTR uint8_t host_tx_buffer[TEST_RESET_DATA_LEN] = {};
for (int i = 0; i < TEST_RESET_BUF_NUMS; i++) {
test_fill_random_to_buffer(i, host_tx_buffer, TEST_RESET_DATA_LEN);
uint8_t* addr;
size_t size;
sdio_slave_buf_handle_t recv_handle;
TEST_ESP_OK(sdio_slave_recv(&recv_handle, &addr, &size, portMAX_DELAY));
TEST_ASSERT_EQUAL(TEST_RESET_DATA_LEN, size);
TEST_ASSERT_EQUAL_HEX8_ARRAY(host_tx_buffer, addr, size);
}
wait_for_finish(&s_test_slv_ctx);
sdio_slave_stop();
sdio_slave_deinit();
}
/*---------------------------------------------------------------
Transaction Tests
---------------------------------------------------------------*/
#define TEST_SLAVE_TRANS_BUF_NUMS 10
/*---------------------------------------------------------------
From Host Tests
---------------------------------------------------------------*/
static void test_from_host(bool check_data)
{
//prepare buffer
test_prepare_buffer_pool(TEST_RX_BUFFER_SIZE * 4, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT | MALLOC_CAP_DMA);
uint8_t *slave_rx_buffer[TEST_SLAVE_TRANS_BUF_NUMS] = {};
for (int i = 0; i < TEST_SLAVE_TRANS_BUF_NUMS; i++) {
slave_rx_buffer[i] = (uint8_t *)heap_caps_calloc(1, TEST_RX_BUFFER_SIZE, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT | MALLOC_CAP_DMA);
TEST_ASSERT(slave_rx_buffer[i]);
}
for (int i = 0; i < TEST_TARNS_PARAM_NUMS; i++) {
//slave init
s_slave_init(SDIO_SLAVE_SEND_STREAM);
TEST_ESP_OK(sdio_slave_start());
ESP_LOGI(TAG, "slave ready");
//slave load rx buffer
sdio_slave_buf_handle_t buf_handle[TEST_SLAVE_TRANS_BUF_NUMS] = {};
for (int j = 0; j < TEST_SLAVE_TRANS_BUF_NUMS; j++) {
buf_handle[j] = sdio_slave_recv_register_buf(slave_rx_buffer[j]);
TEST_ASSERT(buf_handle[j]);
TEST_ESP_OK(sdio_slave_recv_load_buf(buf_handle[j]));
}
void *tx_buf_ptr = NULL;
for (int j = 0; j < TEST_TRANS_NUMS; j++) {
ESP_LOGD(TAG, "j: %d", j);
sdio_slave_buf_handle_t used_buf_handle = NULL;
uint8_t* buf = NULL;
size_t rcv_len = 0;
TEST_ESP_OK(sdio_slave_recv(&used_buf_handle, &buf, &rcv_len, portMAX_DELAY));
ESP_LOGD(TAG, "rcv_len: 0d%d", rcv_len);
ESP_LOG_BUFFER_HEX_LEVEL(TAG, buf, TEST_RX_BUFFER_SIZE, TEST_HEX_LOG_LEVEL);
if (check_data) {
test_get_buffer_from_pool(j, TEST_RX_BUFFER_SIZE, &tx_buf_ptr);
ESP_LOG_BUFFER_HEX_LEVEL("Expect data", tx_buf_ptr, TEST_RX_BUFFER_SIZE, TEST_HEX_LOG_LEVEL);
TEST_ASSERT_EQUAL_HEX8_ARRAY(tx_buf_ptr, buf, rcv_len);
}
TEST_ESP_OK(sdio_slave_recv_load_buf(used_buf_handle));
}
wait_for_finish(&s_test_slv_ctx);
sdio_slave_stop();
sdio_slave_deinit();
}
for (int i = 0; i < TEST_SLAVE_TRANS_BUF_NUMS; i++) {
free(slave_rx_buffer[i]);
}
test_destroy_buffer_pool();
}
TEST_CASE("SDIO_Slave: test from host", "[sdio]")
{
test_from_host(true);
}
TEST_CASE("SDIO_Slave: test from host (Performance)", "[sdio_speed]")
{
test_from_host(false);
}
/*---------------------------------------------------------------
To Host Tests
---------------------------------------------------------------*/
#define QUEUE_FULL() (s_test_slv_ctx.queued_cnt == TEST_SDIO_SLAVE_QUEUE_SIZE)
#define QUEUE_EMPTY() (s_test_slv_ctx.queued_cnt == 0)
static void test_to_host(void)
{
//prepare buffer
test_prepare_buffer_pool(TEST_RX_BUFFER_SIZE * 21, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT | MALLOC_CAP_DMA);
for (int i = 0; i < TEST_TARNS_PARAM_NUMS; i++) {
//slave init
s_slave_init(SDIO_SLAVE_SEND_STREAM);
TEST_ESP_OK(sdio_slave_start());
ESP_LOGI(TAG, "slave ready");
esp_err_t err = ESP_OK;
int offset = 0;
void *tx_buf_ptr = NULL;
for (int j = 0; j < TEST_TRANS_NUMS; j++) {
do {
void* arg;
//when the queue is full, do a blocking wait for 10ms, otherwise non-blocking
err = sdio_slave_send_get_finished(&arg, QUEUE_FULL()? 1: 0);
if (err == ESP_OK) {
s_test_slv_ctx.queued_cnt --;
continue;
}
TEST_ASSERT_EQUAL(ESP_ERR_TIMEOUT, err);
} while (QUEUE_FULL());
test_get_buffer_from_pool(offset, TEST_RX_BUFFER_SIZE, &tx_buf_ptr);
TEST_ESP_OK(sdio_slave_send_queue((uint8_t *)tx_buf_ptr, TEST_RX_BUFFER_SIZE, NULL, portMAX_DELAY));
s_test_slv_ctx.queued_cnt++;
offset += TEST_RX_BUFFER_SIZE;
}
while (!QUEUE_EMPTY()) {
void* arg;
TEST_ESP_OK(sdio_slave_send_get_finished(&arg, portMAX_DELAY));
s_test_slv_ctx.queued_cnt--;
}
wait_for_finish(&s_test_slv_ctx);
sdio_slave_stop();
sdio_slave_deinit();
}
test_destroy_buffer_pool();
}
TEST_CASE("SDIO_Slave: test to host", "[sdio]")
{
test_to_host();
}
TEST_CASE("SDIO_Slave: test to host (Performance)", "[sdio_speed]")
{
test_to_host();
}

View File

@@ -1,2 +0,0 @@
# don't delete.
# used for CI to compile a default config when 'sdkconfig.ci.xxxx' is exist

View File

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

View File

@@ -1,42 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
#define TEST_RX_BUFFER_SIZE 2048
/*---------------------------------------------------------------
Function Tests
---------------------------------------------------------------*/
/*---------------------------------------------------------------
SDMMC_SDIO: test reset
---------------------------------------------------------------*/
#define TEST_RESET_DATA_LEN 12
#define TEST_RESET_BUF_NUMS 10
/*---------------------------------------------------------------
Transaction Tests
---------------------------------------------------------------*/
#define TEST_TARNS_PARAM_NUMS 2
/*---------------------------------------------------------------
SDMMC_SDIO: test from host
---------------------------------------------------------------*/
#define TEST_TRANS_NUMS 10000
#ifdef __cplusplus
}
#endif