************ 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**: Most USB protocol handling occurs in task context; see :doc:`concurrency` for the device class ``sof()`` and ``xfer_isr()`` exceptions - **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
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**: Most application callbacks executed in task context; ``*_isr`` callbacks usually run in interrupt context (see :doc:`class/device`) .. 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 on transfer completion, usually from USB ISR context but possibly in the context of the call that arms the endpoint. 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 queued USB events are processed in task context, where most application callbacks also execute; callbacks named ``*_isr`` usually run in interrupt context (see :doc:`class/device`). 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