summaryrefslogtreecommitdiff
path: root/docs/reference/architecture.rst
blob: 70ea17ed452b969ba4da9802eb5e8f94dec64a29 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
************
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