forked from espressif/esp-idf
test(uhci): Add tests for uhci
This commit is contained in:
@@ -32,5 +32,6 @@ components/esp_driver_uart/test_apps/uart_vfs:
|
||||
components/esp_driver_uart/test_apps/uhci:
|
||||
disable:
|
||||
- if: SOC_UHCI_SUPPORTED != 1
|
||||
- if: CONFIG_NAME == "psram" and SOC_SPIRAM_SUPPORTED != 1
|
||||
depends_components:
|
||||
- esp_driver_uart
|
||||
|
28
components/esp_driver_uart/test_apps/uhci/CMakeLists.txt
Normal file
28
components/esp_driver_uart/test_apps/uhci/CMakeLists.txt
Normal file
@@ -0,0 +1,28 @@
|
||||
# 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")
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(uhci_test)
|
||||
|
||||
if(CONFIG_COMPILER_DUMP_RTL_FILES)
|
||||
add_custom_target(check_test_app_sections ALL
|
||||
COMMAND ${PYTHON} $ENV{IDF_PATH}/tools/ci/check_callgraph.py
|
||||
--rtl-dirs ${CMAKE_BINARY_DIR}/esp-idf/esp_driver_uart/,${CMAKE_BINARY_DIR}/esp-idf/hal/
|
||||
--elf-file ${CMAKE_BINARY_DIR}/uhci_test.elf
|
||||
find-refs
|
||||
--from-sections=.iram0.text
|
||||
--to-sections=.flash.text,.flash.rodata
|
||||
--exit-code
|
||||
DEPENDS ${elf}
|
||||
)
|
||||
endif()
|
||||
|
||||
message(STATUS "Checking uhci registers are not read-write by half-word")
|
||||
include($ENV{IDF_PATH}/tools/ci/check_register_rw_half_word.cmake)
|
||||
check_register_rw_half_word(SOC_MODULES "uhci" "pcr" "hp_sys_clkrst" "lpperi" "lp_clkrst"
|
||||
HAL_MODULES "uhci")
|
2
components/esp_driver_uart/test_apps/uhci/README.md
Normal file
2
components/esp_driver_uart/test_apps/uhci/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
| Supported Targets | ESP32-C3 | ESP32-C6 | ESP32-P4 | ESP32-S3 |
|
||||
| ----------------- | -------- | -------- | -------- | -------- |
|
@@ -0,0 +1,8 @@
|
||||
# In order for the cases defined by `TEST_CASE` to be linked into the final elf,
|
||||
# the component can be registered as WHOLE_ARCHIVE
|
||||
idf_component_register(
|
||||
SRCS "test_app_main.c"
|
||||
"test_uhci.c"
|
||||
REQUIRES esp_driver_uart unity test_utils esp_psram
|
||||
WHOLE_ARCHIVE
|
||||
)
|
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "unity.h"
|
||||
#include "unity_test_runner.h"
|
||||
#include "unity_test_utils.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_newlib.h"
|
||||
|
||||
#define TEST_MEMORY_LEAK_THRESHOLD (500)
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
unity_utils_record_free_mem();
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
esp_reent_cleanup(); //clean up some of the newlib's lazy allocations
|
||||
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();
|
||||
}
|
294
components/esp_driver_uart/test_apps/uhci/main/test_uhci.c
Normal file
294
components/esp_driver_uart/test_apps/uhci/main/test_uhci.c
Normal file
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
#include "unity.h"
|
||||
#include "test_utils.h"
|
||||
#include "driver/uart.h"
|
||||
#include "driver/uhci.h"
|
||||
|
||||
#define DATA_LENGTH 1024
|
||||
#define EX_UART_NUM 1
|
||||
#define UART_TX_IO 2
|
||||
#define UART_RX_IO 3
|
||||
|
||||
TEST_CASE("UHCI driver memory leaking check", "[uhci]")
|
||||
{
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = 1 * 1000 * 1000,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.source_clk = UART_SCLK_DEFAULT,
|
||||
};
|
||||
|
||||
//UART parameter config
|
||||
TEST_ESP_OK(uart_param_config(EX_UART_NUM, &uart_config));
|
||||
TEST_ESP_OK(uart_set_pin(EX_UART_NUM, UART_TX_IO, UART_RX_IO, -1, -1));
|
||||
|
||||
uhci_controller_config_t uhci_cfg = {
|
||||
.uart_port = EX_UART_NUM,
|
||||
.tx_trans_queue_depth = 30,
|
||||
.max_receive_internal_mem = 10 * 1024,
|
||||
.max_transmit_size = 10 * 1024,
|
||||
.dma_burst_size = 32,
|
||||
.rx_eof_flags.idle_eof = 1,
|
||||
};
|
||||
|
||||
uhci_controller_handle_t uhci_ctrl;
|
||||
|
||||
int size = esp_get_free_heap_size();
|
||||
for (int i = 0; i < 5; i++) {
|
||||
TEST_ESP_OK(uhci_new_controller(&uhci_cfg, &uhci_ctrl));
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
TEST_ESP_OK(uhci_del_controller(uhci_ctrl));
|
||||
}
|
||||
|
||||
TEST_ASSERT_INT_WITHIN(300, size, esp_get_free_heap_size());
|
||||
}
|
||||
|
||||
TEST_CASE("UHCI controller install-uninstall test", "[i2c]")
|
||||
{
|
||||
uhci_controller_config_t uhci_cfg = {
|
||||
.uart_port = EX_UART_NUM,
|
||||
.tx_trans_queue_depth = 30,
|
||||
.max_receive_internal_mem = 10 * 1024,
|
||||
.max_transmit_size = 10 * 1024,
|
||||
.dma_burst_size = 32,
|
||||
.rx_eof_flags.idle_eof = 1,
|
||||
};
|
||||
|
||||
uhci_controller_handle_t uhci_ctrl;
|
||||
uhci_controller_handle_t uhci_ctrl2;
|
||||
|
||||
TEST_ESP_OK(uhci_new_controller(&uhci_cfg, &uhci_ctrl));
|
||||
|
||||
TEST_ESP_ERR(ESP_ERR_NOT_FOUND, uhci_new_controller(&uhci_cfg, &uhci_ctrl2));
|
||||
|
||||
TEST_ESP_OK(uhci_del_controller(uhci_ctrl));
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
UHCI_EVT_PARTIAL_DATA,
|
||||
UHCI_EVT_EOF,
|
||||
} uhci_event_t;
|
||||
|
||||
typedef struct {
|
||||
QueueHandle_t uhci_queue;
|
||||
size_t receive_size;
|
||||
uint8_t *p_receive_data;
|
||||
} uhci_context_t;
|
||||
|
||||
static void disp_buf(uint8_t *buf, int len)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < len; i++) {
|
||||
printf("%02x ", buf[i]);
|
||||
if ((i + 1) % 16 == 0) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
IRAM_ATTR static bool s_uhci_rx_event_cbs(uhci_controller_handle_t uhci_ctrl, const uhci_rx_event_data_t *edata, void *user_ctx)
|
||||
{
|
||||
uhci_context_t *ctx = (uhci_context_t *)user_ctx;
|
||||
BaseType_t xTaskWoken = 0;
|
||||
uhci_event_t evt = 0;
|
||||
if (edata->flags.totally_received) {
|
||||
evt = UHCI_EVT_EOF;
|
||||
ctx->receive_size += edata->recv_size;
|
||||
memcpy(ctx->p_receive_data, edata->data, edata->recv_size);
|
||||
} else {
|
||||
evt = UHCI_EVT_PARTIAL_DATA;
|
||||
ctx->receive_size += edata->recv_size;
|
||||
memcpy(ctx->p_receive_data, edata->data, edata->recv_size);
|
||||
ctx->p_receive_data += edata->recv_size;
|
||||
}
|
||||
|
||||
xQueueSendFromISR(ctx->uhci_queue, &evt, &xTaskWoken);
|
||||
return xTaskWoken;
|
||||
}
|
||||
|
||||
static void uhci_receive_test(void *arg)
|
||||
{
|
||||
uhci_controller_handle_t uhci_ctrl = ((uhci_controller_handle_t *)arg)[0];
|
||||
SemaphoreHandle_t exit_sema = ((SemaphoreHandle_t *)arg)[1];
|
||||
|
||||
uhci_context_t *ctx = calloc(1, sizeof(uhci_context_t));
|
||||
assert(ctx);
|
||||
ctx->uhci_queue = xQueueCreate(15, sizeof(uhci_event_t));
|
||||
assert(ctx->uhci_queue);
|
||||
|
||||
uint8_t *receive_data = heap_caps_calloc(1, DATA_LENGTH, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||
assert(receive_data);
|
||||
uint8_t *pdata = heap_caps_calloc(1, DATA_LENGTH / 4, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||
assert(pdata);
|
||||
ctx->p_receive_data = receive_data;
|
||||
|
||||
uhci_event_callbacks_t uhci_cbs = {
|
||||
.on_rx_trans_event = s_uhci_rx_event_cbs,
|
||||
};
|
||||
TEST_ESP_OK(uhci_register_event_callbacks(uhci_ctrl, &uhci_cbs, ctx));
|
||||
TEST_ESP_OK(uhci_receive(uhci_ctrl, pdata, DATA_LENGTH / 4));
|
||||
|
||||
uhci_event_t evt;
|
||||
while (1) {
|
||||
if (xQueueReceive(ctx->uhci_queue, &evt, portMAX_DELAY) == pdTRUE) {
|
||||
if (evt == UHCI_EVT_EOF) {
|
||||
disp_buf(receive_data, ctx->receive_size);
|
||||
for (int i = 0; i < DATA_LENGTH; i++) {
|
||||
TEST_ASSERT(receive_data[i] == (uint8_t)i);
|
||||
}
|
||||
printf("Received size: %d\n", ctx->receive_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vQueueDelete(ctx->uhci_queue);
|
||||
free(pdata);
|
||||
free(receive_data);
|
||||
free(ctx);
|
||||
xSemaphoreGive(exit_sema);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
TEST_CASE("UHCI write and receive", "[uhci]")
|
||||
{
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = 5 * 1000 * 1000,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.source_clk = UART_SCLK_XTAL,
|
||||
};
|
||||
TEST_ESP_OK(uart_param_config(EX_UART_NUM, &uart_config));
|
||||
// Connect TX and RX together for testing self send-receive
|
||||
TEST_ESP_OK(uart_set_pin(EX_UART_NUM, UART_TX_IO, UART_TX_IO, -1, -1));
|
||||
|
||||
uhci_controller_config_t uhci_cfg = {
|
||||
.uart_port = EX_UART_NUM,
|
||||
.tx_trans_queue_depth = 30,
|
||||
.max_receive_internal_mem = 10 * 1024,
|
||||
.max_transmit_size = 10 * 1024,
|
||||
.dma_burst_size = 32,
|
||||
.rx_eof_flags.idle_eof = 1,
|
||||
};
|
||||
|
||||
uhci_controller_handle_t uhci_ctrl;
|
||||
SemaphoreHandle_t exit_sema = xSemaphoreCreateBinary();
|
||||
TEST_ESP_OK(uhci_new_controller(&uhci_cfg, &uhci_ctrl));
|
||||
|
||||
void *args[] = { uhci_ctrl, exit_sema };
|
||||
xTaskCreate(uhci_receive_test, "uhci_receive_test", 4096 * 2, args, 5, NULL);
|
||||
|
||||
uint8_t data_wr[DATA_LENGTH];
|
||||
for (int i = 0; i < DATA_LENGTH; i++) {
|
||||
data_wr[i] = i;
|
||||
}
|
||||
TEST_ESP_OK(uhci_transmit(uhci_ctrl, data_wr, DATA_LENGTH));
|
||||
uhci_wait_all_tx_transaction_done(uhci_ctrl, portMAX_DELAY);
|
||||
xSemaphoreTake(exit_sema, portMAX_DELAY);
|
||||
vTaskDelay(2);
|
||||
TEST_ESP_OK(uhci_del_controller(uhci_ctrl));
|
||||
vSemaphoreDelete(exit_sema);
|
||||
}
|
||||
|
||||
#if CONFIG_SPIRAM
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
static void uhci_receive_test_in_psram(void *arg)
|
||||
{
|
||||
uhci_controller_handle_t uhci_ctrl = ((uhci_controller_handle_t *)arg)[0];
|
||||
SemaphoreHandle_t exit_sema = ((SemaphoreHandle_t *)arg)[1];
|
||||
|
||||
uhci_context_t *ctx = calloc(1, sizeof(uhci_context_t));
|
||||
assert(ctx);
|
||||
ctx->uhci_queue = xQueueCreate(15, sizeof(uhci_event_t));
|
||||
assert(ctx->uhci_queue);
|
||||
|
||||
uint8_t *receive_data = heap_caps_calloc(1, DATA_LENGTH, MALLOC_CAP_DMA | MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
assert(receive_data);
|
||||
uint8_t *pdata = heap_caps_calloc(1, DATA_LENGTH / 4, MALLOC_CAP_DMA | MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
assert(pdata);
|
||||
ctx->p_receive_data = receive_data;
|
||||
|
||||
uhci_event_callbacks_t uhci_cbs = {
|
||||
.on_rx_trans_event = s_uhci_rx_event_cbs,
|
||||
};
|
||||
TEST_ESP_OK(uhci_register_event_callbacks(uhci_ctrl, &uhci_cbs, ctx));
|
||||
TEST_ESP_OK(uhci_receive(uhci_ctrl, pdata, DATA_LENGTH / 4));
|
||||
|
||||
uhci_event_t evt;
|
||||
while (1) {
|
||||
if (xQueueReceive(ctx->uhci_queue, &evt, portMAX_DELAY) == pdTRUE) {
|
||||
if (evt == UHCI_EVT_EOF) {
|
||||
disp_buf(receive_data, ctx->receive_size);
|
||||
for (int i = 0; i < DATA_LENGTH; i++) {
|
||||
TEST_ASSERT(receive_data[i] == (uint8_t)i);
|
||||
}
|
||||
printf("Received size: %d\n", ctx->receive_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vQueueDelete(ctx->uhci_queue);
|
||||
free(pdata);
|
||||
free(receive_data);
|
||||
free(ctx);
|
||||
xSemaphoreGive(exit_sema);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
TEST_CASE("UHCI write and receive in psram", "[uhci]")
|
||||
{
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = 5 * 1000 * 1000,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.source_clk = UART_SCLK_XTAL,
|
||||
};
|
||||
TEST_ESP_OK(uart_param_config(EX_UART_NUM, &uart_config));
|
||||
// Connect TX and RX together for testing self send-receive
|
||||
TEST_ESP_OK(uart_set_pin(EX_UART_NUM, UART_TX_IO, UART_TX_IO, -1, -1));
|
||||
|
||||
uhci_controller_config_t uhci_cfg = {
|
||||
.uart_port = EX_UART_NUM,
|
||||
.tx_trans_queue_depth = 30,
|
||||
.max_receive_internal_mem = 10 * 1024,
|
||||
.max_transmit_size = 10 * 1024,
|
||||
.dma_burst_size = 32,
|
||||
.rx_eof_flags.idle_eof = 1,
|
||||
};
|
||||
|
||||
uhci_controller_handle_t uhci_ctrl;
|
||||
SemaphoreHandle_t exit_sema = xSemaphoreCreateBinary();
|
||||
TEST_ESP_OK(uhci_new_controller(&uhci_cfg, &uhci_ctrl));
|
||||
|
||||
void *args[] = { uhci_ctrl, exit_sema };
|
||||
xTaskCreate(uhci_receive_test_in_psram, "uhci_receive_test_in_psram", 4096 * 2, args, 5, NULL);
|
||||
|
||||
uint8_t *data_wr = heap_caps_calloc(1, DATA_LENGTH, MALLOC_CAP_DMA | MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
for (int i = 0; i < DATA_LENGTH; i++) {
|
||||
data_wr[i] = i;
|
||||
}
|
||||
TEST_ESP_OK(uhci_transmit(uhci_ctrl, data_wr, DATA_LENGTH));
|
||||
uhci_wait_all_tx_transaction_done(uhci_ctrl, portMAX_DELAY);
|
||||
xSemaphoreTake(exit_sema, portMAX_DELAY);
|
||||
vTaskDelay(2);
|
||||
free(data_wr);
|
||||
TEST_ESP_OK(uhci_del_controller(uhci_ctrl));
|
||||
vSemaphoreDelete(exit_sema);
|
||||
}
|
||||
#endif
|
||||
#endif // CONFIG_SPIRAM
|
20
components/esp_driver_uart/test_apps/uhci/pytest_uhci.py
Normal file
20
components/esp_driver_uart/test_apps/uhci/pytest_uhci.py
Normal file
@@ -0,0 +1,20 @@
|
||||
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
from pytest_embedded_idf.utils import idf_parametrize
|
||||
from pytest_embedded_idf.utils import soc_filtered_targets
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@pytest.mark.parametrize(
|
||||
'config',
|
||||
[
|
||||
'release',
|
||||
'cache_safe',
|
||||
],
|
||||
indirect=True,
|
||||
)
|
||||
@idf_parametrize('target', soc_filtered_targets('SOC_UHCI_SUPPORTED == 1'), indirect=['target'])
|
||||
def test_uhci(dut: Dut) -> None:
|
||||
dut.run_all_single_board_cases()
|
@@ -0,0 +1,11 @@
|
||||
CONFIG_COMPILER_DUMP_RTL_FILES=y
|
||||
CONFIG_UHCI_ISR_CACHE_SAFE=y
|
||||
CONFIG_GPIO_CTRL_FUNC_IN_IRAM=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_NONE=y
|
||||
# place non-ISR FreeRTOS functions in Flash
|
||||
CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y
|
||||
# silent the error check, as the error string are stored in rodata, causing RTL check failure
|
||||
CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
|
||||
CONFIG_HAL_ASSERTION_SILENT=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE=y
|
@@ -0,0 +1 @@
|
||||
CONFIG_SPIRAM=y
|
@@ -0,0 +1,6 @@
|
||||
CONFIG_PM_ENABLE=y
|
||||
CONFIG_PM_DFS_INIT_AUTO=y
|
||||
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
|
@@ -0,0 +1,2 @@
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
CONFIG_ESP_TASK_WDT_EN=n
|
Reference in New Issue
Block a user