docs/reference/architecture.rst
Architecture
This document explains TinyUSB's internal architecture, design principles, and how different components work together.
TinyUSB is designed for resource-constrained embedded systems with strict memory requirements:
TinyUSB uses no dynamic allocation - all memory is statically allocated at compile time for predictability. All buffers have bounded, compile-time defined sizes to prevent overflow issues. The TinyUSB core avoids heap allocation, resulting in predictable memory usage where consumption is fully deterministic.
TinyUSB achieves thread safety through a deferred interrupt model:
tud_task()The stack is designed to work across diverse microcontroller families:
TinyUSB follows a layered architecture from hardware to application:
.. figure:: ../assets/stack.svg :width: 500px :align: left :alt: stackup
.. raw:: html
<div class="clear-both"></div>This section is concerned with the Device Stack, i.e., the component of TinyUSB used in USB devices (that talk to a USB host).
Device Controller Driver (DCD):
src/portable/VENDOR/USBIP/USB Device Core (USBD):
src/device/Class Drivers:
src/class/*/Control Transfers (Setup Requests):
.. code-block:: none
USB Bus → DCD → USBD Core → Class Driver → Application ↓ Standard requests handled in core ↓ Class-specific requests → Class Driver
Data Transfers:
.. code-block:: none
Application → Class Driver → USBD Core → DCD → USB Bus USB Bus → DCD → USBD Core → Class Driver → Application
TinyUSB uses a deferred interrupt model for thread safety:
dcd_int_handler() captures event, minimal processingtud_task() (called by application code) processes queued events.. code-block:: none
USB IRQ → ISR → Event Queue → tud_task() → Class Callbacks → Application
This section is concerned with the Host Stack, i.e., the component of TinyUSB used in USB hosts, managing connected USB devices.
Host Controller Driver (HCD):
src/portable/VENDOR/FAMILY/USB Host Core (USBH):
src/host/Hub Driver:
src/host/The host stack follows USB enumeration process:
.. code-block:: none
Device Connect → Reset → Get Descriptors → Load Driver → Configure → Operate
All USB classes follow a similar architecture:
Device Classes:
*_device.c: Device-side implementation*_device.h: Device API definitionsHost Classes:
*_host.c: Host-side implementation*_host.h: Host API definitionsSee usbd.c.
Required Functions:
init(): Initialize class driverreset(): Reset class stateopen(): Configure class endpointscontrol_xfer_cb(): Handle control requestsxfer_cb(): Handle data transfer completionOptional Functions:
close(): Clean up class resourcesdeinit(): Deinitialize class driversof(): Start-of-frame processingxfer_isr(): Called from USB ISR context on transfer completion. Data will get queued for xfer_cb() only if this returns false.Each class is responsible for:
TinyUSB uses only static memory allocation; it allocates fixed-size endpoint buffers for each configured endpoint, static buffers for class-specific data handling, a fixed buffer dedicated to control transfers, and static event queues for deferred interrupt processing.
Endpoint Buffers:
CFG_TUD_*_EP_BUFSIZE macrosFIFO Buffers:
CFG_TUD_*_RX/TX_BUFSIZE macrosTinyUSB uses a cooperative task model; it provides main tasks - tud_task() for device and tuh_task() for host operation. These tasks must be called regularly (typically less than 1ms intervals) to ensure all USB events are processed in task context, where application callbacks also execute.
Bare Metal:
tud_task() in main loopFreeRTOS:
Other RTOS:
Interrupt Service Routine:
Deferred Processing:
Flash Memory:
RAM Usage: