espressif/esp_tinyusb

2.0.0-rc0

Pre-release
uploaded 22 hours ago
Espressif's additions to TinyUSB

readme

# Espressif's Additions to TinyUSB

[![Component Registry](https://components.espressif.com/components/espressif/esp_tinyusb/badge.svg)](https://components.espressif.com/components/espressif/esp_tinyusb)

This component extends TinyUSB with features that simplify integration into ESP-IDF applications.

It provides both default and customizable configurations for TinyUSB, enabling USB device functionality on ESP chips with USB-OTG support.

### Run-time configuration

During configuration, the following parameters can be set when installing the driver:

- Descriptors
- Peripheral port
- Task parameters (size, priority, and CPU affinity)
- USB PHY parameters

### Default configuration

Run-time default configuration for Device Stack is managed internally via the `TINYUSB_DEFAULT_CONFIG()` macros.

### Custom configuration

Manual configuration for Device Stack: descriptors, peripheral port, task, and USB PHY parameters can be set as needed.

### Build-Time configuration

Configure the Device Stack using `menuconfig`:

- TinyUSB log verbosity
- Default device/string descriptor used by the default configuration macros
- Class-specific options (CDC-ACM, MSC, MIDI, HID, DFU, BTH, ECM/NCM/RNDIS, Vendor etc.)

### Supported classes

- USB Serial Device (CDC-ACM) with optional Virtual File System support.
- Input and output streams through the USB Serial Device (available only when Virtual File System support is enabled).
- Mass Storage Device Class (MSC): create USB flash drives using SPI Flash or SD/MMC as storage media.
- Support for other USB classes (MIDI, HID, etc.) directly via TinyUSB.

## How to use?

This component is distributed via [IDF component manager](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-component-manager.html). Just add `idf_component.yml` file to your main component with the following content:

``` yaml
## IDF Component Manager Manifest File
dependencies:
  esp_tinyusb: "~2.0.0"
```

Or simply run:
```
idf.py add-dependency esp_tinyusb~2.0.0
```

## Breaking changes

- [v2.0.0](https://docs.espressif.com/projects/esp-usb/docs/device/migration-guide/v2)

## USB Device Stack: usage, installation & configuration

Hardware-related documentation can be found in the [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/api-reference/peripherals/usb_device.html).

### Structure overview

The Device Stack is built on top of TinyUSB and provides:

- Custom USB descriptor support
- Serial device (CDC-ACM) support
- Standard stream redirection through the serial device
- Storage media support (SPI Flash and SD Card) for the USB MSC class
- A dedicated task for TinyUSB servicing

### Installation

Install the Device Stack by calling `tinyusb_driver_install` with a `tinyusb_config_t` structure.

A default configuration is available using the `TINYUSB_DEFAULT_CONFIG()` macro.

The default installation automatically configures the port (High-speed if supported by the hardware, otherwise Full-speed), task (with default parameters), USB PHY, Device Event callback and descriptors.

Default descriptors are provided for the following USB classes: CDC, MSC, and NCM.

> **⚠️ Important:** For demonstration purposes, all error handling logic has been removed from the code examples. Do not ignore proper error handling in actual development.

```c
  #include "tinyusb_default_config.h"

  void main(void) {
    const tinyusb_config_t tusb_cfg = TINYUSB_DEFAULT_CONFIG();
    tinyusb_driver_install(&tusb_cfg);
  }
```

### Device Event callback

USB Device Event callback allows to get the following events during USB Device lifecycle:

- `TINYUSB_EVENT_ATTACHED`: Device attached to the USB Host
- `TINYUSB_EVENT_DETACHED`: Device detached from the USB Host

To configure the USB Device Event Callback, provide the callback to the `TINYUSB_DEFAULT_CONFIG()` macros:

```c
  #include "tinyusb_default_config.h"

  static void device_event_handler(tinyusb_event_t *event, void *arg)
  {
    switch (event->id) {
    case TINYUSB_EVENT_ATTACHED:
    case TINYUSB_EVENT_DETACHED:
    default:
        break;
    }
  }

  void main(void) {
    const tinyusb_config_t tusb_cfg = TINYUSB_DEFAULT_CONFIG(device_event_handler);
    tinyusb_driver_install(&tusb_cfg);
  }
```

User Argument could be passed to the USB Device Event callback as a second argument (optional):

```c
  #include "tinyusb_default_config.h"

  static context_t *context;

  static void device_event_handler(tinyusb_event_t *event, void *arg)
  {
    context_t *context = (context_t*) arg;

    switch (event->id) {
    case TINYUSB_EVENT_ATTACHED:
    case TINYUSB_EVENT_DETACHED:
    default:
        break;
    }
  }

  void main(void) {
    const tinyusb_config_t tusb_cfg = TINYUSB_DEFAULT_CONFIG(device_event_handler, (void*) context);
    tinyusb_driver_install(&tusb_cfg);
  }
```

### Peripheral port

When several peripheral ports are available by the hardware, the specific port could be configured manually:

```c
  #include "tinyusb_default_config.h"

  void main(void) {
    tinyusb_config_t tusb_cfg = TINYUSB_DEFAULT_CONFIG();
#if (TUD_OPT_HIGH_SPEED)
    tusb_cfg.port = TINYUSB_PORT_HIGH_SPEED_0;
#else
    tusb_cfg.port = TINYUSB_PORT_FULL_SPEED_0;
#endif
    tinyusb_driver_install(&tusb_cfg);
  }
```

### Task configuration

When the default parameters of the internal task should be changed:

```c
  #include "tinyusb_default_config.h"

  void main(void) {
    tinyusb_config_t tusb_cfg = TINYUSB_DEFAULT_CONFIG();
    tusb_cfg.task = TINYUSB_TASK_CUSTOM(4096 /*size */, 4 /* priority */, 0 /* affinity: 0 - CPU0, 1 - CPU1 ... */);
    tinyusb_driver_install(&tusb_cfg);
  }
```

### USB Descriptors configuration

Configure USB descriptors using the `tinyusb_config_t` structure:

- `descriptor.device`
- `descriptor.string`
- `descriptor.full_speed_config`
- `descriptor.high_speed_config`
- `descriptor.qualifier`

If any descriptor field is set to `NULL`, default descriptor will be assigned during installation.
Values of default descriptors could be configured via `menuconfig`.

```c
  #include "tinyusb_default_config.h"

  void main(void) {
    tinyusb_config_t tusb_cfg = TINYUSB_DEFAULT_CONFIG();

    tusb_cfg.descriptor.device = &custom_device_descriptor;
    tusb_cfg.descriptor.full_speed_config = custom_full_speed_configuration;
#if (TUD_OPT_HIGH_SPEED)
    tusb_cfg.descriptor.high_speed_config = custom_high_speed_configuration;
#endif // TUD_OPT_HIGH_SPEED

    tinyusb_driver_install(&tusb_cfg);
  }
```

### USB PHY configuration & Self-Powered Device

For self-powered devices, monitoring the VBUS voltage is required. To do this:

- Configure a GPIO pin as an input, using an external voltage divider or comparator to detect the VBUS state.
- Set `self_powered = true` and assign the VBUS monitor GPIO in the `tinyusb_config_t` structure.

```c
  #include "tinyusb_default_config.h"

  void main(void)
  {
    tinyusb_config_t tusb_cfg = TINYUSB_DEFAULT_CONFIG();

    tusb_cfg.phy.self_powered = true;
    tusb_cfg.phy.vbus_monitor_io = GPIO_NUM_0;

    tinyusb_driver_install(&tusb_cfg);
  }
```
If external PHY is used:

```c
  #include "tinyusb_default_config.h"
  #include "esp_private/usb_phy.h"

  void main(void)
  {
    // Initialize the USB PHY externally
    usb_new_phy(...);

    tinyusb_config_t tusb_cfg = TINYUSB_DEFAULT_CONFIG();

    tusb_cfg.phy.skip_setup = true;

    tinyusb_driver_install(&tusb_cfg);
  }
```

## USB Device Classes: usage, installation & configuration

### USB Serial Device (CDC-ACM)

To enable USB Serial Device:

- select the option from `menuconfig`.
- initialize the USB Serial Device with `tusb_cdc_acm_init` and a `tinyusb_config_cdcacm_t` structure

```c
const tinyusb_config_cdcacm_t acm_cfg = {
  .cdc_port = TINYUSB_CDC_ACM_0,
  .rx_unread_buf_sz = 64,
  .callback_rx = NULL,
  .callback_rx_wanted_char = NULL,
  .callback_line_state_changed = NULL,
  .callback_line_coding_changed = NULL
};
tusb_cdc_acm_init(&acm_cfg);
```

Redirect standard I/O streams to USB with `esp_tusb_init_console` and revert with `esp_tusb_deinit_console`.

### USB Mass Storage Device (MSC)

To enable Mass Storage Device:

- select the option from `menuconfig`
- configure storage for MSC Device class: SPI Flash or SD/MMC (when supported by the hardware).

**SPI-Flash Storage**

```c
static wl_handle_t storage_init_spiflash(void)
{
  wl_handle_t wl;
  // Find partition
  // Mount Wear Levelling
  return wl;
}

void main(void)
{
  wl_handle_t wl_handle = storage_init_spiflash();

  tinyusb_msc_storage_handle_t storage_hdl;
  const tinyusb_msc_storage_config_t cfg = {
    .medium.wl_handle = wl_handle,
  };
  tinyusb_msc_new_storage_spiflash(&cfg, &storage_hdl);
}
```

**SD-Card Storage**

```c
static sdmmc_card_t *storage_init_sdmmc(void)
{
  sdmmc_card_t *card;
  // Config sdmmc
  // Init sdmmc_host
  // Init sdmmc slot
  // Init sdmmc card
  return card;
}

void main(void)
{
  sdmmc_card_t *card = storage_init_sdmmc();

  tinyusb_msc_storage_handle_t storage_hdl;
  const tinyusb_msc_storage_config_t cfg = {
    .medium.card = card,
  };
  tinyusb_msc_new_storage_sdmmc(&cfg, &storage_hdl);
}
```

**Storage callback**

Storage event callback is called, when one of the following events occurred:
- `TINYUSB_MSC_EVENT_MOUNT_START`: Start mount from APP to USB or from USB to APP
- `TINYUSB_MSC_EVENT_MOUNT_COMPLETE`: Complete mount from USB to APP or from APP to USB
- `TINYUSB_MSC_EVENT_FORMAT_REQUIRED`: Filesystem not found, format needed
- `TINYUSB_MSC_EVENT_MOUNT_FAILED`: Error occurred during mounting filesystem

To use or enable storage callback there are two options available.

Set the callback with specific call after creating the storage:

```c
static void storage_event_handle(tinyusb_msc_storage_handle_t handle, tinyusb_msc_event_t *event, void *arg)
{
    switch (event->id) {
      case TINYUSB_MSC_EVENT_MOUNT_START:
      case TINYUSB_MSC_EVENT_MOUNT_COMPLETE:
      case TINYUSB_MSC_EVENT_MOUNT_FAILED:
      case TINYUSB_MSC_EVENT_FORMAT_REQUIRED:
    default:
        break;
    }
}

void main(void)
{
  sdmmc_card_t *card = storage_init_sdmmc();

  tinyusb_msc_storage_handle_t storage_hdl;
  const tinyusb_msc_storage_config_t cfg = {
    .medium.card = card,
  };
  tinyusb_msc_new_storage_sdmmc(&cfg, &storage_hdl);
  tinyusb_msc_set_storage_callback(storage_event_handle, NULL /* user argument for the event callback */);
}
```

Install the TinyUSB MSC Storage driver explicitly and provide the storage event via configuration:

```c
void main(void)
{
  sdmmc_card_t *card = storage_init_sdmmc();

  const tinyusb_msc_driver_config_t driver_cfg = {
    .storage_event_cb = storage_event_handle,
    .storage_event_arg = NULL /* user argument for the storage event callback */,
  };
  tinyusb_msc_install_driver(&driver_cfg);

  tinyusb_msc_storage_handle_t storage_hdl;
  const tinyusb_msc_storage_config_t cfg = {
    .medium.card = card,
  };
  tinyusb_msc_new_storage_sdmmc(&cfg, &storage_hdl);
}
```

### MSC Performance Optimization

- **Single-buffer approach:** Buffer size is set via `CONFIG_TINYUSB_MSC_BUFSIZE`.
- **Performance:** SD cards offer higher throughput than internal SPI flash due to architectural constraints.

**Performance Table (ESP32-S3):**

| FIFO Size | Read Speed | Write Speed |
|-----------|------------|-------------|
| 512 B     | 0.566 MB/s | 0.236 MB/s  |
| 8192 B    | 0.925 MB/s | 0.928 MB/s  |

**Performance Table (ESP32-P4):**

| FIFO Size | Read Speed | Write Speed |
|-----------|------------|-------------|
| 512 B     | 1.174 MB/s | 0.238 MB/s  |
| 8192 B    | 4.744 MB/s | 2.157 MB/s  |
| 32768 B   | 5.998 MB/s | 4.485 MB/s  |

**Performance Table (ESP32-S2, SPI Flash):**

| FIFO Size | Write Speed |
|-----------|-------------|
| 512 B     | 5.59 KB/s   |
| 8192 B    | 21.54 KB/s  |

**Note:** Internal SPI flash is for demonstration only; use SD cards or external flash for higher performance.

## Examples
You can find examples in [ESP-IDF on GitHub](https://github.com/espressif/esp-idf/tree/master/examples/peripherals/usb/device).

Links

Supports all targets

License: Apache-2.0

To add this component to your project, run:

idf.py add-dependency "espressif/esp_tinyusb^2.0.0-rc0"

or download archive

Stats

  • Archive size
    Archive size ~ 123.16 KB
  • Downloaded in total
    Downloaded in total 267.0k times
  • Downloaded this version
    This version: 0 times

Badge

espressif/esp_tinyusb version: 2.0.0-rc0
|