Understanding USB versus UART on ESP32-S3

zazas321
Posts: 235
Joined: Mon Feb 01, 2021 9:41 am

Understanding USB versus UART on ESP32-S3

Postby zazas321 » Fri Aug 08, 2025 6:23 am

Hello. I have been into MCU'S and programming for a while now, but never really used USB much. I have finally picked up a few ESP32-S3 Development boards and decided to try USB. The example I am currently running:
https://github.com/espressif/esp-idf/tr ... ial_device



My goal is to write an application for the ESP32-S3 that would be capable of communicating with a QT application running on my PC via the USB at high speed. I am able to send data via the ESP32-S3 to PC using UART and it seems to work fine, but I feel like I want to be able to send/receive data at even higher speeds than 921600 baudrate (My application is measuring voltage/current at a very high sampling rate and trasnfering this data to PC application which is calculating and averaging data and displaying a graph).

I have a bunch of questions regarding USB and I am hoping to get some answers! :)

1. What are the main advantages why someone would choose USB over good old UART when communicating/debugging? One advantages that I see when using USB is that you do not need any CP2102 or any other USB/Uart adapters. If there is USB support on the MCU, you can just use it without any external HW components required. Are there any other major reasons?


2. Normally, people say that the UART speed is limited by baudrate. Frequently used is 115200 but you can use something as high as 921600 or even higher in some cases. What about the USB speed? How to utilize the maximum USB speed for sending/receiving data between the PC and ESP32-S3? In the example tusb_serial_device the USB is used as serial device so I assume the same speed limitations are applied to it as regular UART. So even though I am using USB, I am not getting USB speeds am I?


3. Normally, when communicating with MCU's via the PC application (I also write PC applications using QT C++ ir PyQT) via the serial you just connect to serial port and listen to incoming data. How would I even go about writing a PC application that would be capable of communicating with ESP32-S3 via the USB? For example, I have a Salae Logic analyzer:
https://www.saleae.com/?gad_source=1&ga ... u8EALw_wcB
and when connected to PC, it does not even show up as COM port and instead it shows as Universal Serial Bus controller. I assume that means this is a proper USB implementation, is that correct? How would I go about implementing something like this on my ESP32-S3 Development board?


4. Are there any ESP32-S3 examples where I could test USB and not USB Serial implementation if that even makes sense?


Appreciate in advance! I hope I can get some answers regarding my USB questions.
Last edited by zazas321 on Fri Aug 08, 2025 8:42 am, edited 1 time in total.

MicroController
Posts: 2661
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: Understanding USB versus UART on ESP32-S3

Postby MicroController » Fri Aug 08, 2025 7:35 am

4. Are there any ESP32-S3 examples where I could test USB and not USB Serial implementation if that even makes sense?
Sure: https://github.com/espressif/esp-idf/tr ... usb/device

zazas321
Posts: 235
Joined: Mon Feb 01, 2021 9:41 am

Re: Understanding USB versus UART on ESP32-S3

Postby zazas321 » Fri Aug 08, 2025 8:39 am

4. Are there any ESP32-S3 examples where I could test USB and not USB Serial implementation if that even makes sense?
Sure: https://github.com/espressif/esp-idf/tr ... usb/device
I see all those examples and none of them seem to be what I am looking for hence I was aksing this.

tusb_ncm -> Not what I want
tusb_msc -> I dont want mass storage device
tusb_midi -> I dont want MIDI
tusb_hid -> Not sure about this
tusb_composite_msc_serialdevice -> not what I want

Perhaps I need either:
tusb_console
tusb_serial_device
but I am not too sure. I dont want my device to appear as COM port, I want my device to appear as Universal Serial Bus controller and I want to be able to communicate with it via my custom PC application not via COM port. Perhaps you could put me on the right track? Does what I am asking even make any sense to you?

Perhaps what I am looking for is creating a custom device class specifically for my application but I am not sure if that makes any sense if I can use some other already available classes instead
Last edited by zazas321 on Fri Aug 08, 2025 10:58 am, edited 1 time in total.

zazas321
Posts: 235
Joined: Mon Feb 01, 2021 9:41 am

Re: Understanding USB versus UART on ESP32-S3

Postby zazas321 » Fri Aug 08, 2025 9:41 am

Ok it turns out that when using https://github.com/espressif/esp-idf/tr ... ial_device
example, the device appears both on Ports as USB Serial device and also appears as USB Composite Device in Universal Serial Bus controllers in device manager.

Few questions, how can I change the usb device name from the USB Composite Davice to some custom name?

I assume I would need to change tinyusb_config_t

Code: Select all

    ESP_LOGI(TAG, "USB initialization");
    const tinyusb_config_t tusb_cfg = {
        .device_descriptor = NULL,
        .string_descriptor = NULL,
        .external_phy = false,
#if (TUD_OPT_HIGH_SPEED)
        .fs_configuration_descriptor = NULL,
        .hs_configuration_descriptor = NULL,
        .qualifier_descriptor = NULL,
#else
        .configuration_descriptor = NULL,
#endif // TUD_OPT_HIGH_SPEED
    };

If I provide custom .device_descriptor and .string_descriptor:

Code: Select all

tusb_desc_device_t const desc_device =
{
    .bLength            = sizeof(tusb_desc_device_t),
    .bDescriptorType    = TUSB_DESC_DEVICE,
    .bcdUSB             = 0x0210, // at least 2.1 or 3.x for BOS & webUSB

    // Use Interface Association Descriptor (IAD) for CDC
    // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
    .bDeviceClass       = TUSB_CLASS_MISC,
    .bDeviceSubClass    = MISC_SUBCLASS_COMMON,
    .bDeviceProtocol    = MISC_PROTOCOL_IAD,
    .bMaxPacketSize0    = CFG_TUD_ENDPOINT0_SIZE,

    .idVendor           = 0xCafe,
    .idProduct          = 1234,
    .bcdDevice          = 0x0100,

    .iManufacturer      = 0x01,
    .iProduct           = 0x02,
    .iSerialNumber      = 0x03,

    .bNumConfigurations = 0x01
};


    const char *str_desc[] = {
        "TinyUSB Device",
        "TinyUSB CDC ACM Device",
        "1234567890", // Serial number
    };

Code: Select all


    ESP_LOGI(TAG, "USB initialization");
    const tinyusb_config_t tusb_cfg = {
        .device_descriptor = &desc_device,
        .string_descriptor = str_desc,
        .external_phy = false,
#if (TUD_OPT_HIGH_SPEED)
        .fs_configuration_descriptor = NULL,
        .hs_configuration_descriptor = NULL,
        .qualifier_descriptor = NULL,
#else
        .configuration_descriptor = NULL,
#endif // TUD_OPT_HIGH_SPEED
    };



LOG:

Code: Select all

�ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x1 (POWERON),boot:0x8 (SPI_FAST_FLASH_BOOT)
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce2810,len:0x15a0
load:0x403c8700,len:0x4
load:0x403c8704,len:0xd20
load:0x403cb700,len:0x2ee4
entry 0x403c8928
I (27) boot: ESP-IDF HEAD-HASH-NOTFOUND 2nd stage bootloader
I (27) boot: compile time Aug  8 2025 08:48:56
I (27) boot: Multicore bootloader
I (28) boot: chip revision: v0.1
I (31) boot: efuse block revision: v1.2
I (34) boot.esp32s3: Boot SPI Speed : 80MHz
I (38) boot.esp32s3: SPI Mode       : DIO
I (42) boot.esp32s3: SPI Flash Size : 2MB
I (46) boot: Enabling RNG early entropy source...
I (50) boot: Partition Table:
I (53) boot: ## Label            Usage          Type ST Offset   Length
I (59) boot:  0 nvs              WiFi data        01 02 00009000 00006000
I (66) boot:  1 phy_init         RF data          01 01 0000f000 00001000
I (72) boot:  2 factory          factory app      00 00 00010000 00100000
I (79) boot: End of partition table
I (82) esp_image: segment 0: paddr=00010020 vaddr=3c020020 size=0a8a4h ( 43172) map
I (97) esp_image: segment 1: paddr=0001a8cc vaddr=3fc92400 size=02b88h ( 11144) load
I (100) esp_image: segment 2: paddr=0001d45c vaddr=40374000 size=02bbch ( 11196) load
I (107) esp_image: segment 3: paddr=00020020 vaddr=42000020 size=1cea4h (118436) map
I (133) esp_image: segment 4: paddr=0003cecc vaddr=40376bbc size=0b75ch ( 46940) load
I (143) esp_image: segment 5: paddr=00048630 vaddr=600fe100 size=0001ch (    28) load
I (154) boot: Loaded app from partition at offset 0x10000
I (154) boot: Disabling RNG early entropy source...
I (164) cpu_start: Multicore app
I (174) cpu_start: Pro cpu start user code
I (174) cpu_start: cpu freq: 160000000 Hz
I (174) app_init: Application information:
I (174) app_init: Project name:     tusb_serial_device
I (179) app_init: App version:      1
I (182) app_init: Compile time:     Aug  8 2025 12:28:07
I (187) app_init: ELF file SHA256:  e3810d13f...
I (191) app_init: ESP-IDF:          HEAD-HASH-NOTFOUND
I (196) efuse_init: Min chip rev:     v0.0
I (200) efuse_init: Max chip rev:     v0.99
I (204) efuse_init: Chip rev:         v0.1
I (208) heap_init: Initializing. RAM available for dynamic allocation:
I (214) heap_init: At 3FC961F8 len 00053518 (333 KiB): RAM
I (219) heap_init: At 3FCE9710 len 00005724 (21 KiB): RAM
I (224) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM
I (230) heap_init: At 600FE11C len 00001ECC (7 KiB): RTCRAM
I (236) spi_flash: detected chip: generic
I (239) spi_flash: flash io: dio
W (242) spi_flash: Detected size(8192k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
I (254) sleep_gpio: Configure to isolate all GPIO pins in sleep state
I (260) sleep_gpio: Enable automatic switching of GPIO sleep configuration
I (267) main_task: Started on CPU0
I (287) main_task: Calling app_main()
I (287) example: USB initialization
W (287) tusb_desc: No FullSpeed configuration descriptor provided, using default.
I (287) tusb_desc:
┌─────────────────────────────────┐
│  USB Device Descriptor Summary  │
├───────────────────┬─────────────┤
│bDeviceClass       │ 239         │
├───────────────────┼─────────────┤
│bDeviceSubClass    │ 2           │
├───────────────────┼─────────────┤
│bDeviceProtocol    │ 1           │
├───────────────────┼─────────────┤
│bMaxPacketSize0    │ 64          │
├───────────────────┼─────────────┤
│idVendor           │ 0xcafe      │
├───────────────────┼─────────────┤
│idProduct          │ 0x4d2       │
│bNumConfigurations │ 0x1         │
└───────────────────┴─────────────┘
I (457) TinyUSB: TinyUSB Driver installed
I (457) example: USB initialization DONE


It will not change the USB device name how it appears on device manager, but instead it will show as USB device not recognized:
https://we.tl/t-MpbZqbfSSs

MicroController
Posts: 2661
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: Understanding USB versus UART on ESP32-S3

Postby MicroController » Fri Aug 08, 2025 11:21 am

I want my device to appear as Universal Serial Bus controller and I want to be able to communicate with it via my custom PC application not via COM port.
I think here may happen some complication. Apparently you want simple serial communication but don't want the device to appear as a COM port to the PC. Note that every USB device needs a driver on the PC side; the driver for USB virtual COM port devices is usually already present on a PC, as is the driver for MSC devices &c. I guess you only have two options here: Use a standard device class with a third-party-provided driver, or create a 'custom' USB device and write corresponding driver(s) yourself.

zazas321
Posts: 235
Joined: Mon Feb 01, 2021 9:41 am

Re: Understanding USB versus UART on ESP32-S3

Postby zazas321 » Fri Aug 08, 2025 12:25 pm

I want my device to appear as Universal Serial Bus controller and I want to be able to communicate with it via my custom PC application not via COM port.
I think here may happen some complication. Apparently you want simple serial communication but don't want the device to appear as a COM port to the PC. Note that every USB device needs a driver on the PC side; the driver for USB virtual COM port devices is usually already present on a PC, as is the driver for MSC devices &c. I guess you only have two options here: Use a standard device class with a third-party-provided driver, or create a 'custom' USB device and write corresponding driver(s) yourself.
That sounds complicated and I dont know if I am ready to embark on such a mission yet. So the options are:

1. Use USB Serial device class and my device will appear as com port - this is not the biggest issue. My main concern for this method - do I even get the benefits of using USB if I use it as COM port device? I dont see the purpose of using USB if I end up using it as UART device (COM port) I assume I will still be limited of UART baudrate for this method and I cannot achieve proper USB speeds. Can you help me understand how this method is different than using simple UART?

Can I achieve real USB speeds with USB serial device class?

2.Use HID example as a starter and then just remove keyboard and mouse implementations and implement some code that would allow sending/receiving data from and to my PC application. Is that possible for HID class?

3. Implement a custom USB class specifically designed to communicate with my application. This method seems the most complex and I am not even sure where to start. Which USB example would be the best to start implementing something like that?

MicroController
Posts: 2661
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: Understanding USB versus UART on ESP32-S3

Postby MicroController » Fri Aug 08, 2025 1:31 pm

Can I achieve real USB speeds with USB serial device class?
Not quite sure, but a few Mbits/s are definitely possible.
2.Use HID example as a starter and then just remove keyboard and mouse implementations and implement some code that would allow sending/receiving data from and to my PC application. Is that possible for HID class?
I don't think that'd work. HIDs tend to prioritize low latency and send a lot of small pieces of data to the PC; longer data streams, esp. from the PC to the device, may not go together well with a HID profile.

tore-espressif
Espressif staff
Espressif staff
Posts: 28
Joined: Thu Oct 07, 2021 8:11 am

Re: Understanding USB versus UART on ESP32-S3

Postby tore-espressif » Mon Aug 18, 2025 7:58 am

Hello @zazas321

As already mentioned, each USB device needs a driver in the host PC. Implementing a custom USB driver for Windows or Linux can be complicated, so sticking with CDC class (Virtual COM ports are implemented with CDC class) is the easiest solution for you. There are countless examples about how to work with these ports from Python and many other programming languages.

Main advantage you get is the USB itself. You can connect it to any PC without any additional converters (eg CP2012). If you write your software right, you will also get better speeds.

The Virtual COM port is there only to mimic good-old serial port, but the speed limitations do not apply. In case you use native USB connection between ESP32-S3 and the host PC, the 'baudrate' of the serial connection is meaningless. All communication is at USB Full Speed.

USB Full Speed is 12Mbit/s, practically you can get 80% of the bandwidth: 9.6Mbit/s (1.2MB/s), which should be good enough for data logging.

Who is online

Users browsing this forum: Applebot, Baidu [Spider], Bing [Bot] and 4 guests