# TinyUSB: a no-malloc USB stack for embedded systems

> TinyUSB is an MIT-licensed USB Host and Device stack for microcontrollers, built so that no dynamic allocation happens and all interrupts are deferred to task context. This review covers the device and host class support, the cdc_msc example path, and where the stack is the wrong choice.

**hathach/tinyusb** — An open source  cross-platform USB stack for embedded system

- Repository: https://github.com/hathach/tinyusb
- Website: https://www.tinyusb.org
- Stars: 7,166 · Forks: 1,540
- Language: C
- License: MIT
- Published: 2026-09-22 · Updated: 2026-09-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/hathach-tinyusb

## What TinyUSB solves, and for whom

Writing a USB stack by hand means implementing enumeration, descriptor handling, endpoint arbitration and class protocols before your application does anything at all. TinyUSB packages that work as a reusable C library. The README describes it as an open-source cross-platform USB Host/Device stack for embedded systems, designed for memory safety (no dynamic allocation) and thread safety (all interrupts deferred to non-ISR task functions).

The audience is firmware engineers on microcontrollers, not people writing desktop USB drivers. The README claims support for 50+ MCU families, and the supported CPU table lists manufacturers such as Allwinner, Analog Devices (MAX3421E over SPI) and others. If your board is in that table, you are the target user. If it is not, porting is a separate project: the repository has a hw/mcu directory for low level MCU core and peripheral drivers and a Porting guide referenced from the README.

## How the stack is put together: descriptors, classes and a central queue

The repository layout separates the stack from the hardware. src holds all source files for the TinyUSB stack itself, hw/bsp holds supported board sources, hw/mcu holds low level MCU core and peripheral drivers, and lib holds third-party sources such as FreeRTOS and FatFs. Examples live under examples/ with make and cmake build systems.

The device side supports multiple configurations by dynamically changing USB descriptors, plus suspend, resume and remote wakeup. Classes listed in the README include Audio (UAC1/UAC2), BTH HCI, CDC, DFU (with DFU mode marked work in progress), HID, Printer, MSC with multiple LUNs, MIDI, MTP/PTP, RNDIS/ECM/NCM networking, USBTMC, and Video 1.5 (marked work in progress). Vendor-specific classes are supported with generic In and Out endpoints, and can use an MS OS 2.0 compatible descriptor to load the winUSB driver without an INF file. WebUSB is supported through the vendor-specific class.

The host side is narrower: CDC-ACM, vendor serial over FTDI, CP210x, CH34x and PL2303, HID (keyboard, mouse, generic), MSC, MIDI, and hubs with multiple-level support.

The thread-safety mechanism is the part worth understanding before adopting. The README states that TinyUSB pushes all Interrupt Service Request events into a central queue and processes them later in a non-ISR task function, and that it uses semaphore/mutex to access shared resources such as the CDC FIFO. That means the stack needs some OS primitives. Supported OSes out of the box are No OS, FreeRTOS, RT-Thread and Mynewt. On bare metal the queue still exists; there is simply no scheduler behind it.

Both stacks expose an extension point so you do not fork the project. On the device side, usbd_app_driver_get_cb() lets you write a class driver; on the host side, usbh_app_driver_get_cb() does the same. The README points to raspberrypi/pico-sdk#197 as an example of the RPi team adding a reset interface this way.

## Building the cdc_msc example: install and first run

The README does not give a copy-paste install command. It points to the online documentation at docs.tinyusb.org and to a Getting Started guide for adding TinyUSB to a project or building the examples. It also states that newcomers should start with the cdc_msc example, and that a handful of Supported Boards should work out of the box.

The examples directory ships both make and cmake build systems, and examples/CMakePresets.json is present in the repository, so CMake presets are the intended entry point for the CMake path. The README gives no clone command and no board variable, so the concrete starting points are the example directories themselves:

examples/device/cdc_msc

From there, the example's own build system takes over. Which make or cmake target applies is defined by the files in that directory, so read them before running anything. The result is a firmware image for a board whose name appears in the BSP directory listing. When flashed, the device enumerates as a composite CDC plus MSC device: a serial port and a mass storage volume appear on the host. That composite is the point of the example, because it exercises two class drivers, the descriptor set and the shared task function at once. If the serial port appears but the storage volume does not, the problem is in your board's BSP or clock configuration, not in the class drivers.

## Where TinyUSB is the wrong tool

Power Delivery is the clearest limitation. The README describes the PD stack as Power Delivery 3.0 with USB Type-C support, marks it work in progress, calls it super early stage, only for testing purpose, and states it supports only STM32 G4. If your product needs PD negotiation on any other part, this stack does not cover it today.

Video class 1.5 and DFU mode are both marked work in progress in the device class list. Treat them as unfinished rather than shipping features.

Host support is real but limited in breadth. If you need to drive a USB device class that is not CDC-ACM, the listed serial bridges, HID, MSC, MIDI or a hub, you are writing a host class driver through usbh_app_driver_get_cb() yourself.

The supported CPU table is the other hard boundary. It is a table of manufacturers and families with Device, Host, Highspeed and Driver columns, and a family that is absent from it is not supported. The README also notes that Mynewt examples are better kept in a separate repository because of the newt package build system, so that integration path is not inside this tree.

Finally, the no-dynamic-allocation design is a constraint as well as a feature. All buffers are static, so buffer sizing is a compile-time decision and the stack's RAM footprint is fixed by configuration rather than growing on demand.

## TinyUSB against CherryUSB and vendor USB stacks

The alternative that comes up most often is CherryUSB, and the difference is mostly in how the two projects organize portability and OS integration. TinyUSB keeps a hw/mcu tree of low level MCU core and peripheral drivers inside the repository and lists supported OSes as No OS, FreeRTOS, RT-Thread and Mynewt, with RT-Thread support also available through a separate package repository. A competing stack makes its own choices about which OS abstraction it ships and how much peripheral code lives in-tree, so the comparison you should actually run is whether your specific MCU and RTOS combination is already present.

Vendor stacks are the other alternative, and the trade-off is the opposite one. A silicon vendor's USB stack is typically tied to that vendor's peripherals and toolchain, so it will fit one family well and give you nothing when you add a second MCU vendor to the product line. TinyUSB's 50+ family claim is the reason to accept its abstraction layer and its central event queue. If your product will only ever use one MCU family, the vendor stack is less machinery to learn; if you expect to port, the vendor stack is the one that costs you a rewrite.

## Maintenance, licensing and what upgrading costs

The repository is not archived, and the last push was on 2026-09-21. Recent releases are 0.21.0 on 2026-06-30, 0.20.0 on 2025-11-20 and 0.19.0 on 2025-10-06. That cadence suggests releases arrive a few times a year rather than continuously, so pinning a tag and reading the release notes before moving is a reasonable posture.

The project is MIT licensed, with the LICENSE file at the repository root and a LICENSES/ directory alongside it. MIT is permissive, so the usual obligation is preserving the copyright and licence text in what you distribute. The LICENSES/ directory matters for anything vendored under lib/, such as FreeRTOS and FatFs, because those carry their own terms. That is a description of the repository layout, not legal advice; check the licence files for the components you actually ship.

Upgrade cost concentrates in two places. First, the porting layer: hw/mcu and hw/bsp code is where a stack update meets your board, so a board that is not upstreamed means re-applying local changes at each upgrade. Second, the class drivers you wrote through usbd_app_driver_get_cb() or usbh_app_driver_get_cb(); those callbacks are your code and will not be fixed by a release. The version.yml file at the repository root is the place to check what the tree considers its current version.

## Conclusion

Adopt TinyUSB when you need a USB device or host class on a supported MCU and cannot afford a heap: the static-buffer and deferred-ISR design is the whole point, and the cdc_msc example is the fastest way to confirm your board works. Do not adopt it if you need Power Delivery beyond STM32 G4 (the README labels that stack super early stage and testing only), or if your MCU is not in the supported CPU table. Before committing, verify your specific MCU family appears in that table with the Device or Host column marked, and check whether the class you need is listed as work in progress.

## FAQ

### Is TinyUSB thread safe?

The README states that TinyUSB is completely thread-safe because it pushes all Interrupt Service Request events into a central queue and processes them later in the non-ISR context task function, and because it uses semaphore/mutex for shared resources such as the CDC FIFO. That design requires some OS primitives, and the supported OSes out of the box are No OS, FreeRTOS, RT-Thread and Mynewt.

### Which devices are supported by TinyUSB?

The README claims support for 50+ MCU families and includes a supported CPU table listing manufacturers and families with Device, Host, Highspeed and Driver columns, such as Allwinner F1C100s/F1C200s and the Analog MAX3421E host controller over SPI. A family that is not in that table is not supported without porting.

### How do I enable USB host mode in TinyUSB?

Host support is a separate stack in the same repository, with its own class list: CDC-ACM, vendor serial over FTDI, CP210x, CH34x and PL2303, HID, MSC, MIDI, and hubs with multiple-level support. Whether your board can act as a host depends on the Host column for its family in the supported CPU table, so check that table first.

### What is TinyUSB CDC?

CDC is the Communication Device Class, one of the device classes TinyUSB implements, and the README also lists CDC-ACM on the host side. The README's recommended first example, cdc_msc, combines CDC with Mass Storage so a single board enumerates as both a serial port and a storage volume.

### How do I use TinyUSB with ESP-IDF?

The README does not document an ESP-IDF integration path. It points to the online documentation at docs.tinyusb.org and the Getting Started guide for adding TinyUSB to a project, and lists No OS, FreeRTOS, RT-Thread and Mynewt as the OSes supported out of the box.

### How does TinyUSB differ from CherryUSB?

The README does not compare TinyUSB with CherryUSB. What it does describe is TinyUSB's own portability structure: a hw/mcu tree of low level MCU core and peripheral drivers, a hw/bsp tree of board sources, and out-of-the-box support for No OS, FreeRTOS, RT-Thread and Mynewt. Compare that against CherryUSB's own OS and porting choices for your MCU.

## Sources

- [hathach/tinyusb on GitHub](https://github.com/hathach/tinyusb)
- [License: MIT](https://github.com/hathach/tinyusb/blob/master/LICENSE)
- [Project website](https://www.tinyusb.org)
- [README](https://github.com/hathach/tinyusb/blob/master/README.md)
- [Releases](https://github.com/hathach/tinyusb/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/hathach-tinyusb
