Inconsistent serial output with ESP32-S3 and the TinyUSB CDC device stack

Zigzag
Posts: 2
Joined: Tue Oct 01, 2024 3:55 pm

Inconsistent serial output with ESP32-S3 and the TinyUSB CDC device stack

Postby Zigzag » Tue Oct 01, 2024 9:02 pm

I've been struggling to get serial printing to work consistently using the USB-OTG and the TinyUSB CDC device stack on the ESP32-S3-DevKitC-1 with the ESP32-S3-WROOM-1).

I have narrowed one issue to the minimal code + sdk config provided below. When I delay the task for 3s, the idf_monitor.py sometimes receives a single iteration of text, but then will not print again (I left it for an hour) until I try to send something back by typing. When I type, I get all the built up text at once in bulk - so it is running, but the serial data appears to just not be transmitted. When the delay is set to 2s, it happily prints as expected with with 2s intervals between messages.

I also tried waiting on tud_cdc_connected() and tud_cdc_available(), but both remain false, even while the serial is printing and working and being received with the 2s delay. It seems odd, and is maybe a hint at the problem?

Would anyone be able to point me in the right direction about what is causing this behaviour? It's so basic, I'm sure I'm missing something very obvious, but I've been through the documentation and much deeper in the codebase and I can't figure it out.
  1. #include <stdint.h>
  2. #include "esp_log.h"
  3. #include "freertos/FreeRTOS.h"
  4. #include "freertos/task.h"
  5. #include "tinyusb.h"
  6. #include "tusb_cdc_acm.h"
  7. #include "tusb_console.h"
  8. #include "sdkconfig.h"
  9.  
  10. static const char *TAG = "example";
  11.  
  12. void use_tinyusb(void *arg)
  13. {
  14.     const tinyusb_config_t tusb_cfg = {
  15.         .device_descriptor = NULL,
  16.         .string_descriptor = NULL,
  17.         .external_phy = false,
  18.         .configuration_descriptor = NULL,
  19.     };
  20.     ESP_ERROR_CHECK(tinyusb_driver_install(&tusb_cfg));
  21.     tinyusb_config_cdcacm_t acm_cfg = { 0 };
  22.     ESP_ERROR_CHECK(tusb_cdc_acm_init(&acm_cfg));
  23.     ESP_ERROR_CHECK(esp_tusb_init_console(TINYUSB_CDC_ACM_0)); // log to usb
  24. }
  25.  
  26. void app_main(void)
  27. {
  28.     use_tinyusb(NULL);
  29.     while (true) {
  30.         printf("before...\n");
  31.         //vTaskDelay(pdMS_TO_TICKS(2000)); // Received as expected every 2s to idf-monitor
  32.         vTaskDelay(pdMS_TO_TICKS(3000)); // Sometimes received once, and never again until text sent back through the monitor.
  33.         printf("after\n\n");
  34.     }
  35. }
The sdkconfig.defaults

Code: Select all

# Increase main task stack size
CONFIG_ESP_MAIN_TASK_STACK_SIZE=7168

# Enable FreeRTOS stats formatting functions, needed for 'tasks' command
CONFIG_FREERTOS_USE_TRACE_FACILITY=y
CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y

# Enable Tiny USB
CONFIG_TINYUSB_CDC_ENABLED=y
# On chips with USB serial, disable secondary console which does not make sense when using console component
CONFIG_ESP_CONSOLE_SECONDARY_NONE=y

Zigzag
Posts: 2
Joined: Tue Oct 01, 2024 3:55 pm

Re: Inconsistent serial output with ESP32-S3 and the TinyUSB CDC device stack

Postby Zigzag » Wed Oct 02, 2024 5:46 pm

After much debugging, I found that this was due to autosuspend 'feature' in linux for USB devices which is set to a default of 2 seconds (Windows I believe may have a similar issue, I am going to test soon). One solution is to setup udev rules and turn off autosuspend, but it would be better for the ESP32 to properly send data without having to specially configure the host in such a manner. I found out that modifying the default tinyusb settings to remove the TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP fixes it for linux at least.
  1.  //TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, TUSB_DESC_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
  2.  TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, TUSB_DESC_TOTAL_LEN, 0x00, 100),
Another way to deal with it appears to be to call:

Code: Select all

tud_remote_wakeup();
after each serial message is sent (note that flushing with tinyusb_cdcacm_write_flush(itf, 0); does not awaken the device transmission and does not fix the issue). Does anyone know of a standard location for calling tud_remote_wakeup()? Maybe the tusb task should be checking and doing this automatically when transmission data is waiting in the buffer? It is quite surprising to listen out for deactivation by default but to provide no default functionality to awaken itself when data is awaiting transmission.

I also discovered that with other Serial interfaces such as pythons minicom, DTR is properly asserted and the tud_cdc_connected() signal works as expected. Maybe the idf_monitor.py is not doing that because it uses the DTR line as part of flashing? But it's not ideal that the provided serial interface doesn't work with the provided cdc status functions by default as well. Maybe there is a setting I am missing for DTR to function for idf_monitor.py.

It would have been very useful for all of these unusual behaviors for basic functionality to be highlighted in the documentation here or at least in the README of the tusb_serial_device github example.

Who is online

Users browsing this forum: Eltrion and 167 guests