Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Universal Serial Bus (USB)

Ariel OS integrates support for USB peripherals built into many microcontrollers.

Hardware Support

Supported USB Standards

Many microcontrollers supported by Ariel OS include a USB microcontroller peripheral that can be leveraged to build any USB device. At the time of writing, most of them support USB 2.0, but their signaling rate is often limited to 12 Mbit/s, even though some also do support 480 Mbit/s. The following table summarizes the standard signaling rates and their names:

Signaling rateStandard
1.5 Mbits/sLow-Speed USB (now aka Basic-Speed USB)
12 Mbits/sFull-Speed USB (now aka Basic-Speed USB)
480 Mbits/sHi-Speed USB

Some also support USB On-The-Go (OTG), allowing the device to also behave as a USB Targeted Host on the same USB receptacle (by alternatively switching between the peripheral and host roles). Currently only the USB peripheral (device) role is supported by Ariel OS. The USB host role is not supported.

USB Microcontrollers Peripherals

Currently, Ariel OS applications can only make use of “generic” USB peripherals, that is, USB microcontroller peripherals that can be used to implement any USB device class. Some microcontrollers also feature USB microcontroller peripherals that only support a fixed set of USB classes: e.g., multiple ESP32 MCUs comprise a USB CDC-ACM/JTAG peripheral, which can only be used for the standard USB CDC-ACM device class or a vendor-specific device class implementing JTAG access over USB. The others may still be integrated by Ariel OS to implement specific functionality, like logging.

Tip

Development kits that support USB often feature two USB receptacles: one for the onboard debug probe (if there is one), and the other connected to the USB peripheral of the microcontroller. That second USB connection is usually called “user USB” to differentiate it from that of the debug probe and is the one that must be connected to the computer acting as USB host.

USB 1.x/USB 2.0 Device Speed Identification Pull-up Resistors

The USB specifications require that the USB device advertise its supported speed to the USB host using a pull-up resistor on one of the data line. A pull-up resistor1 (Rpu) must be added on D+ to advertise support for Full-Speed USB, while Low-Speed requires one on D−. Hi-Speed USB uses the same pull-up as Full-Speed, with additional software negotiation.

If the USB device is always bus powered, these pull-up resistors may be always connected. However, because devices are not allowed to supply current on the data lines when VBUS is not present (sections 7.1.5 and 7.2.1 of the USB 2.0 specification), self-powered devices must implement VBUS detection. VBUS detection (aka VBUS sensing) involves monitoring whether VBUS is present, connecting the pull-up resistor when it is applied, and disconnecting it when VBUS is removed, within 10 seconds (see section 7.2.1 of the USB 2.0 specification). To this effect, microcontroller USB peripherals often implement VBUS detection in hardware, and require a dedicated GPIO pin to monitor the state of VBUS. If they do not, or if the pin is not connected on the board, VBUS detection must be implemented manually, to enable/disable the pull-up resistor as necessary.

Ariel OS always uses the internal pull-up resistors when available in hardware, and supports enabling VBUS detection when supported by the hardware (so they are only connected when VBUS is present). When the microcontroller USB peripheral in use is USB OTG-capable, the pull-up is always managed by hardware, as part of OTG’s protocols. Otherwise, if VBUS detection is required and is not made possible by the hardware, it must currently be implemented manually in the application.

Software Integration

Ariel OS provides support for the USB peripheral role through embassy-usb, which provides a consistent API across the supported hardware. It can be enabled with the usb laze module, which is only made available when the board features a USB device port.

An instance of embassy_usb::Builder is created by Ariel OS, on which support for well-known USB device classes can be added using a dedicated Ariel OS task hook:

#[ariel_os::task(autostart, usb_builder_hook)]
async fn main() {
    let mut usb_class = USB_BUILDER_HOOK
        .with(|builder| {
            // USB class constructor that mutates the builder.
        })
        .await;
}

Support for well-known USB device classes is provided by embassy-usb, which is re-exported as ariel_os::reexports::embassy_usb. Custom USB device classes can also be implemented. Additionally, multiple USB device classes can be added on the builder, to create a composite USB device.

USB Device Classes

The table below lists some of the well-known USB device classes and how to use them in Ariel OS :

Device classHow to use
USB CDC-ACMApply the CdcAcmClass constructor on the builder
USB CDC-NCMEnable the usb-ethernet laze module
USB HIDEnable the usb-hid Cargo feature and apply the HidReaderWriter constructor on the builder

Other well-known device classes are supported, and it is also possible to implement custom ones.

Device Configuration

Configuration for the USB device created can be provided using the #[ariel_os::config(usb)] attribute. In particular, it allows setting the Vendor ID (VID) and Product ID (PID), and the manufacturer and product names.

Additionally, some environment variables are used by embassy-usb for configuration. See its documentation for more.

Clock Configuration

As USB microcontroller peripherals rely on specific clock frequencies (to accommodate the signaling rates of USB), they are usually provided with a dedicated clock signal, that is often not shared with other peripherals. Because USB requires accurate timings2, the clock source typically relies on a crystal resonator (or an external crystal oscillator). When that is not the case, the microcontroller must feature a clock recovery system that is able to recover a clock from the USB Start Of Frame (SOF) packets (sent by the USB host every 1 ms for Full-Speed USB) and that trims an internal oscillator, keeping it in sync with the USB host and thus enabling crystal-less USB. Many STM32 MCUs feature such clock recovery system (CRS).

To be able to use USB, the clock configuration must enable and configure the clock source required for the USB microcontroller peripheral. The default clock configuration provided by Ariel OS usually already configures it appropriately when made possible by the board. Otherwise, an appropriate clock configuration must be provided in the application.


  1. Originally, the pull-up resistance was required to be 1.5 kΩ ±5% (see section 7.1.3 of the USB 1.0 specification, section 7.1.5 of the USB 1.1 specification, and section 7.1.5 of the USB 2.0 specification). Following the Resistor ECN, the resistance value is given more tolerance and is allowed to fall into two different ranges: one around 1.2 kΩ when the bus is idle, and the other around 2.3 kΩ when the upstream device (i.e., the USB host or hub) is transmitting. The higher tolerance allowed integrating these pull-up resistors into the chip as internal resistors (as these have higher manufacturing tolerance than discrete resistors).

  2. Full-Speed USB requires a bit rate accuracy of 2500 ppm, while Hi-Speed USB requires 500 ppm (see section 7.1.11 of the USB 2.0 specification).