Open-source project
sekigon-gonnoc/Pico-PIO-USB avatar
sekigon-gonnoc/Pico-PIO-USB

Pico-PIO-USB for Adding USB Host and Device Ports to RP2040

USB host/device implementation using PIO of raspberry pi pico (RP2040/RP2350).

1,764 stars231 forksCMIT

At a glance

What is it?
Pico-PIO-USB implements USB host and device functions through the Raspberry Pi Pico PIO, with examples for forwarding HID input and exposing a HID device. It suits firmware developers who need an additional USB port but must account for its resource use, sample-specific wiring, and narrower documentation.
Who is it for?
Adopt Pico-PIO-USB when an RP2040 design needs PIO-based USB host or device support and can accommodate the stated GPIO, PIO, timer, and memory costs. Do not choose it as a fully documented general USB stack for RP2350 without first checking its source and examples.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 93 days ago.
What is it written in?
Mainly C, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Why Pico-PIO-USB Adds a Port to RP2040

Pico-PIO-USB addresses a specific hardware constraint: an RP2040 needs an additional USB interface, but its native USB peripheral is already tied to the device role described by the example. The library uses the RP2040's PIO block to perform USB host or device signal handling on ordinary GPIOs. According to the repository description, the implementation targets RP2040 and RP2350, although the README specifically frames the project around RP2040 and says that RP2350 support should not be assumed from the documentation alone.

The intended users are firmware developers working directly in C with the Raspberry Pi Pico SDK and CMake. The project includes separate host and device examples. One forwards mouse and keyboard reports from a host port to a CDC output on the native USB device connection. Another presents itself as a full-speed HID device and moves the mouse cursor at fixed intervals. A linked QMK example covers a split keyboard configuration.

This is infrastructure for embedded USB connectivity, not a general-purpose host stack for conventional desktop computers. Its value lies in assigning a second USB connection to two configurable GPIO pins while retaining control over embedded firmware. The documentation does not describe peripheral enumeration from an operating system, driver installation, or use with Raspberry Pi OS.

PIO, GPIO, Timer, and IRQ Allocation

The documented resource budget is unusually concrete. Host support consumes one PIO block, three state machines, and 32 PIO instructions. The USB data connection requires two GPIOs for D+ and D-, with the README recommending 22-ohm series resistors. Host operation also uses a repeating 1 ms timer. Device operation uses a PIO interrupt for reception.

The PIO block is what allows USB signaling to execute outside the main CPU path. The README does not expose the state-machine program or low-level packet parser, so it would be misleading to claim more about the internal state transitions. The visible architecture is still enough to identify the principal resource boundaries: PIO handles signaling, GPIO carries the differential data lines, and a timer or interrupt drives time-sensitive work.

Memory use is listed as 15 KB for ROM and RAM, but the entry does not distinguish those two categories. It would therefore be inappropriate to interpret the figure as 15 KB of flash plus 15 KB of RAM or as a combined figure with a defined linker meaning. Firmware authors should inspect the example build and linked output for their configuration. Pin conflicts are another practical concern because D+ and D- occupy two GPIO resources, while the device sample assigns D+ to `gp0` by default.

CMake Build for the Included Examples

The README gives a short CMake workflow for building the examples. Start from the repository's `examples` directory, create a build directory, configure with CMake, and compile it. The documented command sequence is:

bash
cd examples
mkdir build
cd build
cmake ..
make

After a successful local build, the generated UF2 output location depends on the CMake configuration. The README instructs users to copy a UF2 file from `capture_hid_report/` or `usbdevice/` to the Raspberry Pi Pico. This instruction is inconsistent with the repository entries, which include `examples/host_hid_to_device_cdc/` and `examples/usb_device/`. The article cannot correct those names without inventing repository paths, so check the generated `build` tree and `examples/CMakeLists.txt` before copying a file.

The build also expects the Raspberry Pi Pico SDK because `pico_sdk_import.cmake` is included. The README does not document SDK installation, toolchain prerequisites, board selection, or environment variables, so it does not provide a complete installation tutorial for a machine that lacks the Pico C/C++ toolchain. For the first real use, follow the build exactly, locate the generated UF2 artifact, and inspect the directory rather than assuming the README's output names match the current example layout.

Forwarding HID Reports Through Two USB Roles

The `examples/host_hid_to_device_cdc/host_hid_to_device_cdc.c` example is the clearest end-to-end use case. The README says that it prints mouse and keyboard reports received through the PIO-backed host port to the device port's CDC interface. TinyUSB manages both stacks: the native USB connection operates as the device-facing CDC path, while Pico-PIO-USB provides the host role on the added port.

That arrangement is useful when an embedded RP2040 needs to read a USB keyboard or mouse while exposing diagnostics or forwarded input over its native USB connection. It also demonstrates two distinct roles on one chip. The PIO-backed host side must enumerate and communicate with the attached HID device, while TinyUSB handles the device side described by the README.

The README does not specify the exact device descriptor, supported HID subclasses, host polling behavior, CDC baud settings, or output format. It also does not document behavior when no USB device is attached, when a device is disconnected, or when the attached HID device uses a report layout the example does not expect. Those details must come from the source. The example is a starting point for forwarding, not evidence that every HID class, rate, or hot-plug case is handled.

Running the HID Device Example on D+ and D-

The `examples/usb_device/usb_device.c` sample configures a full-speed HID USB device and moves the mouse cursor every 0.5 seconds. Its documented hardware requirement is an external 1.5-kilohm pull-up resistor on D+, with the default D+ pin set to `gp0`. The D- assignment is not stated in the README.

This example is useful for checking whether a host can recognize a PIO-backed USB device. Its behavior is fixed, so it tests connection, enumeration, HID reporting, and cursor movement without requiring manual input. It does not demonstrate configuration storage, composite devices, battery reporting, or a production keyboard interface.

The pull-up requirement is essential because software configuration alone does not create the documented electrical condition. The README also recommends 22-ohm series resistors for D+ and D-. It does not provide a wiring diagram, board outline, cable guidance, signal-integrity guidance, or supported host operating systems. Before wiring hardware, inspect `usb_device.c` for its complete pin definitions and the example configuration for any additional setup. Treat the README as a partial hardware note rather than a complete board design guide.

Scope Limits for Hubs, Low Speed, and Split Keyboards

The status table marks FS Host, LS Host, hub support, multi-port support, and FS Device as completed. Those entries describe feature status, not compatibility guarantees for every topology. The README does not say how many downstream devices a hub may expose, whether all hub speeds are covered, how much endpoint or transfer bandwidth is available, or whether simultaneous host and device workloads meet application-specific timing requirements.

The linked QMK keyboard example expands the scope beyond the bundled HID samples. It shows how Pico-PIO-USB can sit inside a split-keyboard arrangement, where one USB connection has a different role than a direct host peripheral. The link is to a separate `qmk_firmware` branch and keyboard directory, so its QMK integration details are outside this repository's README. Pin mappings, keyboard scanning, transport behavior, and build requirements for that example must be read in the linked QMK tree.

There are also clear wrong-use cases. Pico-PIO-USB is not presented as a USB peripheral driver for a general computer, a Raspberry Pi OS host driver, or a battery-aware console driver. The documentation also does not cover suspend, wake, USB-C negotiation, power delivery, peripheral OTG roles, or electrically isolated industrial interfaces. Those omissions matter because adding two GPIOs does not remove the electrical and protocol requirements of USB.

License, Releases, and Maintenance Boundaries

The repository identifies Pico-PIO-USB as MIT licensed. The applicable obligations come from the repository's `LICENSE` file. Code reuse should be evaluated against that text, including its notice and license requirements. This is a license identification, not legal advice.

The available release history lists version 0.7.2 on 2025-05-21, following 0.7.1 on 2025-04-14 and 0.7.0 on 2025-04-04. The last push was on 2026-07-22, so the repository is not archived and its activity is recent. That fact does not establish long-term support for the Pico SDK, RP2350, TinyUSB, QMK, or specific USB device classes. Each of those dependencies can change independently.

The README does not provide a compatibility matrix, semantic-versioning policy, deprecation process, validated board list, long-term-support branch, or migration guide between 0.7.x releases. It also does not document rollback. Upgrading cost therefore depends on diffing the release changes, rebuilding the examples, and checking external TinyUSB and Pico SDK compatibility.

Editorial conclusion

Adopt Pico-PIO-USB when an RP2040 design needs PIO-based USB host or device support and can accommodate the stated GPIO, PIO, timer, and memory costs. Do not choose it as a fully documented general USB stack for RP2350 without first checking its source and examples. Verify the exact example directory names, electrical requirements, target support, and lifecycle expectations before building production firmware.

Frequently asked questions

What Raspberry Pi boards and chips does Pico-PIO-USB support?

The repository description names RP2040 and RP2350, while the README specifically documents RP2040. Confirm RP2350 support in the source and build configuration before treating it as documented support.

How do I build and flash the Pico-PIO-USB examples?

The README instructs users to run CMake and `make` under `examples/build`, then copy a generated UF2 file to the Raspberry Pi Pico. Its named output directories do not match the example directory names shown in the repository, so inspect the generated build tree first.

What hardware is required to run the Pico-PIO-USB HID device example?

The README requires an external 1.5-kilohm pull-up resistor on D+, whose default pin is `gp0`, plus two GPIO connections for D+ and D-. It also recommends 22-ohm series resistors for the data lines.

Does Pico-PIO-USB support USB hubs and split keyboards?

The status table marks hub support and FS Host and LS Host as completed. A separate linked QMK example demonstrates a split keyboard, but its configuration is documented in the linked QMK repository rather than this README.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. Releases
  5. sekigon-gonnoc/Pico-PIO-USB on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/sekigon-gonnoc-pico-pio-usb.svg)](https://hysenlabs.com/projects/sekigon-gonnoc-pico-pio-usb)

Was this useful?