Skip to content

Choose the host FIFO bias at runtime, not at build time #2

Description

@bdbarnett

The problem

The DWC controller's FIFO split is one board-wide choice, made at build time via Kconfig, and the three presets are in direct competition:

Bias IN (all types) Non-periodic OUT Periodic OUT
Balanced 408 192 192
Bias IN 600 64 128
Periodic OUT 128 64 600

Both capabilities this program has actually demonstrated fall on opposite sides of that:

  • Hosted audio playback to a USB CODEC needs 192 B/ms for 48 kHz stereo 16-bit — so it needs periodic OUT ≥ 192.
  • Hosted video capture from a UVC camera needs 384 B/ms at the smallest useful mode on this bench (320x240 MJPEG @ 5 fps) and 944 at its preferred one — so it needs IN ≥ 384.

No preset satisfies both. Balanced comes closest (IN 408 / OUT 192) but leaves no headroom on either side, and 64 of its lines go to non-periodic OUT, which is pointless at full speed where bulk and control max out at 64 bytes anyway.

The build currently uses Bias IN, chosen for the camera (cmods 518d850). That trades away stereo playback, which was working.

Why this is fixable

usb_host_config_t exposes a runtime override:

struct {
    uint32_t nptx_fifo_lines;  // Required, must be > 0
    uint32_t ptx_fifo_lines;   // Optional, 0 if no periodic TX endpoints
    uint32_t rx_fifo_lines;    // Required, must be > 0
} fifo_settings_custom;

Passed to usb_host_install(), which usbif already calls from its own host task. And host_start(classes) is already told which classes the caller wants to host — so the split can be derived from the request rather than guessed at build time.

IDF's own preset formulas (_calculate_fifo_from_bias in hcd_dwc.c) are the model, with otg_dfifo_depth 256 on full-speed targets and 1024 on high-speed ones:

Bias IN:       nptx = depth/16, ptx = depth/8,  rx = total - ptx - nptx
Periodic OUT:  rx = depth/8 + 2, nptx = depth/16, ptx = total - nptx - rx
Balanced:      nptx = depth/4,  ptx = depth/8,  rx = total - ptx - nptx

usb_dwc_hal_fifo_config_is_valid() only requires used_lines <= fifo_size, so a split may under-allocate — it does not have to consume every line. That makes a conservative custom split safe even without knowing the exact hardware FIFO size.

Proposed behaviour

host_start(classes) picks the split from what was asked for:

  • uvc (or any IN-heavy class) requested → IN-leaning
  • uac requested without uvc → periodic-OUT-leaning
  • neither, or both → balanced, and say so

One firmware would then serve stereo playback and a camera in the same session — just not in the same host_start(). That limitation is inherent (the FIFO is configured at usb_host_install()) and worth documenting rather than hiding.

Notes

  • The failure mode when the bias is wrong is ESP_ERR_NOT_SUPPORTED (0x106) from usb_host_interface_claim(), which says nothing about packet sizes. Worth translating into a real diagnostic — "endpoint MPS N exceeds the current FIFO bias limit" — since it cost real time to identify twice today.
  • The Kconfig help table above is the authority for the limits; note it lists Balanced and Bias IN with the same ptx formula but different periodic-OUT limits, so the numbers should be re-measured rather than trusted if they start to matter at the margin.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions