# TinyUSB

TinyUSB is an open-source cross-platform USB Host/Device stack for embedded
system, designed to be memory-safe with no dynamic allocation and thread-safe
with all interrupt events are deferred then handled in the non-ISR task
function.

This module provides a autogenerated port for TinyUSB, which includes the
correct interrupt mapping, a serial number based on the UID of the device,
as well as remapping the assertions of TinyUSB.


## Full vs High Speed Ports

Some microcontroller have USB peripherals capable of using external high speed
transceivers via an ULPI interface. TinyUSB can be configured to run device
and host classes on one port or both on separate ports at the same time.
You can configure this via these module options:

```xml
<option name="modm:tinyusb:device:port">fs</option>
<option name="modm:tinyusb:host:port">hs</option>
```

However, the high speed capable port can also run in full speed mode, in which
case you must configure TinyUSB to *not* use the ULPI interface:

```xml
<option name="modm:tinyusb:max-speed">full</option>
```


## Initializing USB

The `modm:platform:usb` module provides the correct way of initializing the USB
peripheral, however, you must connect the right signals too:

```cpp
// USB is timing-sensitive, so prioritize the IRQs accordingly
Usb::initialize<SystemClock>(/*priority=*/3);

// For Device-Only USB implementations, this is enough
Usb::connect<GpioA11::Dm, GpioA12::Dp>();

// But for On-The-Go (OTG) USB implementations, you need more:
Usb::connect<GpioA11::Dm, GpioA12::Dp, GpioA10::Id>();

// For high speed USB ports, you need to connect all ULPI signals:
UsbHs::connect<
		GpioA5::Ulpick,	GpioC0::Ulpistp, GpioC2::Ulpidir, GpioH4::Ulpinxt,
		GpioA3::Ulpid0, GpioB0::Ulpid1, GpioB1::Ulpid2, GpioB10::Ulpid3,
		GpioB11::Ulpid4, GpioB12::Ulpid5, GpioB13::Ulpid6, GpioB5::Ulpid7>();
```

Note that depending on your specific hardware setup, you may need to fiddle
around to find the right VBus sensing mechanism. Please look at the TinyUSB
board definitions and examples for inspiration.

```cpp
// Enable hardware Vbus sensing on GpioA9 (this can be tricky to get right!)
USB_OTG_FS->GCCFG |= USB_OTG_GCCFG_VBDEN;
```

!!! warning "USB shares resources with CAN"
	Note that on STM32F1 and STM32F3 the USB interrupts and RAM are shared with CAN,
	thus there are conflicts in IRQ definitions as well as resource limitions in
	hardware. On some STM32F3, the USB IRQs can be remapped, this is done
	automatically by our port.


## Autogeneration of USB Descriptors

You can select the device classes you want to use via the `modm:tinyusb:config`
list option:

- `device.cdc`: Serial connection (uses **two** endpoints!)
- `device.msc`: Mass Storage class.
- `device.midi`: MIDI device.
- `device.vendor`: WebUSB device.
- `device.dfu_rt`: DFU runtime.

Note that you can add multiple devices at the same time, as long as there are
enough endpoints and USB RAM available:

```xml
<!-- Using the CDC and MSC classes together -->
<option name="modm:tinyusb:config">device.cdc,device.msc</option>
<!-- Using two CDC ports! -->
<option name="modm:tinyusb:config">device.cdc,device.cdc</option>
```

modm will generate the USB descriptors automatically for the set of device
classes you've chosen. You can then implement your app via TinyUSB callbacks.


### Partial Customization

You can overwrite or add configurations via a `<tusb_config_local.h>` file,
which will be included at the very *beginning* of the modm-generated
`tusb_config.h` file:

```c
// Overwrite the modm default
#define CFG_TUD_CDC_TX_BUFSIZE 1024
// Overwrite the TinyUSB default
#define CFG_TUD_CDC_EP_BUFSIZE 1024
```

You can also replace the following weakly linked descriptor functions and
objects in case you want to update only a small part of the autogenerated
descriptors:

- `const uint8_t* tud_descriptor_device_cb(void)` to replace the autogenerated
  `tusb_desc_device_t` descriptor.
- `const uint8_t* tud_descriptor_configuration_cb(uint8_t index)` to replace
  the endpoint descriptions.
- `const char* tud_string_desc_arr[]` to replace the string descriptors.
- `const uint16_t* tud_descriptor_string_cb(uint8_t index, uint16_t langid)`


## Manual USB Descriptors

If you leave the `modm:tinyusb:config` option empty, no descriptors are
generated, so you can implement them yourself. Note that you must also
manually depend on the device classes you want to implement:

```xml
<module>modm:tinyusb:device:audio</module>
<module>modm:tinyusb:device:bth</module>
<module>modm:tinyusb:device:cdc</module>
<module>modm:tinyusb:device:dfu</module>
<module>modm:tinyusb:device:dfu_rt</module>
<module>modm:tinyusb:device:ecm_rndis</module>
<module>modm:tinyusb:device:hid</module>
<module>modm:tinyusb:device:midi</module>
<module>modm:tinyusb:device:msc</module>
<module>modm:tinyusb:device:ncm</module>
<module>modm:tinyusb:device:usbtmc</module>
<module>modm:tinyusb:device:vendor</module>
<module>modm:tinyusb:device:video</module>
```

Some of these classes require a lot of configuration that you must provide via
the `<tusb_config_local.h>` file. Please consult the TinyUSB documentation and
examples for their purpose.


## Host classes

To use the host classes you must depend on them manually as modm does not
provide a configuration option for them:

```xml
<module>modm:tinyusb:host:cdc</module>
<module>modm:tinyusb:host:cdc_rndis</module>
<module>modm:tinyusb:host:hid</module>
<module>modm:tinyusb:host:msc</module>
<module>modm:tinyusb:host:vendor</module>
```


## Debugging TinyUSB

Since we've made it so easy to add multiple device classes, it's also easy to
run out of endpoints or RAM. Therefore we reroute TinyUSBs assertions to
`modm_assert`, so make sure you have implemented the `modm_abandon` handler!
See the `modm:architecture:assert` module for details.

A TinyUSB assertion failure in release mode is fairly cryptic:

```
Assertion 'tu' failed!
Abandoning...
```

If you run this again in debug mode, you'll note a much more detailed assertion
description. In this example you've exhaused the number of endpoints:

```
Assertion 'tu' failed!
  modm/ext/tinyusb/portable/st/synopsys/dcd_synopsys.c:524 -> "epnum < 4U"
Abandoning...
```

To trace the TinyUSB core, you can add `CFG_TUSB_DEBUG=3` to your CPP flags and
the output will be forwarded to `MODM_LOG_DEBUG`.

```
<collect name="modm:build:cppdefines">CFG_TUSB_DEBUG=3</collect>
```
