embassy-rs/embassy · error

Unsupported EP0 size

Error message

Unsupported EP0 size: {}

What it means

The Synopsys OTG USB driver encodes the EP0 (control endpoint) max packet size into the MPSIZ field, which hardware supports only for sizes 8, 16, 32, or 64. ep0_mpsiz panics on any other value rather than programming an invalid hardware register.

Solutions

  1. Set max_packet_size_0 to 64 (the standard control-endpoint size for full/high speed).
  2. Use only 8, 16, 32, or 64 for EP0.
  3. Add a compile-time constant for the control EP size so it cannot drift with endpoint-specific values.

Example fix

// before
let config = Config { max_packet_size_0: 128, .. };
// after
let config = Config { max_packet_size_0: 64, .. };
Defensive patterns

Strategy: validation

Validate before calling

fn valid_ep0_size(n: u16) -> bool { matches!(n, 8 | 16 | 32 | 64) }
assert!(valid_ep0_size(config.max_packet_size_0), "EP0 size must be 8/16/32/64");

Type guard

fn valid_ep0_size(n: u16) -> bool { matches!(n, 8 | 16 | 32 | 64) }

Prevention

When it happens

Trigger: Setting UsbConfig::max_packet_size_0 (or the value reaching ep0_mpsiz) to something other than 8/16/32/64 — e.g. 0, 128, or a packet size intended for a bulk endpoint.

Common situations: Copying a max_packet_size from a bulk/interrupt endpoint config into max_packet_size_0; typos like 512; constructing config programmatically with computed values.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of embassy-rs/embassy@463a07b963 (2026-09-10). Data as JSON: /api/errors/4a007f22a1689429. Report an issue: GitHub.

Appendix: source

Thrown at embassy-usb-synopsys-otg/src/lib.rs:1998

/// Translates HAL [EndpointType] into PAC [vals::Eptyp]
fn to_eptyp(ep_type: EndpointType) -> vals::Eptyp {
    match ep_type {
        EndpointType::Control => vals::Eptyp::CONTROL,
        EndpointType::Isochronous => vals::Eptyp::ISOCHRONOUS,
        EndpointType::Bulk => vals::Eptyp::BULK,
        EndpointType::Interrupt => vals::Eptyp::INTERRUPT,
    }
}

/// Calculates MPSIZ value for EP0, which uses special values.
fn ep0_mpsiz(max_packet_size: u16) -> u16 {
    match max_packet_size {
        8 => 0b11,
        16 => 0b10,
        32 => 0b01,
        64 => 0b00,
        other => panic!("Unsupported EP0 size: {}", other),
    }
}

/// Hardware-dependent USB IP configuration.
#[derive(Copy, Clone)]
pub struct OtgInstance<'d, M = CriticalSectionRawMutex>
where
    M: RawMutex + Copy,
{
    /// The USB peripheral.
    pub regs: Otg,
    /// Shared driver/interrupt state from [`State::as_state`].
    pub state: State<'d, M>,
    /// FIFO depth in words.
    pub fifo_depth_words: u16,
    /// The PHY type.
    pub phy_type: PhyType,
    /// Extra RX FIFO words needed by some implementations.

View on GitHub (pinned to 463a07b963)