embassy-rs/embassy · error

Endpoint memory full

Error message

Endpoint memory full

What it means

STM32 USB devices have a small shared packet-buffer RAM (USBRAM, typically 512–4096 bytes). alloc_ep_mem is a bump allocator over that region; when an endpoint allocation would push past USBRAM_SIZE, the driver panics because the hardware physically cannot back more buffers.

Solutions

  1. Reduce endpoint max_packet_size values (e.g. 512 -> 64 for bulk FS)
  2. Drop or combine endpoints/interfaces, or use fewer bidirectional endpoints
  3. Move to a chip variant with larger USBRAM (check USBRAM_SIZE for your part; 32-bit usbram parts usually have 1–4 KB)
  4. Compute your budget: sum of (IN+OUT buffer sizes + 2-byte Tx/Rx counts, aligned) and keep it under USBRAM_SIZE before adding endpoints

Example fix

// before
let ep_in = dev.alloc_endpoint(EndpointType::Bulk, 512, 512)?;
let ep_out = dev.alloc_endpoint(EndpointType::Bulk, 512, 512)?; // + more eps -> "Endpoint memory full"
// after
let ep_in = dev.alloc_endpoint(EndpointType::Bulk, 64, 64)?;
let ep_out = dev.alloc_endpoint(EndpointType::Bulk, 64, 64)?;
Defensive patterns

Strategy: validation

Validate before calling

// sum endpoint buffer needs before allocating
const USBRAM_SIZE: usize = 1024; // check your part
let needed: usize = eps.iter().map(|e| (e.in_size + e.out_size) as usize).sum();
assert!(needed <= USBRAM_SIZE, "USB RAM budget {} exceeds {}", needed, USBRAM_SIZE);

Type guard

fn fits_usbram(total: usize, usbram: usize) -> bool { total <= usbram }

Prevention

When it happens

Trigger: alloc_endpoint calls whose cumulative buffer sizes exceed USBRAM_SIZE — e.g. many endpoints with large max_packet_size, or several bidirectional ISO/Bulk endpoints on a 512–1024-byte USBRAM part.

Common situations: Adding a second interface (e.g. CDC-ACM + MSC + custom vendor) and exhausting 512 B of USBRAM; bumping packet sizes to 512 for speed on a part with 1 KB USBRAM; iterating during development, growing buffers until total allocation overflows.

Related errors


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

Appendix: source

Thrown at embassy-stm32/src/usb/usb.rs:361

        // Initialize the bus so that it signals that power is available
        BUS_WAKER.wake();

        Self {
            phantom: PhantomData,
            alloc: [EndpointData {
                ep_type: EndpointType::Bulk,
                used_in: false,
                used_out: false,
            }; EP_COUNT],
            ep_mem_free: EP_COUNT as u16 * 8, // for each EP, 4 regs, so 8 bytes
        }
    }

    fn alloc_ep_mem(&mut self, len: u16) -> u16 {
        assert!(len as usize % USBRAM_ALIGN == 0);
        let addr = self.ep_mem_free;
        if addr + len > USBRAM_SIZE as _ {
            panic!("Endpoint memory full");
        }
        self.ep_mem_free += len;
        addr
    }

    fn is_endpoint_available<D: Dir>(&self, index: usize, ep_type: EndpointType) -> bool {
        if index == 0 && ep_type != EndpointType::Control {
            return false; // EP0 is reserved for control
        }

        let ep = match self.alloc.get(index) {
            Some(ep) => ep,
            None => return false,
        };

        let used = ep.used_out || ep.used_in;

        if used && ep.ep_type == EndpointType::Isochronous {

View on GitHub (pinned to 463a07b963)