The number of USB devices you can have active at once is limited. Here we'll explain the limitations.
You can specify no more than eight HID devices in total. In addition, you can only define a single composite HID device, though you may be able to define more in the future.
Microcontrollers provide a limited number of USB endpoints. This is a hardware limitation. An endpoint is a single low-level USB communications channel. Typically endpoints are paired. Each endpoint pair has an IN endpoint and OUT endpoint. The naming is from the point of view of the host: IN means sending data from device to the host; OUT means sending data from the host to the device.
Endpoint pairs are numbered starting at 0. Endpoint pair 0 is always reserved for USB setup and control, so we can't use it for regular devices.
Each separate USB device needs to use one or more endpoint pairs. Here are the endpoint requirements for the devices we provide:
- CIRCUITPY (MSC): 1 IN/OUT endpoint pair.
- MIDI: 1 IN/OUT pair.
CDC: 1 IN endpoint for control, and 1 IN/OUT pair for data, for a total of 2 pairs, for each CDC device. If you enable both
usb_cdcdevices in CircuitPython, 2+2=4 pairs are needed in total.
- HID: 1 IN/OUT pair for each composite device. All the devices in the composite share the single endpoint pair.
So if all these devices are enabled, including both
usb_cdc devices, you'll need 1+1+2+2+1=7 endpoint pairs.
The SAMD21, SAMD51, nRF52840, and RP2040 microcontrollers all provide 8 endpoint pairs each. since pair 0 is reserved, 7 pairs are available, and so enabling all the devices above just fits.
However, other microcontrollers provide fewer than 8 pairs:
- STM32F4 chips typically provide only 3 pairs, not counting pair 0. That means only CIRCUITPY and one CDC device will fit. If you want HID or MIDI on an STM32F4, you'll need to turn off CIRCUITPY or CDC.
- ESP32-S2 provides 6 pairs, not counting pair 0. However, you can have only 5 IN endpoints active at a time. So there are usually just 5 pairs available.
- Spresense provides 6 pairs but assigns its endpoints at build-time, so you can't turn on MIDI or an extra CDC device.
If your boot.py settings turn on too many devices, CircuitPython will go into safe mode after running boot.py, and will not run code.py. If you go into the REPL, you will see CircuitPython reporting the reason it is in safe mode, such as "USB devices need more endpoints than are available".