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
- Reduce endpoint max_packet_size values (e.g. 512 -> 64 for bulk FS)
- Drop or combine endpoints/interfaces, or use fewer bidirectional endpoints
- Move to a chip variant with larger USBRAM (check USBRAM_SIZE for your part; 32-bit usbram parts usually have 1–4 KB)
- 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
- Budget USBRAM per interface before adding endpoints
- Prefer 64-byte FS bulk buffers unless bandwidth demands more
- Check USBRAM_SIZE for your exact chip (512 B to 4 KB) in the datasheet
- Recount the budget whenever adding an interface (CDC, MSC, vendor)
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
- invalid OUT length
- invalid OUT length
- USB clock should be one of 16, 19.2, 20, 24, 26, 32Mhz but…
- USB clock should be 48Mhz but is
- USB HS PHY reference clock should be 19.2, 20 or 24 MHz but…
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)