Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions device/esp_tinyusb/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## [Unreleased]

- esp_tinyusb: Added possibility to select blocking time for dedicated TinyUSB task

## 2.0.1~1

- esp_tinyusb: Claim forward compatibility with TinyUSB 0.19
Expand Down
24 changes: 24 additions & 0 deletions device/esp_tinyusb/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,30 @@ When the default parameters of the internal task should be changed:
}
```

When your app calls `tinyusb_driver_uninstall()`, the driver cleanly stops the internal TinyUSB task. To make the start/stop points deterministic (so your code knows when the task is fully started or stopped), the driver exposes a blocking timeout for the TinyUSB task loop.

This timeout is the maximum time (ms) the TinyUSB task may block while waiting for or servicing USB events. It is not a polling interval.

> **Note:** Default timeout values may differ per CPU/target to match CPU load observed in legacy (block-forever) mode versus non-blocking mode.
To re-enable legacy behavior (block indefinitely), set `blocking_timeout_ms` to `UINT32_MAX`.

You can configure the timeout during driver installation:

```c
#include "tinyusb_default_config.h"

void main(void) {
tinyusb_config_t tusb_cfg = TINYUSB_DEFAULT_CONFIG();
tusb_cfg.task.blocking_timeout_ms = 3000;
tinyusb_driver_install(&tusb_cfg);

// ...

tinyusb_driver_uninstall(); // will stop deterministically within ~blocking_timeout_ms
}
```
> **💡 Tip:** If you need very low CPU usage and don’t care about stop latency, use a larger value (hundreds or thousands of ms). If you need quick teardown (e.g., switching roles or remounting), keep this small.

### USB Descriptors configuration

Configure USB descriptors using the `tinyusb_config_t` structure:
Expand Down
13 changes: 13 additions & 0 deletions device/esp_tinyusb/include/tinyusb.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,19 @@ typedef struct {
size_t size; /*!< USB Device Task size. */
uint8_t priority; /*!< USB Device Task priority. */
int xCoreID; /*!< USB Device Task core affinity. */
uint32_t blocking_timeout_ms; /*!< USB Device Task blocking timeout in milliseconds.
This feature is used to control the behavior of the tud_task_ext() function called
inside the dedicated TinyUSB task. The timeout defines how long the tud_task_ext() function
will block waiting for USB events and how frequently the driver will poll for the uninstall notififcation.
If tinyusb_driver_uninstall() is not used, the blocking timeout can block indefinitely to reduce CPU usage.

Values:
0 - non-blocking mode.
UINT_MAX - blocks indefinetely (legacy mode).

Default value: 1000 ms.
*/

} tinyusb_task_config_t;

/**
Expand Down
28 changes: 28 additions & 0 deletions device/esp_tinyusb/include/tinyusb_default_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ extern "C" {
#define TINYUSB_DEFAULT_TASK_SIZE 4096
// Default priority for task used in TinyUSB task creation
#define TINYUSB_DEFAULT_TASK_PRIO 5
// Default blocking timeout_ms for tud_task_ext(timeout_ms, false), depending on target to acieve similar CPU load
#if CONFIG_IDF_TARGET_ESP32P4
#define TINYUSB_DEFAULT_BLOCK_TIME_MS 1000
#else
#define TINYUSB_DEFAULT_BLOCK_TIME_MS 2000
#endif // CONFIG_IDF_TARGET_ESP32P4

#define TINYUSB_CONFIG_FULL_SPEED(event_hdl, arg) \
(tinyusb_config_t) { \
Expand Down Expand Up @@ -111,13 +117,16 @@ extern "C" {
.size = TINYUSB_DEFAULT_TASK_SIZE, \
.priority = TINYUSB_DEFAULT_TASK_PRIO, \
.xCoreID = TINYUSB_DEFAULT_TASK_AFFINITY, \
.blocking_timeout_ms = TINYUSB_DEFAULT_BLOCK_TIME_MS,\
}

/**
* @brief TinyUSB Task configuration structure initializer
*
* This macro is used to create a custom TinyUSB Task configuration structure.
*
* Note: blocking_timeout_ms is set to default value.
*
* @param s Stack size of the task
* @param p Task priority
* @param a Task affinity (CPU core)
Expand All @@ -127,6 +136,25 @@ extern "C" {
.size = (s), \
.priority = (p), \
.xCoreID = (a), \
.blocking_timeout_ms = TINYUSB_DEFAULT_BLOCK_TIME_MS, \
}

/**
* @brief TinyUSB Task configuration structure initializer
*
* This macro is used to create a custom TinyUSB Task configuration structure.
*
* @param s Stack size of the task
* @param p Task priority
* @param a Task affinity (CPU core)
* @param t Blocking timeout in milliseconds for tud_task_ext() function
*/
#define TINYUSB_TASK_CUSTOM_NON_BLOCKING(s, p, a, t) \
(tinyusb_task_config_t) { \
.size = (s), \
.priority = (p), \
.xCoreID = (a), \
.blocking_timeout_ms = (t), \
}

#ifdef __cplusplus
Expand Down
88 changes: 87 additions & 1 deletion device/esp_tinyusb/test_apps/runtime_config/main/test_cpu_load.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ static void test_cpu_load_measure(void)
* - uninstall driver
* - show results
*/
TEST_CASE("[CPU load] Install & Uninstall, default configuration", "[cpu_load]")
TEST_CASE("[CPU load] Install & Uninstall, default blocking task", "[cpu_load]")
{
#if (!CONFIG_FREERTOS_UNICORE)
// Allow other core to finish initialization
Expand Down Expand Up @@ -178,4 +178,90 @@ TEST_CASE("[CPU load] Install & Uninstall, default configuration", "[cpu_load]")
printf("TinyUSB CPU load: %" PRIu32 " %%\n", _tinyusb_cpu_load);
}

/**
* @brief Test TinyUSB CPU load measurement
*
* Scenario:
* - Install TinyUSB driver with default configuration
* - wait for device connection
* - measure CPU load
* - uninstall driver
* - show results
*/
TEST_CASE("[CPU load] Install & Uninstall, non-blocking task", "[cpu_load]")
{
#if (!CONFIG_FREERTOS_UNICORE)
// Allow other core to finish initialization
vTaskDelay(pdMS_TO_TICKS(100));
#endif // (!CONFIG_FREERTOS_UNICORE)

// Install TinyUSB driver
tinyusb_config_t tusb_cfg = TINYUSB_DEFAULT_CONFIG(test_device_event_handler);
// Set the task blocking timeout to 0: non-blocking
tusb_cfg.task.blocking_timeout_ms = 0;

TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_install(&tusb_cfg));

// Initialize CPU load measurement
test_cpu_load_init();

// Wait for the device to be mounted and enumerated by the Host
test_device_wait();
printf("\t -> Device connected\n");

// Measure CPU load
test_cpu_load_measure();

// Uninstall TinyUSB driver
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall());

// Show results
printf("TinyUSB Run time: %" PRIu32 " ticks\n", _tinyusb_run_time);
printf("TinyUSB CPU load: %" PRIu32 " %%\n", _tinyusb_cpu_load);
}

/**
* @brief Test TinyUSB CPU load measurement
*
* Scenario:
* - Install TinyUSB driver with default configuration
* - wait for device connection
* - measure CPU load
* - uninstall driver
* - show results
*/
TEST_CASE("[CPU load] Install & Uninstall, blocking task indefinitely (legacy mode)", "[cpu_load]")
{
#if (!CONFIG_FREERTOS_UNICORE)
// Allow other core to finish initialization
vTaskDelay(pdMS_TO_TICKS(100));
#endif // (!CONFIG_FREERTOS_UNICORE)

// Install TinyUSB driver
tinyusb_config_t tusb_cfg = TINYUSB_DEFAULT_CONFIG(test_device_event_handler);
// Set the task blocking timeout to UINT32_t_MAX: blocking indefinitely
tusb_cfg.task.blocking_timeout_ms = UINT32_MAX;

TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_install(&tusb_cfg));

// Initialize CPU load measurement
test_cpu_load_init();

// Wait for the device to be mounted and enumerated by the Host
test_device_wait();
printf("\t -> Device connected\n");

// Measure CPU load
test_cpu_load_measure();

// Uninstall TinyUSB driver
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall());

// Show results
printf("TinyUSB Run time: %" PRIu32 " ticks\n", _tinyusb_run_time);
printf("TinyUSB CPU load: %" PRIu32 " %%\n", _tinyusb_cpu_load);
}



#endif // SOC_USB_OTG_SUPPORTED
Loading
Loading