mirror of
https://github.com/espressif/esp-idf.git
synced 2025-07-29 18:27:20 +02:00
feat(usb/host): Add option to choose peripheral for USB host library
Starting with ESP32-P4 we can have targets that have more than 1 USB-OTG peripheral. This commit adds an option to choose which peripherals will be used by USB Host lib. Internally, we will still have only 1 Root HUB but with multiple Root ports.
This commit is contained in:
@ -106,9 +106,9 @@ extern const usb_dwc_info_t usb_dwc_info;
|
||||
/* ------------------------------- Deprecated ------------------------------- */
|
||||
/* Todo: Remove in ESP-IDF v6.0 (IDF-9052) */
|
||||
#include <stdint.h>
|
||||
#include "soc/periph_defs.h"
|
||||
|
||||
#if SOC_USB_OTG_SUPPORTED
|
||||
#include "soc/periph_defs.h"
|
||||
|
||||
/*
|
||||
Stores a bunch of USB-peripheral data.
|
||||
|
@ -43,7 +43,7 @@
|
||||
#define CTRL_EP_MAX_MPS_LS 8 // Largest Maximum Packet Size for Low Speed control endpoints
|
||||
#define CTRL_EP_MAX_MPS_HSFS 64 // Largest Maximum Packet Size for High & Full Speed control endpoints
|
||||
|
||||
#define NUM_PORTS 1 // The controller only has one port.
|
||||
#define NUM_PORTS SOC_USB_OTG_PERIPH_NUM // Each peripheral is a root port
|
||||
|
||||
// ----------------------- Configs -------------------------
|
||||
|
||||
@ -108,7 +108,6 @@ DEFINE_CRIT_SECTION_LOCK_STATIC(hcd_lock);
|
||||
* For other SOCs this is no-operation
|
||||
*/
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
#define ALIGN_UP_BY(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
#define CACHE_SYNC_FRAME_LIST(frame_list) cache_sync_frame_list(frame_list)
|
||||
#define CACHE_SYNC_XFER_DESCRIPTOR_LIST_M2C(buffer) cache_sync_xfer_descriptor_list(buffer, true)
|
||||
#define CACHE_SYNC_XFER_DESCRIPTOR_LIST_C2M(buffer) cache_sync_xfer_descriptor_list(buffer, false)
|
||||
@ -257,15 +256,15 @@ struct port_obj {
|
||||
void *callback_arg;
|
||||
SemaphoreHandle_t port_mux;
|
||||
void *context;
|
||||
intr_handle_t isr_hdl; // Interrupt handle for this root port (USB-OTG peripheral)
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Object representing the HCD
|
||||
*/
|
||||
typedef struct {
|
||||
// Ports (Hardware only has one)
|
||||
port_t *port_obj;
|
||||
intr_handle_t isr_hdl;
|
||||
// Ports: Each peripheral is a root port
|
||||
port_t *port_obj[NUM_PORTS];
|
||||
} hcd_obj_t;
|
||||
|
||||
static hcd_obj_t *s_hcd_obj = NULL; // Note: "s_" is for the static pointer
|
||||
@ -1041,52 +1040,66 @@ esp_err_t hcd_install(const hcd_config_t *config)
|
||||
HCD_CHECK_FROM_CRIT(s_hcd_obj == NULL, ESP_ERR_INVALID_STATE);
|
||||
HCD_EXIT_CRITICAL();
|
||||
|
||||
// Check if peripheral_map does not have bits set outside of valid range. Valid bits are BIT0 - BIT(NUM_PORTS - 1)
|
||||
HCD_CHECK((config->peripheral_map != 0) && (config->peripheral_map < BIT(NUM_PORTS)), ESP_ERR_INVALID_ARG);
|
||||
|
||||
esp_err_t err_ret;
|
||||
|
||||
// Allocate memory for the driver object
|
||||
hcd_obj_t *p_hcd_obj_dmy = calloc(1, sizeof(hcd_obj_t));
|
||||
if (p_hcd_obj_dmy == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
// Allocate each port object (the hardware currently only has one port)
|
||||
p_hcd_obj_dmy->port_obj = port_obj_alloc();
|
||||
if (p_hcd_obj_dmy->port_obj == NULL) {
|
||||
err_ret = ESP_ERR_NO_MEM;
|
||||
goto port_alloc_err;
|
||||
}
|
||||
// Allocate interrupt
|
||||
err_ret = esp_intr_alloc(usb_dwc_info.controllers[0].irq,
|
||||
config->intr_flags | ESP_INTR_FLAG_INTRDISABLED, // The interrupt must be disabled until the port is initialized
|
||||
intr_hdlr_main,
|
||||
(void *)p_hcd_obj_dmy->port_obj,
|
||||
&p_hcd_obj_dmy->isr_hdl);
|
||||
if (err_ret != ESP_OK) {
|
||||
ESP_LOGE(HCD_DWC_TAG, "Interrupt alloc error: %s", esp_err_to_name(err_ret));
|
||||
goto intr_alloc_err;
|
||||
}
|
||||
// Apply custom FIFO config if provided, otherwise mark as default (all zeros)
|
||||
memset(&p_hcd_obj_dmy->port_obj->fifo_config, 0, sizeof(p_hcd_obj_dmy->port_obj->fifo_config));
|
||||
if (config->fifo_config != NULL) {
|
||||
// Convert and validate user-provided config
|
||||
err_ret = convert_fifo_config_to_hal_config(config->fifo_config, &p_hcd_obj_dmy->port_obj->fifo_config);
|
||||
if (err_ret != ESP_OK) {
|
||||
goto assign_err;
|
||||
|
||||
// Allocate each port object
|
||||
for (int i = 0; i < NUM_PORTS; i++) {
|
||||
if (BIT(i) & config->peripheral_map) {
|
||||
p_hcd_obj_dmy->port_obj[i] = port_obj_alloc();
|
||||
if (p_hcd_obj_dmy->port_obj[i] == NULL) {
|
||||
err_ret = ESP_ERR_NO_MEM;
|
||||
goto clean_up;
|
||||
}
|
||||
// Allocate interrupt
|
||||
const int irq_index = usb_dwc_info.controllers[i].irq;
|
||||
err_ret = esp_intr_alloc(irq_index,
|
||||
config->intr_flags | ESP_INTR_FLAG_INTRDISABLED, // The interrupt must be disabled until the port is initialized
|
||||
intr_hdlr_main,
|
||||
(void *)p_hcd_obj_dmy->port_obj[i],
|
||||
&p_hcd_obj_dmy->port_obj[i]->isr_hdl);
|
||||
if (err_ret != ESP_OK) {
|
||||
ESP_LOGE(HCD_DWC_TAG, "Interrupt alloc error: %s", esp_err_to_name(err_ret));
|
||||
goto clean_up;
|
||||
}
|
||||
|
||||
// Apply custom FIFO config if provided
|
||||
if (config->fifo_config != NULL) {
|
||||
// Convert and validate user-provided config
|
||||
err_ret = convert_fifo_config_to_hal_config(config->fifo_config, &p_hcd_obj_dmy->port_obj[i]->fifo_config);
|
||||
if (err_ret != ESP_OK) {
|
||||
goto clean_up;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HCD_ENTER_CRITICAL();
|
||||
if (s_hcd_obj != NULL) {
|
||||
HCD_EXIT_CRITICAL();
|
||||
err_ret = ESP_ERR_INVALID_STATE;
|
||||
goto assign_err;
|
||||
goto clean_up;
|
||||
}
|
||||
s_hcd_obj = p_hcd_obj_dmy;
|
||||
HCD_EXIT_CRITICAL();
|
||||
return ESP_OK;
|
||||
|
||||
assign_err:
|
||||
esp_intr_free(p_hcd_obj_dmy->isr_hdl);
|
||||
intr_alloc_err:
|
||||
port_obj_free(p_hcd_obj_dmy->port_obj);
|
||||
port_alloc_err:
|
||||
clean_up:
|
||||
// Free resources
|
||||
for (int i = 0; i < NUM_PORTS; i++) {
|
||||
if (p_hcd_obj_dmy->port_obj[i]) {
|
||||
esp_intr_free(p_hcd_obj_dmy->port_obj[i]->isr_hdl);
|
||||
port_obj_free(p_hcd_obj_dmy->port_obj[i]);
|
||||
}
|
||||
}
|
||||
free(p_hcd_obj_dmy);
|
||||
return err_ret;
|
||||
}
|
||||
@ -1094,8 +1107,14 @@ port_alloc_err:
|
||||
esp_err_t hcd_uninstall(void)
|
||||
{
|
||||
HCD_ENTER_CRITICAL();
|
||||
// Check that all ports have been disabled (there's only one port)
|
||||
if (s_hcd_obj == NULL || s_hcd_obj->port_obj->initialized) {
|
||||
// Check that all ports have been disabled
|
||||
bool all_ports_disabled = true;
|
||||
for (int i = 0; i < NUM_PORTS; i++) {
|
||||
if (s_hcd_obj->port_obj[i]) {
|
||||
all_ports_disabled = all_ports_disabled && !(s_hcd_obj->port_obj[i]->initialized);
|
||||
}
|
||||
}
|
||||
if (s_hcd_obj == NULL || !all_ports_disabled) {
|
||||
HCD_EXIT_CRITICAL();
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
@ -1104,8 +1123,12 @@ esp_err_t hcd_uninstall(void)
|
||||
HCD_EXIT_CRITICAL();
|
||||
|
||||
// Free resources
|
||||
port_obj_free(p_hcd_obj_dmy->port_obj);
|
||||
esp_intr_free(p_hcd_obj_dmy->isr_hdl);
|
||||
for (int i = 0; i < NUM_PORTS; i++) {
|
||||
if (p_hcd_obj_dmy->port_obj[i]) {
|
||||
esp_intr_free(p_hcd_obj_dmy->port_obj[i]->isr_hdl);
|
||||
port_obj_free(p_hcd_obj_dmy->port_obj[i]);
|
||||
}
|
||||
}
|
||||
free(p_hcd_obj_dmy);
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -1366,13 +1389,13 @@ exit:
|
||||
|
||||
esp_err_t hcd_port_init(int port_number, const hcd_port_config_t *port_config, hcd_port_handle_t *port_hdl)
|
||||
{
|
||||
HCD_CHECK(port_number > 0 && port_config != NULL && port_hdl != NULL, ESP_ERR_INVALID_ARG);
|
||||
HCD_CHECK(port_number <= NUM_PORTS, ESP_ERR_NOT_FOUND);
|
||||
HCD_CHECK(port_number >= 0 && port_config != NULL && port_hdl != NULL, ESP_ERR_INVALID_ARG);
|
||||
HCD_CHECK(port_number < NUM_PORTS, ESP_ERR_NOT_FOUND);
|
||||
|
||||
HCD_ENTER_CRITICAL();
|
||||
HCD_CHECK_FROM_CRIT(s_hcd_obj != NULL && !s_hcd_obj->port_obj->initialized, ESP_ERR_INVALID_STATE);
|
||||
HCD_CHECK_FROM_CRIT(s_hcd_obj != NULL && !s_hcd_obj->port_obj[port_number]->initialized, ESP_ERR_INVALID_STATE);
|
||||
// Port object memory and resources (such as the mutex) already be allocated. Just need to initialize necessary fields only
|
||||
port_t *port_obj = s_hcd_obj->port_obj;
|
||||
port_t *port_obj = s_hcd_obj->port_obj[port_number];
|
||||
TAILQ_INIT(&port_obj->pipes_idle_tailq);
|
||||
TAILQ_INIT(&port_obj->pipes_active_tailq);
|
||||
port_obj->state = HCD_PORT_STATE_NOT_POWERED;
|
||||
@ -1380,18 +1403,22 @@ esp_err_t hcd_port_init(int port_number, const hcd_port_config_t *port_config, h
|
||||
port_obj->callback = port_config->callback;
|
||||
port_obj->callback_arg = port_config->callback_arg;
|
||||
port_obj->context = port_config->context;
|
||||
usb_dwc_hal_init(port_obj->hal, 0);
|
||||
|
||||
// USB-HAL's size is dependent on its configuration, namely on number of channels in the configuration
|
||||
// We must first initialize the HAL, to get the number of channels and then allocate memory for the channels
|
||||
usb_dwc_hal_init(port_obj->hal, port_number);
|
||||
port_obj->hal->channels.hdls = calloc(port_obj->hal->constant_config.chan_num_total, sizeof(usb_dwc_hal_chan_t*));
|
||||
HCD_CHECK_FROM_CRIT(port_obj->hal->channels.hdls != NULL, ESP_ERR_NO_MEM);
|
||||
|
||||
port_obj->initialized = true;
|
||||
// Clear the frame list. We set the frame list register and enable periodic scheduling after a successful reset
|
||||
// Clear the frame list. We will set the frame list register and enable periodic scheduling after a successful reset
|
||||
memset(port_obj->frame_list, 0, FRAME_LIST_LEN * sizeof(uint32_t));
|
||||
// If FIFO config is zeroed -> calculate from bias
|
||||
if (_is_fifo_config_by_bias(&port_obj->fifo_config)) {
|
||||
// Calculate default FIFO sizes based on Kconfig bias settings
|
||||
_calculate_fifo_from_bias(port_obj, port_obj->hal);
|
||||
}
|
||||
esp_intr_enable(s_hcd_obj->isr_hdl);
|
||||
esp_intr_enable(port_obj->isr_hdl);
|
||||
*port_hdl = (hcd_port_handle_t)port_obj;
|
||||
HCD_EXIT_CRITICAL();
|
||||
ESP_LOGD(HCD_DWC_TAG, "FIFO config lines: RX=%u, PTX=%u, NPTX=%u",
|
||||
@ -1413,7 +1440,7 @@ esp_err_t hcd_port_deinit(hcd_port_handle_t port_hdl)
|
||||
&& port->task_waiting_port_notif == NULL,
|
||||
ESP_ERR_INVALID_STATE);
|
||||
port->initialized = false;
|
||||
esp_intr_disable(s_hcd_obj->isr_hdl);
|
||||
esp_intr_disable(port->isr_hdl);
|
||||
free(port->hal->channels.hdls);
|
||||
usb_dwc_hal_deinit(port->hal);
|
||||
HCD_EXIT_CRITICAL();
|
||||
@ -1529,7 +1556,7 @@ esp_err_t hcd_port_recover(hcd_port_handle_t port_hdl)
|
||||
ESP_ERR_INVALID_STATE);
|
||||
|
||||
// We are about to do a soft reset on the peripheral. Disable the peripheral throughout
|
||||
esp_intr_disable(s_hcd_obj->isr_hdl);
|
||||
esp_intr_disable(port->isr_hdl);
|
||||
usb_dwc_hal_core_soft_reset(port->hal);
|
||||
port->state = HCD_PORT_STATE_NOT_POWERED;
|
||||
port->last_event = HCD_PORT_EVENT_NONE;
|
||||
@ -1537,7 +1564,7 @@ esp_err_t hcd_port_recover(hcd_port_handle_t port_hdl)
|
||||
|
||||
// Clear the frame list. We set the frame list register and enable periodic scheduling after a successful reset
|
||||
memset(port->frame_list, 0, FRAME_LIST_LEN * sizeof(uint32_t));
|
||||
esp_intr_enable(s_hcd_obj->isr_hdl);
|
||||
esp_intr_enable(port->isr_hdl);
|
||||
HCD_EXIT_CRITICAL();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <stdio.h>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include "esp_bit_defs.h"
|
||||
#include "usb_host.h" // Real implementation of usb_host.h
|
||||
|
||||
// Test all the mocked headers defined for this mock
|
||||
@ -52,6 +53,7 @@ SCENARIO("USB Host install")
|
||||
.intr_flags = 1,
|
||||
.enum_filter_cb = nullptr,
|
||||
.fifo_settings_custom = {},
|
||||
.peripheral_map = BIT0,
|
||||
};
|
||||
|
||||
// USB host config is valid, USB Host driver is not installed from previous test case
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <sys/queue.h>
|
||||
#include "esp_err.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_bit_defs.h"
|
||||
#include "esp_private/critical_section.h"
|
||||
#include "esp_log.h"
|
||||
#include "usb_private.h"
|
||||
@ -27,8 +28,6 @@ Implementation of the HUB driver that only supports the Root Hub with a single p
|
||||
implement the bare minimum to control the root HCD port.
|
||||
*/
|
||||
|
||||
#define HUB_ROOT_PORT_NUM 1 // HCD only supports one port
|
||||
|
||||
#ifdef CONFIG_USB_HOST_HW_BUFFER_BIAS_IN
|
||||
#define HUB_ROOT_HCD_PORT_FIFO_BIAS HCD_PORT_FIFO_BIAS_RX
|
||||
#elif CONFIG_USB_HOST_HW_BUFFER_BIAS_PERIODIC_OUT
|
||||
@ -60,7 +59,6 @@ typedef enum {
|
||||
ROOT_PORT_STATE_POWERED, /**< Root port is powered, device is not connected */
|
||||
ROOT_PORT_STATE_DISABLED, /**< A device is connected but is disabled (i.e., not reset, no SOFs are sent) */
|
||||
ROOT_PORT_STATE_ENABLED, /**< A device is connected, port has been reset, SOFs are sent */
|
||||
ROOT_PORT_STATE_RECOVERY, /**< Root port encountered an error and needs to be recovered */
|
||||
} root_port_state_t;
|
||||
|
||||
/**
|
||||
@ -566,7 +564,14 @@ esp_err_t hub_install(hub_config_t *hub_config, void **client_ret)
|
||||
.context = NULL,
|
||||
};
|
||||
hcd_port_handle_t root_port_hdl;
|
||||
ret = hcd_port_init(HUB_ROOT_PORT_NUM, &port_config, &root_port_hdl);
|
||||
|
||||
// Right now we support only one root port, can be extended in future
|
||||
int root_port_index = 0;
|
||||
if (hub_config->port_map & BIT1) {
|
||||
root_port_index = 1;
|
||||
}
|
||||
|
||||
ret = hcd_port_init(root_port_index, &port_config, &root_port_hdl);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(HUB_DRIVER_TAG, "HCD Port init error: %s", esp_err_to_name(ret));
|
||||
goto err;
|
||||
|
@ -121,6 +121,13 @@ typedef struct {
|
||||
} fifo_settings_custom; /**< Optional custom FIFO configuration (advanced use).
|
||||
RX and NPTX must be > 0. If all fields are zero,
|
||||
a default configuration will be selected based on Kconfig bias. */
|
||||
unsigned peripheral_map; /**< Selects the USB peripheral(s) to use.
|
||||
- On targets with multiple USB peripherals, this field can be used to specify which ones to enable.
|
||||
- Set to 0 to use the default peripheral.
|
||||
- On High-Speed capable targets, the default is the High-Speed peripheral.
|
||||
- On Full-Speed only targets, the default is the Full-Speed peripheral.
|
||||
- Example: peripheral_map = BIT1; installs USB host on peripheral 1.
|
||||
- The mapping of bits to specific peripherals is defined in the USB_DWC_LL_GET_HW() macro. */
|
||||
} usb_host_config_t;
|
||||
|
||||
/**
|
||||
|
@ -154,9 +154,10 @@ typedef struct {
|
||||
* @brief HCD configuration structure
|
||||
*/
|
||||
typedef struct {
|
||||
int intr_flags; /**< Interrupt flags for HCD interrupt */
|
||||
const hcd_fifo_settings_t *fifo_config;/**< Optional pointer to custom FIFO config.
|
||||
If NULL, default configuration is used. */
|
||||
int intr_flags; /**< Interrupt flags for HCD interrupt */
|
||||
const hcd_fifo_settings_t *fifo_config; /**< Optional pointer to custom FIFO config.
|
||||
If NULL, default configuration is used. */
|
||||
unsigned peripheral_map; /**< Bit map of USB-OTG peripherals that belong to HCD. Set to zero to use default */
|
||||
} hcd_config_t;
|
||||
|
||||
/**
|
||||
@ -166,6 +167,7 @@ typedef struct {
|
||||
hcd_port_callback_t callback; /**< HCD port event callback */
|
||||
void *callback_arg; /**< User argument for HCD port callback */
|
||||
void *context; /**< Context variable used to associate the port with upper layer object */
|
||||
unsigned peripheral_idx; /**< Index of USB peripheral this port belongs to. Index numbers are defined in USB_DWC_LL_GET_HW */
|
||||
} hcd_port_config_t;
|
||||
|
||||
/**
|
||||
@ -225,8 +227,6 @@ esp_err_t hcd_uninstall(void);
|
||||
*
|
||||
* After a port is initialized, it will be put into the HCD_PORT_STATE_NOT_POWERED state.
|
||||
*
|
||||
* @note The host controller only has one port, thus the only valid port_number is 1
|
||||
*
|
||||
* @param[in] port_number Port number
|
||||
* @param[in] port_config Port configuration
|
||||
* @param[out] port_hdl Port handle
|
||||
|
@ -60,6 +60,7 @@ typedef void (*hub_event_cb_t)(hub_event_data_t *event_data, void *arg);
|
||||
* @brief Hub driver configuration
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned port_map; /**< Bitmap of root ports to enable */
|
||||
usb_proc_req_cb_t proc_req_cb; /**< Processing request callback */
|
||||
void *proc_req_cb_arg; /**< Processing request callback argument */
|
||||
hub_event_cb_t event_cb; /**< Hub event callback */
|
||||
|
@ -25,9 +25,24 @@
|
||||
|
||||
// ----------------------------------------------------- Macros --------------------------------------------------------
|
||||
|
||||
#define TEST_P4_OTG11 0 // Change this to 1 to test on OTG1.1 peripheral - only for ESP32-P4
|
||||
|
||||
// --------------------- Constants -------------------------
|
||||
|
||||
#define PORT_NUM 1
|
||||
#if TEST_P4_OTG11
|
||||
#define TEST_PHY USB_PHY_TARGET_INT
|
||||
#define TEST_PERIPHERAL_MAP BIT1
|
||||
#define TEST_PORT_NUM 1
|
||||
#else
|
||||
#if CONFIG_IDF_TARGET_ESP32P4
|
||||
#define TEST_PHY USB_PHY_TARGET_UTMI
|
||||
#else
|
||||
#define TEST_PHY USB_PHY_TARGET_INT
|
||||
#endif
|
||||
#define TEST_PERIPHERAL_MAP BIT0
|
||||
#define TEST_PORT_NUM 0
|
||||
#endif // TEST_P4_OTG11
|
||||
|
||||
#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
|
||||
@ -149,7 +164,7 @@ int test_hcd_get_num_pipe_events(hcd_pipe_handle_t pipe_hdl)
|
||||
|
||||
hcd_port_handle_t test_hcd_setup(void)
|
||||
{
|
||||
test_setup_usb_phy();
|
||||
test_setup_usb_phy(TEST_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));
|
||||
@ -157,6 +172,7 @@ hcd_port_handle_t test_hcd_setup(void)
|
||||
// Install HCD
|
||||
hcd_config_t hcd_config = {
|
||||
.intr_flags = ESP_INTR_FLAG_LEVEL1,
|
||||
.peripheral_map = TEST_PERIPHERAL_MAP,
|
||||
};
|
||||
TEST_ASSERT_EQUAL(ESP_OK, hcd_install(&hcd_config));
|
||||
// Initialize a port
|
||||
@ -166,7 +182,7 @@ hcd_port_handle_t test_hcd_setup(void)
|
||||
.context = (void *)port_evt_queue,
|
||||
};
|
||||
hcd_port_handle_t port_hdl;
|
||||
TEST_ASSERT_EQUAL(ESP_OK, hcd_port_init(PORT_NUM, &port_config, &port_hdl));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, hcd_port_init(TEST_PORT_NUM, &port_config, &port_hdl));
|
||||
TEST_ASSERT_NOT_NULL(port_hdl);
|
||||
return port_hdl;
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
static usb_phy_handle_t phy_hdl = NULL;
|
||||
|
||||
void test_setup_usb_phy(void)
|
||||
void test_setup_usb_phy(usb_phy_target_t phy_target)
|
||||
{
|
||||
// Deinitialize PHY from previous failed test
|
||||
if (phy_hdl != NULL) {
|
||||
@ -31,11 +31,7 @@ void test_setup_usb_phy(void)
|
||||
// Initialize the internal USB PHY to connect to the USB OTG peripheral
|
||||
usb_phy_config_t phy_config = {
|
||||
.controller = USB_PHY_CTRL_OTG,
|
||||
#if CONFIG_IDF_TARGET_ESP32P4 // ESP32-P4 has 2 USB-DWC peripherals, each with its dedicated PHY. We support HS+UTMI only ATM.
|
||||
.target = USB_PHY_TARGET_UTMI,
|
||||
#else
|
||||
.target = USB_PHY_TARGET_INT,
|
||||
#endif
|
||||
.target = phy_target,
|
||||
.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,
|
||||
|
@ -4,10 +4,15 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "hal/usb_phy_types.h"
|
||||
|
||||
/**
|
||||
* @brief Install USB PHY separately from the usb_host_install()
|
||||
*
|
||||
* @param[in] phy_target USB PHY target
|
||||
*/
|
||||
void test_setup_usb_phy(void);
|
||||
void test_setup_usb_phy(usb_phy_target_t phy_target);
|
||||
|
||||
/**
|
||||
* @brief Uninstall PHY
|
||||
|
@ -13,17 +13,36 @@
|
||||
#include "phy_common.h"
|
||||
#include "usb/usb_host.h"
|
||||
|
||||
// ----------------------------------------------------- Macros --------------------------------------------------------
|
||||
|
||||
#define TEST_P4_OTG11 0 // Change this to 1 to test on OTG1.1 peripheral - only for ESP32-P4
|
||||
|
||||
// --------------------- Constants -------------------------
|
||||
|
||||
#if TEST_P4_OTG11
|
||||
#define TEST_PHY USB_PHY_TARGET_INT
|
||||
#define TEST_PERIPHERAL_MAP BIT1
|
||||
#else
|
||||
#if CONFIG_IDF_TARGET_ESP32P4
|
||||
#define TEST_PHY USB_PHY_TARGET_UTMI
|
||||
#else
|
||||
#define TEST_PHY USB_PHY_TARGET_INT
|
||||
#endif
|
||||
#define TEST_PERIPHERAL_MAP BIT0
|
||||
#endif // TEST_P4_OTG11
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
unity_utils_record_free_mem();
|
||||
dev_msc_init();
|
||||
// Install PHY separately
|
||||
test_setup_usb_phy();
|
||||
test_setup_usb_phy(TEST_PHY);
|
||||
// Install USB Host
|
||||
usb_host_config_t host_config = {
|
||||
.skip_phy_setup = true,
|
||||
.root_port_unpowered = false,
|
||||
.intr_flags = ESP_INTR_FLAG_LEVEL1,
|
||||
.peripheral_map = TEST_PERIPHERAL_MAP,
|
||||
};
|
||||
ESP_ERROR_CHECK(usb_host_install(&host_config));
|
||||
printf("USB Host installed\n");
|
||||
|
@ -17,9 +17,11 @@ Warning: The USB Host Library API is still a beta version and may be subject to
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_private/critical_section.h"
|
||||
#include "soc/usb_dwc_periph.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_bit_defs.h"
|
||||
#include "hub.h"
|
||||
#include "enum.h"
|
||||
#include "usbh.h"
|
||||
@ -464,16 +466,26 @@ esp_err_t usb_host_install(const usb_host_config_t *config)
|
||||
- Hub
|
||||
*/
|
||||
|
||||
// For backward compatibility accept 0 too
|
||||
const unsigned peripheral_map = config->peripheral_map == 0 ? BIT0 : config->peripheral_map;
|
||||
|
||||
// Install USB PHY (if necessary). USB PHY driver will also enable the underlying Host Controller
|
||||
if (!config->skip_phy_setup) {
|
||||
bool init_utmi_phy = false; // Default value for Linux simulation
|
||||
|
||||
#if SOC_USB_OTG_SUPPORTED // In case we run on a real target, select the PHY from usb_dwc_info description structure
|
||||
// Right now we support only one peripheral, can be extended in future
|
||||
int peripheral_index = 0;
|
||||
if (peripheral_map & BIT1) {
|
||||
peripheral_index = 1;
|
||||
}
|
||||
init_utmi_phy = (usb_dwc_info.controllers[peripheral_index].supported_phys == USB_PHY_INST_UTMI_0);
|
||||
#endif // SOC_USB_OTG_SUPPORTED
|
||||
|
||||
// Host Library defaults to internal PHY
|
||||
usb_phy_config_t phy_config = {
|
||||
.controller = USB_PHY_CTRL_OTG,
|
||||
#if CONFIG_IDF_TARGET_ESP32P4 // ESP32-P4 has 2 USB-DWC peripherals, each with its dedicated PHY. We support HS+UTMI only ATM.
|
||||
.target = USB_PHY_TARGET_UTMI,
|
||||
#else
|
||||
.target = USB_PHY_TARGET_INT,
|
||||
#endif
|
||||
.target = init_utmi_phy ? USB_PHY_TARGET_UTMI : 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,
|
||||
@ -491,6 +503,7 @@ esp_err_t usb_host_install(const usb_host_config_t *config)
|
||||
hcd_fifo_settings_t user_fifo_config;
|
||||
hcd_config_t hcd_config = {
|
||||
.intr_flags = config->intr_flags,
|
||||
.peripheral_map = peripheral_map,
|
||||
.fifo_config = NULL, // Default: use bias strategy from Kconfig
|
||||
};
|
||||
|
||||
@ -545,6 +558,7 @@ esp_err_t usb_host_install(const usb_host_config_t *config)
|
||||
|
||||
// Install Hub
|
||||
hub_config_t hub_config = {
|
||||
.port_map = peripheral_map, // Each USB-OTG peripheral maps to a root port
|
||||
.proc_req_cb = proc_req_callback,
|
||||
.proc_req_cb_arg = NULL,
|
||||
.event_cb = hub_event_callback,
|
||||
|
@ -33,6 +33,7 @@ The Host Library has the following features:
|
||||
:esp32p4: - Supports High Speed (HS), Full Speed (FS) and Low Speed (LS) Devices.
|
||||
- Supports all four transfer types: Control, Bulk, Interrupt, and Isochronous.
|
||||
:esp32p4: - Supports High-Bandwidth Isochronous endpoints.
|
||||
:esp32p4: - {IDF_TARGET_NAME} includes two USB 2.0 OTG peripherals: one High-Speed and one Full-Speed. Both support USB Host functionality; however, due to a current software limitation, only one can operate as a USB Host at a time. Support for dual USB Host operation is planned for a future update.
|
||||
- Allows multiple class drivers to run simultaneously, i.e., multiple clients of the Host Library.
|
||||
- A single device can be used by multiple clients simultaneously, e.g., composite devices.
|
||||
- The Host Library itself and the underlying Host Stack does not internally instantiate any OS tasks. The number of tasks is entirely controlled by how the Host Library interface is used. However, a general rule of thumb regarding the number of tasks is ``(the number of host class drivers running + 1)``.
|
||||
@ -46,7 +47,6 @@ Currently, the Host Library and the underlying Host Stack has the following limi
|
||||
- Only supports Asynchronous transfers.
|
||||
- Only supports using one configuration. Changing to other configurations after enumeration is not supported yet.
|
||||
- Transfer timeouts are not supported yet.
|
||||
:esp32p4: - {IDF_TARGET_NAME} contains two USB-OTG peripherals USB 2.0 OTG High-Speed and USB 2.0 OTG Full-Speed. Only the High-Speed instance is supported now.
|
||||
- The External Hub Driver: Remote Wakeup feature is not supported (External Hubs are active, even if there are no devices inserted).
|
||||
- The External Hub Driver: Doesn't handle error cases (overcurrent handling, errors during initialization etc. are not implemented yet).
|
||||
- The External Hub Driver: No Interface selection. The Driver uses the first available Interface with Hub Class code (09h).
|
||||
|
@ -113,8 +113,10 @@ static void usb_host_lib_task(void *arg)
|
||||
# ifdef ENABLE_ENUM_FILTER_CALLBACK
|
||||
.enum_filter_cb = set_config_cb,
|
||||
# endif // ENABLE_ENUM_FILTER_CALLBACK
|
||||
.peripheral_map = BIT0,
|
||||
};
|
||||
ESP_ERROR_CHECK(usb_host_install(&host_config));
|
||||
ESP_LOGI(TAG, "USB Host installed with peripheral map 0x%x", host_config.peripheral_map);
|
||||
|
||||
//Signalize the app_main, the USB host library has been installed
|
||||
xTaskNotifyGive(arg);
|
||||
|
Reference in New Issue
Block a user