Search topics...
USBEmbedded USBfoundational

How does USB CDC-ACM work as a virtual serial port?

0 upvotes
Practice with AISoon
Study the fundamentals first — USB topic page

CDC-ACM (Abstract Control Model) is a subclass of the USB Communications Device Class that emulates a serial port over USB. It allows an embedded device to appear as a standard COM port on the host PC, enabling existing serial terminal software (PuTTY, minicom, screen) and serial libraries (pyserial) to communicate with the device without any custom driver — the operating system's built-in CDC-ACM driver handles everything.

The CDC-ACM device presents two USB interfaces to the host. Interface 0 (Communication Class Interface) carries management commands and notifications. It includes a single interrupt IN endpoint used to send serial state notifications (e.g., DCD, DSR, ring indicator changes) to the host — many embedded implementations leave this endpoint unused and never send notifications. This interface also includes CDC-specific functional descriptors: the Header Functional Descriptor, Call Management Functional Descriptor, ACM Functional Descriptor (declares which line coding and control signal features are supported), and the Union Functional Descriptor (links the communication and data interfaces together). Interface 1 (Data Class Interface) carries the actual serial data. It has two bulk endpoints: a bulk IN endpoint (device-to-host, the device's "TX") and a bulk OUT endpoint (host-to-device, the device's "RX").

From the firmware perspective, the MCU's USB stack handles enumeration and class requests automatically. The two class-specific control requests that matter are: SET_LINE_CODING (the host tells the device the desired baud rate, stop bits, parity, and data bits — most embedded implementations accept any values and ignore them since the communication is USB, not actual UART) and SET_CONTROL_LINE_STATE (the host signals DTR and RTS — firmware often uses the DTR assertion as a "port opened" signal to start sending data). For actual data transfer, firmware writes bytes into the bulk IN endpoint buffer, and the USB peripheral transmits them when the host polls. Incoming data from the host arrives in the bulk OUT endpoint buffer, and firmware reads it. The throughput is determined by USB, not by the "baud rate" set via SET_LINE_CODING — at full-speed USB, CDC-ACM can achieve approximately 1 MB/s, regardless of whether the host configures 9600 or 115200 baud.

Source: USB Q&A