mirror of
https://github.com/espressif/esp-idf.git
synced 2025-07-29 18:27:20 +02:00
Merge branch 'feat/usb-explicit-fifo-config' into 'master'
feat(usb/hal): Add HAL API to configure custom FIFO layout Closes IDF-9042 See merge request espressif/esp-idf!38404
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -29,15 +29,6 @@ extern "C" {
|
||||
|
||||
// ----------------------- Configs -------------------------
|
||||
|
||||
/**
|
||||
* @brief Possible FIFO biases
|
||||
*/
|
||||
typedef enum {
|
||||
USB_HAL_FIFO_BIAS_DEFAULT, /**< Default (balanced) FIFO sizes */
|
||||
USB_HAL_FIFO_BIAS_RX, /**< Bigger RX FIFO for IN transfers */
|
||||
USB_HAL_FIFO_BIAS_PTX, /**< Bigger periodic TX FIFO for ISOC OUT transfers */
|
||||
} usb_hal_fifo_bias_t;
|
||||
|
||||
/**
|
||||
* @brief MPS limits based on FIFO configuration
|
||||
*
|
||||
@ -261,20 +252,35 @@ void usb_dwc_hal_deinit(usb_dwc_hal_context_t *hal);
|
||||
void usb_dwc_hal_core_soft_reset(usb_dwc_hal_context_t *hal);
|
||||
|
||||
/**
|
||||
* @brief Set FIFO bias
|
||||
* @brief Check if FIFO configuration is valid
|
||||
*
|
||||
* This function will set the sizes of each of the FIFOs (RX FIFO, Non-periodic TX FIFO, Periodic TX FIFO) and must be
|
||||
* called at least once before allocating the channel. Based on the type of endpoints (and the endpoints' MPS), there
|
||||
* may be situations where this function may need to be called again to resize the FIFOs. If resizing FIFOs dynamically,
|
||||
* it is the user's responsibility to ensure there are no active channels when this function is called.
|
||||
* This function checks that the sum of FIFO sizes does not exceed available space.
|
||||
* It does not modify hardware state and is safe to call from HAL or upper layers.
|
||||
*
|
||||
* @note After a port reset, the FIFO size registers will reset to their default values, so this function must be called
|
||||
* again post reset.
|
||||
*
|
||||
* @param[in] hal Context of the HAL layer
|
||||
* @param[in] fifo_bias FIFO bias configuration
|
||||
* @param[in] hal Pointer to HAL context (must be initialized)
|
||||
* @param[in] config Pointer to FIFO config to validate
|
||||
* @return true if config is valid, false otherwise
|
||||
*/
|
||||
void usb_dwc_hal_set_fifo_bias(usb_dwc_hal_context_t *hal, const usb_hal_fifo_bias_t fifo_bias);
|
||||
bool usb_dwc_hal_fifo_config_is_valid(const usb_dwc_hal_context_t *hal, const usb_dwc_hal_fifo_config_t *config);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the FIFO sizes of the USB-DWC core
|
||||
*
|
||||
* This function programs the FIFO sizing registers (RX FIFO, Non-Periodic TX FIFO,
|
||||
* and Periodic TX FIFO) based on the provided configuration. It must be called
|
||||
* during USB initialization, before any channels are allocated or transfers started.
|
||||
*
|
||||
* The sum of all FIFO sizes must not exceed the hardware-defined limit
|
||||
* (see HWCFG3.DfifoDepth and EPINFO_CTL).
|
||||
*
|
||||
* @note This function must be called exactly once during initialization and after
|
||||
* each USB port reset. It is typically used internally by the USB Host stack.
|
||||
*
|
||||
* @param[inout] hal Pointer to the HAL context
|
||||
* @param[in] config Pointer to the FIFO configuration to apply (must be valid)
|
||||
*/
|
||||
void usb_dwc_hal_set_fifo_config(usb_dwc_hal_context_t *hal, const usb_dwc_hal_fifo_config_t *config);
|
||||
|
||||
/**
|
||||
* @brief Get MPS limits
|
||||
|
@ -185,64 +185,53 @@ void usb_dwc_hal_core_soft_reset(usb_dwc_hal_context_t *hal)
|
||||
}
|
||||
}
|
||||
|
||||
void usb_dwc_hal_set_fifo_bias(usb_dwc_hal_context_t *hal, const usb_hal_fifo_bias_t fifo_bias)
|
||||
bool usb_dwc_hal_fifo_config_is_valid(const usb_dwc_hal_context_t *hal, const usb_dwc_hal_fifo_config_t *config)
|
||||
{
|
||||
HAL_ASSERT(hal->channels.hdls);
|
||||
const uint16_t fifo_size_lines = hal->constant_config.fifo_size;
|
||||
/*
|
||||
* Recommended FIFO sizes (see 2.1.2.4 for programming guide)
|
||||
*
|
||||
* RXFIFO: ((LPS/4) * 2) + 2
|
||||
* NPTXFIFO: (LPS/4) * 2
|
||||
* PTXFIFO: (LPS/4) * 2
|
||||
*
|
||||
* Recommended sizes fit 2 packets of each type. For S2 and S3 we can't fit even one MPS ISOC packet (1023 FS and 1024 HS).
|
||||
* So the calculations below are compromises between the available FIFO size and optimal performance.
|
||||
*/
|
||||
|
||||
// Information for maintainers: this calculation is here for backward compatibility
|
||||
// It should be removed when we allow HAL users to configure the FIFO sizes IDF-9042
|
||||
const int otg_dfifo_depth = hal->constant_config.hsphy_type ? 1024 : 256;
|
||||
|
||||
usb_dwc_hal_fifo_config_t fifo_config;
|
||||
switch (fifo_bias) {
|
||||
// Define minimum viable (fits at least 1 MPS) FIFO sizes for non-biased FIFO types
|
||||
// Allocate the remaining size to the biased FIFO type
|
||||
case USB_HAL_FIFO_BIAS_DEFAULT:
|
||||
fifo_config.nptx_fifo_lines = otg_dfifo_depth / 4;
|
||||
fifo_config.ptx_fifo_lines = otg_dfifo_depth / 8;
|
||||
fifo_config.rx_fifo_lines = fifo_size_lines - fifo_config.ptx_fifo_lines - fifo_config.nptx_fifo_lines;
|
||||
break;
|
||||
case USB_HAL_FIFO_BIAS_RX:
|
||||
fifo_config.nptx_fifo_lines = otg_dfifo_depth / 16;
|
||||
fifo_config.ptx_fifo_lines = otg_dfifo_depth / 8;
|
||||
fifo_config.rx_fifo_lines = fifo_size_lines - fifo_config.ptx_fifo_lines - fifo_config.nptx_fifo_lines;
|
||||
break;
|
||||
case USB_HAL_FIFO_BIAS_PTX:
|
||||
fifo_config.rx_fifo_lines = otg_dfifo_depth / 8 + 2; // 2 extra lines are allocated for status information. See USB-OTG Programming Guide, chapter 2.1.2.1
|
||||
fifo_config.nptx_fifo_lines = otg_dfifo_depth / 16;
|
||||
fifo_config.ptx_fifo_lines = fifo_size_lines - fifo_config.nptx_fifo_lines - fifo_config.rx_fifo_lines;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
if (!hal || !config) {
|
||||
return false;
|
||||
}
|
||||
uint32_t used_lines = config->rx_fifo_lines + config->nptx_fifo_lines + config->ptx_fifo_lines;
|
||||
return (used_lines <= hal->constant_config.fifo_size);
|
||||
}
|
||||
|
||||
HAL_ASSERT((fifo_config.rx_fifo_lines + fifo_config.nptx_fifo_lines + fifo_config.ptx_fifo_lines) <= fifo_size_lines);
|
||||
//Check that none of the channels are active
|
||||
|
||||
void usb_dwc_hal_set_fifo_config(usb_dwc_hal_context_t *hal, const usb_dwc_hal_fifo_config_t *config)
|
||||
{
|
||||
// Check internal HAL state
|
||||
HAL_ASSERT(hal != NULL);
|
||||
HAL_ASSERT(hal->channels.hdls != NULL);
|
||||
|
||||
// Validate provided config
|
||||
HAL_ASSERT(config != NULL);
|
||||
|
||||
// Check if configuration exceeds available FIFO memory
|
||||
HAL_ASSERT(usb_dwc_hal_fifo_config_is_valid(hal, config));
|
||||
|
||||
// Ensure no active channels (must only be called before USB install completes)
|
||||
for (int i = 0; i < hal->constant_config.chan_num_total; i++) {
|
||||
if (hal->channels.hdls[i] != NULL) {
|
||||
HAL_ASSERT(!hal->channels.hdls[i]->flags.active);
|
||||
}
|
||||
}
|
||||
//Set the new FIFO lengths
|
||||
usb_dwc_ll_grxfsiz_set_fifo_size(hal->dev, fifo_config.rx_fifo_lines);
|
||||
usb_dwc_ll_gnptxfsiz_set_fifo_size(hal->dev, fifo_config.rx_fifo_lines, fifo_config.nptx_fifo_lines);
|
||||
usb_dwc_ll_hptxfsiz_set_ptx_fifo_size(hal->dev, fifo_config.rx_fifo_lines + fifo_config.nptx_fifo_lines, fifo_config.ptx_fifo_lines);
|
||||
//Flush the FIFOs
|
||||
|
||||
// Program FIFO size registers
|
||||
usb_dwc_ll_grxfsiz_set_fifo_size(hal->dev, config->rx_fifo_lines);// Set RX FIFO size (GRXFSIZ)
|
||||
// Set Non-Periodic TX FIFO (GNPTXFSIZ)
|
||||
// Offset = RX FIFO lines
|
||||
usb_dwc_ll_gnptxfsiz_set_fifo_size(hal->dev, config->rx_fifo_lines, config->nptx_fifo_lines);
|
||||
// Set Periodic TX FIFO (HPTXFSIZ)
|
||||
// Offset = RX + NPTX
|
||||
usb_dwc_ll_hptxfsiz_set_ptx_fifo_size(hal->dev,
|
||||
config->rx_fifo_lines + config->nptx_fifo_lines,
|
||||
config->ptx_fifo_lines);
|
||||
|
||||
// Flush all FIFOs
|
||||
usb_dwc_ll_grstctl_flush_nptx_fifo(hal->dev);
|
||||
usb_dwc_ll_grstctl_flush_ptx_fifo(hal->dev);
|
||||
usb_dwc_ll_grstctl_flush_rx_fifo(hal->dev);
|
||||
hal->fifo_config = fifo_config; // Implicit struct copy
|
||||
|
||||
// Save configuration to HAL context
|
||||
hal->fifo_config = *config;
|
||||
hal->flags.fifo_sizes_set = 1;
|
||||
}
|
||||
|
||||
|
@ -250,8 +250,8 @@ struct port_obj {
|
||||
uint32_t val;
|
||||
} flags;
|
||||
bool initialized;
|
||||
// FIFO biasing related
|
||||
usb_hal_fifo_bias_t fifo_bias; // Bias is saved so it can be reconfigured upon reset
|
||||
// FIFO related
|
||||
usb_dwc_hal_fifo_config_t fifo_config; // FIFO config to be applied at HAL level
|
||||
// Port callback and context
|
||||
hcd_port_callback_t callback;
|
||||
void *callback_arg;
|
||||
@ -554,6 +554,23 @@ static bool _port_check_all_pipes_halted(port_t *port);
|
||||
*/
|
||||
static bool _port_debounce(port_t *port);
|
||||
|
||||
/**
|
||||
* @brief Convert user-provided FIFO configuration to HAL format
|
||||
*
|
||||
* This function validates and converts a user-defined FIFO configuration
|
||||
* (provided via `hcd_config_t.fifo_config`) into the format expected by the HAL.
|
||||
* It ensures that both RX FIFO and Non-Periodic TX FIFO sizes are non-zero.
|
||||
*
|
||||
* @param[in] src Pointer to user-defined FIFO settings (HCD format)
|
||||
* @param[out] dst Pointer to HAL-compatible FIFO configuration structure
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Conversion successful and values copied
|
||||
* - ESP_ERR_INVALID_SIZE: Either RX FIFO or Non-Periodic TX FIFO is zero
|
||||
*/
|
||||
|
||||
static esp_err_t convert_fifo_config_to_hal_config(const hcd_fifo_settings_t *src, usb_dwc_hal_fifo_config_t *dst);
|
||||
|
||||
/**
|
||||
* @brief Power ON the port
|
||||
*
|
||||
@ -744,16 +761,6 @@ static usb_speed_t get_usb_port_speed(usb_dwc_speed_t priv)
|
||||
}
|
||||
}
|
||||
|
||||
static usb_hal_fifo_bias_t get_hal_fifo_bias(hcd_port_fifo_bias_t public)
|
||||
{
|
||||
switch (public) {
|
||||
case HCD_PORT_FIFO_BIAS_BALANCED: return USB_HAL_FIFO_BIAS_DEFAULT;
|
||||
case HCD_PORT_FIFO_BIAS_RX: return USB_HAL_FIFO_BIAS_RX;
|
||||
case HCD_PORT_FIFO_BIAS_PTX: return USB_HAL_FIFO_BIAS_PTX;
|
||||
default: abort();
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------- Interrupt Handlers --------------------
|
||||
|
||||
/**
|
||||
@ -954,6 +961,46 @@ static void intr_hdlr_main(void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------- FIFO Config -------------------------
|
||||
|
||||
/**
|
||||
* @brief Calculate default FIFO configuration based on bias preference
|
||||
*
|
||||
* This function calculates the FIFO configuration (RX, non-periodic TX, and periodic TX)
|
||||
* according to the selected bias mode from Kconfig:
|
||||
*
|
||||
* - CONFIG_USB_HOST_HW_BUFFER_BIAS_IN: Prioritize RX FIFO space, useful for IN-heavy traffic.
|
||||
* - CONFIG_USB_HOST_HW_BUFFER_BIAS_PERIODIC_OUT: Prioritize periodic TX FIFO, suitable for periodic OUT transfers.
|
||||
* - USB_HOST_HW_BUFFER_BIAS_BALANCED: Balanced configuration between RX and both TX FIFOs.
|
||||
*
|
||||
* @param[inout] port Pointer to the port object whose fifo_config will be filled
|
||||
* @param[in] hal Pointer to an initialized HAL context providing hardware FIFO limits
|
||||
*/
|
||||
static void _calculate_fifo_from_bias(port_t *port, const usb_dwc_hal_context_t *hal)
|
||||
{
|
||||
const int otg_dfifo_depth = hal->constant_config.hsphy_type ? 1024 : 256;
|
||||
const uint16_t fifo_size_lines = hal->constant_config.fifo_size;
|
||||
|
||||
#if CONFIG_USB_HOST_HW_BUFFER_BIAS_IN
|
||||
// Prioritize RX FIFO (best for IN-heavy workloads)
|
||||
port->fifo_config.nptx_fifo_lines = otg_dfifo_depth / 16;
|
||||
port->fifo_config.ptx_fifo_lines = otg_dfifo_depth / 8;
|
||||
port->fifo_config.rx_fifo_lines = fifo_size_lines - port->fifo_config.ptx_fifo_lines - port->fifo_config.nptx_fifo_lines;
|
||||
|
||||
#elif CONFIG_USB_HOST_HW_BUFFER_BIAS_PERIODIC_OUT
|
||||
// Prioritize periodic TX FIFO (useful for high throughput periodic endpoints)
|
||||
port->fifo_config.rx_fifo_lines = otg_dfifo_depth / 8 + 2; // 2 extra lines are allocated for status information. See USB-OTG Programming Guide, chapter 2.1.2.1
|
||||
port->fifo_config.nptx_fifo_lines = otg_dfifo_depth / 16;
|
||||
port->fifo_config.ptx_fifo_lines = fifo_size_lines - port->fifo_config.nptx_fifo_lines - port->fifo_config.rx_fifo_lines;
|
||||
|
||||
#else // USB_HOST_HW_BUFFER_BIAS_BALANCED
|
||||
// Balanced configuration (default)
|
||||
port->fifo_config.nptx_fifo_lines = otg_dfifo_depth / 4;
|
||||
port->fifo_config.ptx_fifo_lines = otg_dfifo_depth / 8;
|
||||
port->fifo_config.rx_fifo_lines = fifo_size_lines - port->fifo_config.ptx_fifo_lines - port->fifo_config.nptx_fifo_lines;
|
||||
#endif
|
||||
}
|
||||
|
||||
// --------------------------------------------- Host Controller Driver ------------------------------------------------
|
||||
|
||||
static port_t *port_obj_alloc(void)
|
||||
@ -1018,6 +1065,15 @@ esp_err_t hcd_install(const hcd_config_t *config)
|
||||
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;
|
||||
}
|
||||
}
|
||||
HCD_ENTER_CRITICAL();
|
||||
if (s_hcd_obj != NULL) {
|
||||
HCD_EXIT_CRITICAL();
|
||||
@ -1100,6 +1156,34 @@ static bool _port_debounce(port_t *port)
|
||||
return is_connected;
|
||||
}
|
||||
|
||||
static esp_err_t convert_fifo_config_to_hal_config(const hcd_fifo_settings_t *src, usb_dwc_hal_fifo_config_t *dst)
|
||||
{
|
||||
// Check at least RX and NPTX are non-zero
|
||||
if (src->rx_fifo_lines == 0 || src->nptx_fifo_lines == 0) {
|
||||
ESP_LOGE(HCD_DWC_TAG, "RX and Non-Periodic TX FIFO must be > 0");
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
// Assign valid values
|
||||
dst->rx_fifo_lines = src->rx_fifo_lines;
|
||||
dst->nptx_fifo_lines = src->nptx_fifo_lines;
|
||||
dst->ptx_fifo_lines = src->ptx_fifo_lines; // OK even if zero
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if the FIFO config is marked to use bias-based default values.
|
||||
*
|
||||
* If all FIFO line sizes are zero, the configuration is considered uninitialized,
|
||||
* and default values will be calculated based on bias settings.
|
||||
*/
|
||||
static inline bool _is_fifo_config_by_bias(const usb_dwc_hal_fifo_config_t *cfg)
|
||||
{
|
||||
return (cfg->rx_fifo_lines == 0 &&
|
||||
cfg->nptx_fifo_lines == 0 &&
|
||||
cfg->ptx_fifo_lines == 0);
|
||||
}
|
||||
|
||||
// ---------------------- Commands -------------------------
|
||||
|
||||
static esp_err_t _port_cmd_power_on(port_t *port)
|
||||
@ -1177,8 +1261,16 @@ static esp_err_t _port_cmd_reset(port_t *port)
|
||||
goto bailout;
|
||||
}
|
||||
|
||||
// Reinitialize port registers.
|
||||
usb_dwc_hal_set_fifo_bias(port->hal, port->fifo_bias); // Set FIFO biases
|
||||
// Reinitialize port registers
|
||||
if (!usb_dwc_hal_fifo_config_is_valid(port->hal, &port->fifo_config)) {
|
||||
HCD_EXIT_CRITICAL();
|
||||
ret = ESP_ERR_INVALID_SIZE;
|
||||
ESP_LOGE(HCD_DWC_TAG, "Invalid FIFO config");
|
||||
HCD_ENTER_CRITICAL();
|
||||
goto bailout;
|
||||
}
|
||||
usb_dwc_hal_set_fifo_config(port->hal, &port->fifo_config);// Apply FIFO settings
|
||||
|
||||
usb_dwc_hal_port_set_frame_list(port->hal, port->frame_list, FRAME_LIST_LEN); // Set periodic frame list
|
||||
usb_dwc_hal_port_periodic_enable(port->hal); // Enable periodic scheduling
|
||||
|
||||
@ -1287,7 +1379,6 @@ esp_err_t hcd_port_init(int port_number, const hcd_port_config_t *port_config, h
|
||||
TAILQ_INIT(&port_obj->pipes_active_tailq);
|
||||
port_obj->state = HCD_PORT_STATE_NOT_POWERED;
|
||||
port_obj->last_event = HCD_PORT_EVENT_NONE;
|
||||
port_obj->fifo_bias = get_hal_fifo_bias(port_config->fifo_bias);
|
||||
port_obj->callback = port_config->callback;
|
||||
port_obj->callback_arg = port_config->callback_arg;
|
||||
port_obj->context = port_config->context;
|
||||
@ -1297,10 +1388,18 @@ esp_err_t hcd_port_init(int port_number, const hcd_port_config_t *port_config, h
|
||||
port_obj->initialized = true;
|
||||
// Clear the frame list. We 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);
|
||||
*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",
|
||||
port_obj->fifo_config.rx_fifo_lines,
|
||||
port_obj->fifo_config.ptx_fifo_lines,
|
||||
port_obj->fifo_config.nptx_fifo_lines);
|
||||
vTaskDelay(pdMS_TO_TICKS(INIT_DELAY_MS)); // Need a short delay before host mode takes effect
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -1455,28 +1554,6 @@ void *hcd_port_get_context(hcd_port_handle_t port_hdl)
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t hcd_port_set_fifo_bias(hcd_port_handle_t port_hdl, hcd_port_fifo_bias_t bias)
|
||||
{
|
||||
esp_err_t ret;
|
||||
usb_hal_fifo_bias_t hal_bias = get_hal_fifo_bias(bias);
|
||||
|
||||
// Configure the new FIFO sizes and store the pointers
|
||||
port_t *port = (port_t *)port_hdl;
|
||||
xSemaphoreTake(port->port_mux, portMAX_DELAY);
|
||||
HCD_ENTER_CRITICAL();
|
||||
// Check that port is in the correct state to update FIFO sizes
|
||||
if (port->initialized && !port->flags.event_pending && port->num_pipes_idle == 0 && port->num_pipes_queued == 0) {
|
||||
usb_dwc_hal_set_fifo_bias(port->hal, hal_bias);
|
||||
port->fifo_bias = hal_bias;
|
||||
ret = ESP_OK;
|
||||
} else {
|
||||
ret = ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
HCD_EXIT_CRITICAL();
|
||||
xSemaphoreGive(port->port_mux);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// --------------------------------------------------- HCD Pipes -------------------------------------------------------
|
||||
|
||||
// ----------------------- Private -------------------------
|
||||
|
@ -51,6 +51,7 @@ SCENARIO("USB Host install")
|
||||
.root_port_unpowered = false,
|
||||
.intr_flags = 1,
|
||||
.enum_filter_cb = nullptr,
|
||||
.fifo_settings_custom = {},
|
||||
};
|
||||
|
||||
// USB host config is valid, USB Host driver is not installed from previous test case
|
||||
|
@ -561,7 +561,6 @@ esp_err_t hub_install(hub_config_t *hub_config, void **client_ret)
|
||||
|
||||
// Install HCD port
|
||||
hcd_port_config_t port_config = {
|
||||
.fifo_bias = HUB_ROOT_HCD_PORT_FIFO_BIAS,
|
||||
.callback = root_port_callback,
|
||||
.callback_arg = NULL,
|
||||
.context = NULL,
|
||||
|
@ -111,6 +111,16 @@ typedef struct {
|
||||
int intr_flags; /**< Interrupt flags for the underlying ISR used by the USB Host stack */
|
||||
usb_host_enum_filter_cb_t enum_filter_cb; /**< Enumeration filter callback. Enable CONFIG_USB_HOST_ENABLE_ENUM_FILTER_CALLBACK
|
||||
to use this feature. Set to NULL otherwise. */
|
||||
struct {
|
||||
uint32_t nptx_fifo_lines; /**< Required: Number of non-periodic TX FIFO lines.
|
||||
Must be > 0 to enable custom configuration. */
|
||||
uint32_t ptx_fifo_lines; /**< Optional: Number of periodic TX FIFO lines.
|
||||
Can be 0 if periodic TX endpoints are not used. */
|
||||
uint32_t rx_fifo_lines; /**< Required: Number of RX FIFO lines.
|
||||
Must be > 0 to enable custom configuration. */
|
||||
} 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. */
|
||||
} usb_host_config_t;
|
||||
|
||||
/**
|
||||
|
@ -94,9 +94,11 @@ The HCD currently has the following limitations:
|
||||
- `HCD_PORT_EVENT_DISCONNECTION`
|
||||
- `HCD_PORT_EVENT_ERROR`
|
||||
- `HCD_PORT_EVENT_OVERCURRENT`
|
||||
- The port's internal FIFOs (RX, Periodic TX, Non-periodic TX) must be after each port reset (a port reset seems to clear the FIFO sizing registers). The sizing of these FIFOs will affect the largest supported MPS of endpoints using that FIFO. For convenience, the HCD provides the `hcd_port_fifo_bias_t` enum that will set the FIFO sizes for you but biased towards a particular use case. For example, if the connected device has an IN endpoint with large MPS (e.g., 512 bytes), the FIFO should be biased as `HCD_PORT_FIFO_BIAS_RX`.
|
||||
- The FIFO sizes will be set on port initialization (supplied in `hcd_port_config_t`)
|
||||
- FIFOs can be resized after port reset using `hcd_port_set_fifo_bias()` but some restrictions apply (see API description).
|
||||
- The port's internal FIFOs (RX, Periodic TX, Non-periodic TX) must be configured during port initialization. The sizing of these FIFOs affects the maximum supported MPS (Maximum Packet Size) of endpoints using that FIFO.
|
||||
- FIFO sizes can be explicitly configured by the user via the `usb_host_config_t::fifo_settings_custom` structure during `usb_host_install()`.
|
||||
- If no custom FIFO configuration is provided (i.e., all fields are set to zero), the driver will automatically select FIFO sizes based on Kconfig bias settings (`USB_HOST_HW_BUFFER_BIAS_BALANCED`, `CONFIG_USB_HOST_HW_BUFFER_BIAS_IN`, or `CONFIG_USB_HOST_HW_BUFFER_BIAS_PERIODIC_OUT`).
|
||||
- After each USB port reset, the FIFO configuration is re-applied to the hardware registers based on the stored settings.
|
||||
- Manual FIFO reconfiguration after initialization is not supported. FIFO sizes must be set before any pipes are created or transfers occur.
|
||||
|
||||
## HCD Pipes
|
||||
|
||||
@ -140,4 +142,4 @@ The HCD API is thread safe however the following limitations should be noted:
|
||||
- Likewise, it is the client's responsibility to ensure that events and pipes are cleared before calling `hcd_port_deinit()`.
|
||||
- `hcd_port_command()` is thread safe, but only one port command can be executed at any one time. Therefore HCD internally used a mutex to protect against concurrent commands.
|
||||
- If multiple threads attempt to execute a command on the sample one, all but one of those threads will return with an invalid state error.
|
||||
- Blocking HCD functions should not be called from critical sections and interrupts (e.g., `hcd_port_command()` and `hcd_pipe_command()`).
|
||||
- Blocking HCD functions should not be called from critical sections and interrupts (e.g., `hcd_port_command()` and `hcd_pipe_command()`).
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -137,24 +137,32 @@ typedef bool (*hcd_port_callback_t)(hcd_port_handle_t port_hdl, hcd_port_event_t
|
||||
*/
|
||||
typedef bool (*hcd_pipe_callback_t)(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t pipe_event, void *user_arg, bool in_isr);
|
||||
|
||||
typedef enum {
|
||||
HCD_PORT_FIFO_BIAS_BALANCED, /**< Balanced FIFO sizing for RX, Non-periodic TX, and periodic TX */
|
||||
HCD_PORT_FIFO_BIAS_RX, /**< Bias towards a large RX FIFO */
|
||||
HCD_PORT_FIFO_BIAS_PTX, /**< Bias towards periodic TX FIFO */
|
||||
} hcd_port_fifo_bias_t;
|
||||
|
||||
/**
|
||||
* @brief Optional user-defined FIFO configuration (used internally by HCD)
|
||||
*
|
||||
* This structure is filled by the USB Host layer if the user provides
|
||||
* custom FIFO values. All values must be greater than zero to activate
|
||||
* the configuration. If NULL is passed, HCD will use the default
|
||||
* configuration based on the Kconfig bias.
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t nptx_fifo_lines; /**< Number of non-periodic TX FIFO lines */
|
||||
uint32_t ptx_fifo_lines; /**< Number of periodic TX FIFO lines */
|
||||
uint32_t rx_fifo_lines; /**< Number of RX FIFO lines */
|
||||
} hcd_fifo_settings_t;
|
||||
/**
|
||||
* @brief HCD configuration structure
|
||||
*/
|
||||
typedef struct {
|
||||
int intr_flags; /**< Interrupt flags for HCD interrupt */
|
||||
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. */
|
||||
} hcd_config_t;
|
||||
|
||||
/**
|
||||
* @brief Port configuration structure
|
||||
*/
|
||||
typedef struct {
|
||||
hcd_port_fifo_bias_t fifo_bias; /**< HCD port internal FIFO biasing */
|
||||
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 */
|
||||
@ -340,23 +348,6 @@ esp_err_t hcd_port_recover(hcd_port_handle_t port_hdl);
|
||||
*/
|
||||
void *hcd_port_get_context(hcd_port_handle_t port_hdl);
|
||||
|
||||
/**
|
||||
* @brief Set the bias of the HCD port's internal FIFO
|
||||
*
|
||||
* @note This function can only be called when the following conditions are met:
|
||||
* - Port is initialized
|
||||
* - Port does not have any pending events
|
||||
* - Port does not have any allocated pipes
|
||||
*
|
||||
* @param[in] port_hdl Port handle
|
||||
* @param[in] bias Fifo bias
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK FIFO sizing successfully set
|
||||
* - ESP_ERR_INVALID_STATE Incorrect state for FIFO sizes to be set
|
||||
*/
|
||||
esp_err_t hcd_port_set_fifo_bias(hcd_port_handle_t port_hdl, hcd_port_fifo_bias_t bias);
|
||||
|
||||
// --------------------------------------------------- HCD Pipes -------------------------------------------------------
|
||||
|
||||
/**
|
||||
|
@ -15,7 +15,7 @@ static const usb_ep_desc_t isoc_out_ep_desc = {
|
||||
.bDescriptorType = USB_B_DESCRIPTOR_TYPE_ENDPOINT,
|
||||
.bEndpointAddress = 0x02, // EP 2 OUT
|
||||
.bmAttributes = USB_BM_ATTRIBUTES_XFER_ISOC,
|
||||
.wMaxPacketSize = 512,
|
||||
.wMaxPacketSize = 128,
|
||||
.bInterval = 1, // Isoc interval is (2 ^ (bInterval - 1)) which means an interval of 1ms
|
||||
};
|
||||
|
||||
|
@ -161,7 +161,6 @@ hcd_port_handle_t test_hcd_setup(void)
|
||||
TEST_ASSERT_EQUAL(ESP_OK, hcd_install(&hcd_config));
|
||||
// Initialize a port
|
||||
hcd_port_config_t port_config = {
|
||||
.fifo_bias = HCD_PORT_FIFO_BIAS_BALANCED,
|
||||
.callback = port_callback,
|
||||
.callback_arg = (void *)port_evt_queue,
|
||||
.context = (void *)port_evt_queue,
|
||||
|
@ -43,7 +43,6 @@ TEST_CASE("Test HCD isochronous pipe URBs", "[isoc][full_speed][high_speed]")
|
||||
{
|
||||
usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); // Trigger a connection
|
||||
// The MPS of the ISOC OUT pipe is quite large, so we need to bias the FIFO sizing
|
||||
TEST_ASSERT_EQUAL(ESP_OK, hcd_port_set_fifo_bias(port_hdl, HCD_PORT_FIFO_BIAS_PTX));
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); // Short delay send of SOF (for FS) or EOPs (for LS)
|
||||
|
||||
// Enumerate and reset device
|
||||
@ -118,7 +117,6 @@ TEST_CASE("Test HCD isochronous pipe URBs all", "[isoc][full_speed][high_speed]"
|
||||
{
|
||||
usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); // Trigger a connection
|
||||
// The MPS of the ISOC OUT pipe is quite large, so we need to bias the FIFO sizing
|
||||
TEST_ASSERT_EQUAL(ESP_OK, hcd_port_set_fifo_bias(port_hdl, HCD_PORT_FIFO_BIAS_PTX));
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); // Short delay send of SOF (for FS) or EOPs (for LS)
|
||||
|
||||
// Enumerate and reset device
|
||||
@ -230,7 +228,6 @@ TEST_CASE("Test HCD isochronous pipe sudden disconnect", "[isoc][full_speed][hig
|
||||
{
|
||||
usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); // Trigger a connection
|
||||
// The MPS of the ISOC OUT pipe is quite large, so we need to bias the FIFO sizing
|
||||
TEST_ASSERT_EQUAL(ESP_OK, hcd_port_set_fifo_bias(port_hdl, HCD_PORT_FIFO_BIAS_PTX));
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); // Short delay send of SOF (for FS) or EOPs (for LS)
|
||||
|
||||
// Enumerate and reset device
|
||||
|
@ -487,9 +487,26 @@ esp_err_t usb_host_install(const usb_host_config_t *config)
|
||||
}
|
||||
|
||||
// Install HCD
|
||||
// Prepare HCD configuration
|
||||
hcd_fifo_settings_t user_fifo_config;
|
||||
hcd_config_t hcd_config = {
|
||||
.intr_flags = config->intr_flags
|
||||
.intr_flags = config->intr_flags,
|
||||
.fifo_config = NULL, // Default: use bias strategy from Kconfig
|
||||
};
|
||||
|
||||
// Check if user has provided a custom FIFO configuration
|
||||
if (config->fifo_settings_custom.rx_fifo_lines != 0 ||
|
||||
config->fifo_settings_custom.nptx_fifo_lines != 0 ||
|
||||
config->fifo_settings_custom.ptx_fifo_lines != 0) {
|
||||
|
||||
// Populate user FIFO configuration with provided values
|
||||
user_fifo_config.rx_fifo_lines = config->fifo_settings_custom.rx_fifo_lines;
|
||||
user_fifo_config.nptx_fifo_lines = config->fifo_settings_custom.nptx_fifo_lines;
|
||||
user_fifo_config.ptx_fifo_lines = config->fifo_settings_custom.ptx_fifo_lines;
|
||||
|
||||
// Pass custom configuration to HCD
|
||||
hcd_config.fifo_config = &user_fifo_config;
|
||||
}
|
||||
ret = hcd_install(&hcd_config);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(USB_HOST_TAG, "HCD install error: %s", esp_err_to_name(ret));
|
||||
|
Reference in New Issue
Block a user