#embedded-devices #usb #embedded

no-std usbh

Experimental host-side USB stack for embedded devices

1 unstable release

0.1.0 Aug 6, 2023

#1804 in Hardware support

MIT license



Experimental host-side USB stack for embedded devices.

This crate is in a very early stage. See this PR in the rp-hal repository, the work on which inspired me to create this crate.


Experimental host-side USB stack for embedded devices.

usbh aims to abstract between two things:

  • embedded USB host controllers on one side
  • function specific USB drivers on the other side

The goal is that a driver can be developed independently from the specific host controller hardware, similarly to the usb-device crate allowing implementing USB functions independently of the USB device controller.

Implementing drivers

Please check out the documentation for the driver module.

Adding support for new hardware

Since this project is in an early stage, this area is largely unexplored.

The bus module contains a HostBus trait, which must be implemented for the target hardware.

If you are planning to implement support for a new hardware, please open an issue, so we can figure out together if any additions or changes to the HostBus interface are necessary to accomodate it.


The code block below shows a brief example, leaving out any hardware and driver specifics.

For a full example, please check out the rp-hal-usb-host-example which contains a runnable example, targeting RP2040 based boards.

use usbh::{

fn main() {
    // must implement usbh::bus::HostBus
    let host_bus = hardware_specific_host_bus_initialization();

    let usb_host = UsbHost::new(host_bus);

    // these must implement usbh::driver::Driver;
    let mut driver1 = create_first_driver();
    let mut driver2 = create_second_driver();

    // (leaving out details on how to share `usb_host` and `driver*` with the interrupt routine)

fn USB_IRQ() {
    match usb_host.poll(&mut [&mut driver1, &mut driver2]) {
        PollResult::BusError(error) => {
            // something went wrong
        PollEvent::DiscoveryError(device_address) => {
            // device with specified address misbehaved during discovery (it will likely not be usable)
        PollResult::NoDevice => {
            // no device is currently connected
        Event::Busy => {
            // Host is currently busy with a transfer.
            // Trying to start a transfer now will return `WouldBlock`.
        Event::Idle => {
            // Host is not currently handling any transfer.
            // A new transfer can be started, if desired.

    // After polling the USB host, the drivers may have new things to report:
    if let Some(event) = driver1.take_event() {
       // ...
    if driver2.something_something() {
       // ...


~52K SLoC