| ************ |
| Architecture |
| ************ |
| |
| This document explains TinyUSB's internal architecture, design principles, and how different components work together. |
| |
| Design Principles |
| ================= |
| |
| Memory Safety |
| ------------- |
| |
| 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. |
| |
| Thread Safety |
| ------------- |
| |
| TinyUSB achieves thread safety through a deferred interrupt model: |
| |
| - **ISR deferral**: USB interrupts are captured and deferred to task context |
| - **Single-threaded processing**: All USB protocol handling occurs in task context |
| - **Queue-based design**: Events are queued from ISR and processed in ``tud_task()`` |
| - **RTOS integration**: Proper semaphore/mutex usage for shared resources |
| |
| Portability |
| ----------- |
| |
| The stack is designed to work across diverse microcontroller families: |
| |
| - **Hardware abstraction**: MCU-specific code isolated in portable drivers |
| - **OS abstraction**: RTOS dependencies isolated in OSAL layer |
| - **Modular design**: Features can be enabled/disabled at compile time |
| - **Standard compliance**: Strict adherence to USB specifications |
| |
| Core Architecture |
| ================= |
| |
| Layer Structure |
| --------------- |
| |
| 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> |
| |
| Component Overview |
| ------------------ |
| |
| - **Application Layer**: Your main application code that uses TinyUSB APIs. |
| - **Class Drivers**: Implement specific USB device classes (CDC, HID, MSC, etc.) and handle class-specific requests. |
| - **Device/Host Core**: Implements USB protocol state machines, endpoint management, and core USB functionality. |
| - **OS Abstraction**: Provides threading primitives and synchronization for different RTOS environments. |
| - **Device/Host Controller Driver**: drivers that interface with MCU USB peripherals. Several MCUs may share a common driver. |
| |
| Device Stack Architecture |
| ========================= |
| |
| This section is concerned with the **Device Stack**, i.e., the component of TinyUSB used in USB devices (that talk to a USB host). |
| |
| Core Components |
| --------------- |
| |
| **Device Controller Driver (DCD)**: |
| - MCU-specific USB device peripheral driver |
| - Handles endpoint configuration and data transfers |
| - Abstracts hardware differences between MCU families |
| - Located in ``src/portable/VENDOR/USBIP/`` |
| |
| **USB Device Core (USBD)**: |
| - Implements USB device state machine |
| - Handles standard USB requests (Chapter 9) |
| - Manages device configuration and enumeration |
| - Located in ``src/device/`` |
| |
| **Class Drivers**: |
| - Implement USB class specifications |
| - Handle class-specific requests and data transfer |
| - Provide application APIs |
| - Located in ``src/class/*/`` |
| |
| Data Flow |
| --------- |
| |
| **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 |
| |
| Event Processing |
| ---------------- |
| |
| TinyUSB uses a deferred interrupt model for thread safety: |
| |
| 1. **Interrupt Occurs**: USB hardware generates interrupt |
| 2. **ISR Handler**: ``dcd_int_handler()`` captures event, minimal processing |
| 3. **Event Queuing**: Events queued for later processing |
| 4. **Task Processing**: ``tud_task()`` (called by application code) processes queued events |
| 5. **Callback Execution**: Application callbacks executed in task context |
| |
| .. code-block:: none |
| |
| USB IRQ → ISR → Event Queue → tud_task() → Class Callbacks → Application |
| |
| Host Stack Architecture |
| ======================= |
| |
| This section is concerned with the **Host Stack**, i.e., the component of TinyUSB used in USB hosts, managing connected USB devices. |
| |
| Core Components |
| --------------- |
| |
| **Host Controller Driver (HCD)**: |
| - MCU-specific USB host peripheral driver |
| - Manages USB pipes and data transfers |
| - Handles host controller hardware |
| - Located in ``src/portable/VENDOR/FAMILY/`` |
| |
| **USB Host Core (USBH)**: |
| - Implements USB host functionality |
| - Manages device enumeration and configuration |
| - Handles pipe management and scheduling |
| - Located in ``src/host/`` |
| |
| **Hub Driver**: |
| - Manages USB hub devices |
| - Handles port management and device detection |
| - Supports multi-level hub topologies |
| - Located in ``src/host/`` |
| |
| Device Enumeration |
| ------------------ |
| |
| The host stack follows USB enumeration process: |
| |
| 1. **Device Detection**: Hub or root hub detects device connection |
| 2. **Reset and Address**: Reset device, assign unique address |
| 3. **Descriptor Retrieval**: Get device, configuration, and class descriptors |
| 4. **Driver Matching**: Find appropriate class driver for device |
| 5. **Configuration**: Configure device and start communication |
| 6. **Class Operation**: Normal class-specific communication |
| |
| .. code-block:: none |
| |
| Device Connect → Reset → Get Descriptors → Load Driver → Configure → Operate |
| |
| Class Architecture |
| ================== |
| |
| Common Class Structure |
| ---------------------- |
| |
| All USB classes follow a similar architecture: |
| |
| **Device Classes**: |
| - ``*_device.c``: Device-side implementation |
| - ``*_device.h``: Device API definitions |
| - Implement class-specific descriptors |
| - Handle class requests and data transfer |
| |
| **Host Classes**: |
| - ``*_host.c``: Host-side implementation |
| - ``*_host.h``: Host API definitions |
| - Manage connected devices of this class |
| - Provide application interface |
| |
| Class Driver Interface |
| ---------------------- |
| |
| See ``usbd.c``. |
| |
| **Required Functions**: |
| - ``init()``: Initialize class driver |
| - ``reset()``: Reset class state |
| - ``open()``: Configure class endpoints |
| - ``control_xfer_cb()``: Handle control requests |
| - ``xfer_cb()``: Handle data transfer completion |
| |
| **Optional Functions**: |
| - ``close()``: Clean up class resources |
| - ``deinit()``: Deinitialize class driver |
| - ``sof()``: Start-of-frame processing |
| - ``xfer_isr()``: Called from USB ISR context on transfer completion. Data will get queued for ``xfer_cb()`` only if this returns ``false``. |
| |
| Descriptor Management |
| --------------------- |
| |
| Each class is responsible for: |
| - **Interface Descriptors**: Define class type and endpoints |
| - **Class-Specific Descriptors**: Additional class requirements |
| - **Endpoint Descriptors**: Define data transfer characteristics |
| |
| Memory Management |
| ================= |
| |
| Static Allocation Model |
| ----------------------- |
| |
| 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. |
| |
| Buffer Management |
| ----------------- |
| |
| **Endpoint Buffers**: |
| - Allocated per endpoint at compile time |
| - Size defined by ``CFG_TUD_*_EP_BUFSIZE`` macros |
| - Used for USB data transfers |
| |
| **FIFO Buffers**: |
| - Ring buffers for streaming data |
| - Size defined by ``CFG_TUD_*_RX/TX_BUFSIZE`` macros |
| - Separate read/write pointers |
| |
| Threading Model |
| =============== |
| |
| Task-Based Design |
| ----------------- |
| |
| TinyUSB 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. |
| |
| RTOS Integration |
| ---------------- |
| |
| **Bare Metal**: |
| - Application calls ``tud_task()`` in main loop |
| - No threading primitives needed |
| - Simplest integration method |
| |
| **FreeRTOS**: |
| - USB task runs at high priority |
| - Semaphores used for synchronization |
| - Queue for inter-task communication |
| |
| **Other RTOS**: |
| - Similar patterns with RTOS-specific primitives |
| - OSAL layer abstracts RTOS differences |
| |
| Interrupt Handling |
| ------------------ |
| |
| **Interrupt Service Routine**: |
| - Minimal processing in ISR |
| - Event capture and queuing only |
| - Quick return to avoid blocking |
| |
| **Deferred Processing**: |
| - All complex processing in task context |
| - Thread-safe access to data structures |
| - Application callbacks in known context |
| |
| Memory Usage Patterns |
| --------------------- |
| |
| **Flash Memory**: |
| - Core stack: 8-15KB depending on features |
| - Each class: 1-4KB additional |
| - Portable driver: 2-8KB depending on MCU |
| |
| **RAM Usage**: |
| - Core stack: 1-2KB |
| - Endpoint buffers: User configurable |
| - Class buffers: Depends on configuration |