diff --git a/components/usb/test_apps/hcd/main/Kconfig.projbuild b/components/usb/test_apps/hcd/main/Kconfig.projbuild new file mode 100644 index 0000000000..c8517efc32 --- /dev/null +++ b/components/usb/test_apps/hcd/main/Kconfig.projbuild @@ -0,0 +1,26 @@ +menu "USB HCD Test" + + orsource "$IDF_PATH/examples/common_components/env_caps/$IDF_TARGET/Kconfig.env_caps" + + config USB_HCD_TEST_OTG_DRVVBUS_ENABLE + depends on IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 + bool "Enable driving VBUS by an internal DRVVBUS signal from USB-OTG peripheral" + default n + help + USB-OTG peripheral features a DRVVBUS signal, which controls the VBUS voltage. The DRVVBUS signal can be + either internally connected to a PHY (if a PHY supports it), in such a case the PHY would be controlling + the VBUS voltage by itself. Or the DRVVBUS can be handled by an external logic (a transistor switch). + Our PHY does not support the DRVVBUS signal, thus we must use an external logic to control the VBUS + voltage. The DRVVBUS signal is controlled via HCD_PORT_CMD_POWER_OFF and HCD_PORT_CMD_POWER_ON + + config USB_HCD_TEST_OTG_DRVVBUS_GPIO + depends on USB_HCD_TEST_OTG_DRVVBUS_ENABLE + int "Connect a GPIO to the internal DRVVBUS signal" + range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX + default 1 + help + GPIO number, that will be internally connected to the DRVVBUS signal. + USB Host CI target runners feature an external power switch controlled by this GPIO, to control the VBUS + voltage of USB devices during test. + +endmenu diff --git a/components/usb/test_apps/hcd/main/test_hcd_common.c b/components/usb/test_apps/hcd/main/test_hcd_common.c index 3b30beac50..dbc2896028 100644 --- a/components/usb/test_apps/hcd/main/test_hcd_common.c +++ b/components/usb/test_apps/hcd/main/test_hcd_common.c @@ -21,12 +21,18 @@ #include "test_hcd_common.h" #include "mock_msc.h" #include "unity.h" +#include "sdkconfig.h" #define PORT_NUM 1 #define EVENT_QUEUE_LEN 5 #define ENUM_ADDR 1 // Device address to use for tests that enumerate the device #define ENUM_CONFIG 1 // Device configuration number to use for tests that enumerate the device +#ifdef CONFIG_USB_HCD_TEST_OTG_DRVVBUS_ENABLE +#define OTG_DRVVBUS_ENABLE +#define OTG_DRVVBUS_GPIO CONFIG_USB_HCD_TEST_OTG_DRVVBUS_GPIO +#endif + typedef struct { hcd_port_handle_t port_hdl; hcd_port_event_t port_event; @@ -159,6 +165,24 @@ hcd_port_handle_t test_hcd_setup(void) .ext_io_conf = NULL, .otg_io_conf = NULL, }; + +#ifdef OTG_DRVVBUS_ENABLE + const usb_phy_otg_io_conf_t otg_io_conf = { + .iddig_io_num = -1, + .avalid_io_num = -1, + .vbusvalid_io_num = -1, + .idpullup_io_num = -1, + .dppulldown_io_num = -1, + .dmpulldown_io_num = -1, + .drvvbus_io_num = OTG_DRVVBUS_GPIO, + .bvalid_io_num = -1, + .sessend_io_num = -1, + .chrgvbus_io_num = -1, + .dischrgvbus_io_num = -1 + }; + phy_config.otg_io_conf = &otg_io_conf; +#endif // OTG_DRVVBUS_ENABLE + TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, usb_new_phy(&phy_config, &phy_hdl), "Failed to init USB PHY"); // Create a queue for port callback to queue up port events QueueHandle_t port_evt_queue = xQueueCreate(EVENT_QUEUE_LEN, sizeof(port_event_msg_t)); diff --git a/components/usb/test_apps/hcd/pytest_usb_hcd.py b/components/usb/test_apps/hcd/pytest_usb_hcd.py index 7df14e1779..4bb9ea888c 100644 --- a/components/usb/test_apps/hcd/pytest_usb_hcd.py +++ b/components/usb/test_apps/hcd/pytest_usb_hcd.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: CC0-1.0 import pytest from pytest_embedded import Dut @@ -11,6 +11,6 @@ from pytest_embedded import Dut @pytest.mark.usb_host_flash_disk def test_usb_hcd(dut: Dut) -> None: if (dut.target == 'esp32s3'): - dut.run_all_single_board_cases(group='full_speed') + dut.run_all_single_board_cases(group='full_speed', reset=True) else: - dut.run_all_single_board_cases(group='high_speed') + dut.run_all_single_board_cases(group='high_speed', reset=True) diff --git a/components/usb/test_apps/hcd/sdkconfig.ci b/components/usb/test_apps/hcd/sdkconfig.ci new file mode 100644 index 0000000000..e71059485e --- /dev/null +++ b/components/usb/test_apps/hcd/sdkconfig.ci @@ -0,0 +1,5 @@ +# Use external power switch to control USB device's power +# switch is controlled by GPIO 21 + +CONFIG_USB_HCD_TEST_OTG_DRVVBUS_ENABLE=y +CONFIG_USB_HCD_TEST_OTG_DRVVBUS_GPIO=21 diff --git a/components/usb/test_apps/usb_host/main/Kconfig.projbuild b/components/usb/test_apps/usb_host/main/Kconfig.projbuild index 8706cdd15d..5fb07e5e22 100644 --- a/components/usb/test_apps/usb_host/main/Kconfig.projbuild +++ b/components/usb/test_apps/usb_host/main/Kconfig.projbuild @@ -1,5 +1,7 @@ menu "USB Host Library Test" + orsource "$IDF_PATH/examples/common_components/env_caps/$IDF_TARGET/Kconfig.env_caps" + config USB_HOST_TEST_CHECK_MANU_STR bool "Check manufacturer string descriptor" default y @@ -21,4 +23,25 @@ menu "USB Host Library Test" USB Host tests that check string descriptors will check the serial string descriptor of the connected device. + config USB_HOST_TEST_OTG_DRVVBUS_ENABLE + depends on IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 + bool "Enable driving VBUS by an internal DRVVBUS signal from USB-OTG peripheral" + default n + help + USB-OTG peripheral features a DRVVBUS signal, which controls the VBUS voltage. The DRVVBUS signal can be + either internally connected to a PHY (if a PHY supports it), in such a case the PHY would be controlling + the VBUS voltage by itself. Or the DRVVBUS can be handled by an external logic (a transistor switch). + Our PHY does not support the DRVVBUS signal, thus we must use an external logic to control the VBUS + voltage. The DRVVBUS signal is controlled via HCD_PORT_CMD_POWER_OFF and HCD_PORT_CMD_POWER_ON + + config USB_HOST_TEST_OTG_DRVVBUS_GPIO + depends on USB_HOST_TEST_OTG_DRVVBUS_ENABLE + int "Connect a GPIO to the internal DRVVBUS signal" + range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX + default 1 + help + GPIO number, that will be internally connected to the DRVVBUS signal. + USB Host CI target runners feature an external power switch controlled by this GPIO, to control the VBUS + voltage of USB devices during test. + endmenu diff --git a/components/usb/test_apps/usb_host/main/test_app_main.c b/components/usb/test_apps/usb_host/main/test_app_main.c index 5a790f9831..6fd91e8a57 100644 --- a/components/usb/test_apps/usb_host/main/test_app_main.c +++ b/components/usb/test_apps/usb_host/main/test_app_main.c @@ -10,15 +10,18 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "dev_msc.h" +#include "test_usb_host_common.h" #include "usb/usb_host.h" void setUp(void) { unity_utils_record_free_mem(); dev_msc_init(); + // Install PHY separately + test_usb_host_setup_phy(); // Install USB Host usb_host_config_t host_config = { - .skip_phy_setup = false, + .skip_phy_setup = true, .root_port_unpowered = false, .intr_flags = ESP_INTR_FLAG_LEVEL1, }; @@ -33,6 +36,7 @@ void tearDown(void) // Clean up USB Host printf("USB Host uninstall\n"); ESP_ERROR_CHECK(usb_host_uninstall()); + test_usb_host_delete_phy(); // Short delay to allow task to be cleaned up after client uninstall vTaskDelay(10); unity_utils_evaluate_leaks(); diff --git a/components/usb/test_apps/usb_host/main/test_usb_host_common.c b/components/usb/test_apps/usb_host/main/test_usb_host_common.c new file mode 100644 index 0000000000..1f2daa4e88 --- /dev/null +++ b/components/usb/test_apps/usb_host/main/test_usb_host_common.c @@ -0,0 +1,65 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "esp_intr_alloc.h" +#include "esp_err.h" +#include "usb/usb_types_ch9.h" +#include "esp_private/usb_phy.h" +#include "test_usb_host_common.h" +#include "unity.h" +#include "sdkconfig.h" + +#ifdef CONFIG_USB_HOST_TEST_OTG_DRVVBUS_ENABLE +#define OTG_DRVVBUS_ENABLE +#define OTG_DRVVBUS_GPIO CONFIG_USB_HOST_TEST_OTG_DRVVBUS_GPIO +#endif + +static usb_phy_handle_t phy_hdl = NULL; + +void test_usb_host_setup_phy(void) +{ + // Deinitialize PHY from previous failed test + if (phy_hdl != NULL) { + TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, usb_del_phy(phy_hdl), "Failed to delete PHY"); + phy_hdl = NULL; + } + + // Initialize the internal USB PHY to connect to the USB OTG peripheral + usb_phy_config_t phy_config = { + .controller = USB_PHY_CTRL_OTG, + .target = USB_PHY_TARGET_INT, + .otg_mode = USB_OTG_MODE_HOST, + .otg_speed = USB_PHY_SPEED_UNDEFINED, // In Host mode, the speed is determined by the connected device + .ext_io_conf = NULL, + .otg_io_conf = NULL, + }; + +#ifdef OTG_DRVVBUS_ENABLE + const usb_phy_otg_io_conf_t otg_io_conf = { + .iddig_io_num = -1, + .avalid_io_num = -1, + .vbusvalid_io_num = -1, + .idpullup_io_num = -1, + .dppulldown_io_num = -1, + .dmpulldown_io_num = -1, + .drvvbus_io_num = OTG_DRVVBUS_GPIO, + .bvalid_io_num = -1, + .sessend_io_num = -1, + .chrgvbus_io_num = -1, + .dischrgvbus_io_num = -1 + }; + phy_config.otg_io_conf = &otg_io_conf; +#endif // OTG_DRVVBUS_ENABLE + + TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, usb_new_phy(&phy_config, &phy_hdl), "Failed to init USB PHY"); +} + +void test_usb_host_delete_phy(void) +{ + TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, usb_del_phy(phy_hdl), "Failed to delete PHY"); + phy_hdl = NULL; +} diff --git a/components/usb/test_apps/usb_host/main/test_usb_host_common.h b/components/usb/test_apps/usb_host/main/test_usb_host_common.h new file mode 100644 index 0000000000..eaf15f998f --- /dev/null +++ b/components/usb/test_apps/usb_host/main/test_usb_host_common.h @@ -0,0 +1,15 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief Install PHY separately from the usb_host_install() + */ +void test_usb_host_setup_phy(void); + +/** + * @brief Uninstall PHY + */ +void test_usb_host_delete_phy(void); diff --git a/components/usb/test_apps/usb_host/pytest_usb_host.py b/components/usb/test_apps/usb_host/pytest_usb_host.py index 309ba6e510..95dd043de6 100644 --- a/components/usb/test_apps/usb_host/pytest_usb_host.py +++ b/components/usb/test_apps/usb_host/pytest_usb_host.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: CC0-1.0 import pytest from pytest_embedded import Dut @@ -11,6 +11,6 @@ from pytest_embedded import Dut @pytest.mark.usb_host_flash_disk def test_usb_host(dut: Dut) -> None: if (dut.target == 'esp32s3'): - dut.run_all_single_board_cases(group='full_speed') + dut.run_all_single_board_cases(group='full_speed', reset=True) else: - dut.run_all_single_board_cases(group='high_speed') + dut.run_all_single_board_cases(group='high_speed', reset=True) diff --git a/components/usb/test_apps/usb_host/sdkconfig.ci b/components/usb/test_apps/usb_host/sdkconfig.ci new file mode 100644 index 0000000000..65657e9bd7 --- /dev/null +++ b/components/usb/test_apps/usb_host/sdkconfig.ci @@ -0,0 +1,5 @@ +# Use external power switch to control USB device's power +# switch is controlled by GPIO 21 + +CONFIG_USB_HOST_TEST_OTG_DRVVBUS_ENABLE=y +CONFIG_USB_HOST_TEST_OTG_DRVVBUS_GPIO=21