CDC Serial

Roles: device and host. The standard driver implements CDC ACM virtual serial ports. The host driver can also expose FTDI, CP210x, CH34x, and PL2303 USB serial adapters through the same tuh_cdc_* API.

Device

Enable CFG_TUD_CDC with the required port count and add one TUD_CDC_DESCRIPTOR per port.

Option

Default

What it controls

CFG_TUD_CDC_RX_BUFSIZE / CFG_TUD_CDC_TX_BUFSIZE

Device bulk maximum

Software FIFO capacity in each direction. Larger FIFOs absorb longer application scheduling gaps.

CFG_TUD_CDC_RX_EPSIZE / CFG_TUD_CDC_TX_EPSIZE

Device bulk maximum

Endpoint transfer buffer per direction, at least the _epsize of TUD_CDC_DESCRIPTOR.

CFG_TUD_CDC_NOTIFY

0

Compiles the tud_cdc_n_notify_* API and its buffer for sending serial-state and other notifications. The notification endpoint is opened whenever the descriptor has one, regardless of this option.

CFG_TUD_CDC_RX_PERSISTENT / CFG_TUD_CDC_TX_PERSISTENT

0

Keeps the corresponding FIFO contents across disconnect/reconnect. Enable only when stale bytes are intentional.

CFG_TUD_CDC_RX_NEED_ZLP

0

Enables multi-packet receive transfers terminated by a host-sent zero-length packet. Enable only when the host side supports this framing. RX transfers then can request up to CFG_TUD_CDC_RX_EPSIZE (otherwise one packet); make it a multiple of _epsize.

CFG_TUD_CDC_TX_OVERWRITABLE_IF_NOT_CONNECTED

1

Allows writes made before DTR connection to replace old queued data rather than permanently filling the FIFO.

Use speed-dependent values from an example when the device can enumerate at high speed.

The common data path polls each port from the application loop, after tud_task(). Polling is needed if tud_cdc_rx_cb() can leave bytes unread (for example because the TX FIFO is full): reception stops while the RX FIFO has less than one packet of room.

void cdc_echo_task(uint8_t itf) {
  uint8_t buf[64];
  uint32_t count = tud_cdc_n_available(itf);
  uint32_t room = tud_cdc_n_write_available(itf);
  if (count > sizeof(buf)) count = sizeof(buf);
  if (count > room) count = room;

  count = tud_cdc_n_read(itf, buf, count);
  if (count && tud_cdc_n_write(itf, buf, count) == count) {
    tud_cdc_n_write_flush(itf);
  }
}

Use tud_cdc_n_connected() when transmission should depend on DTR. A port can be mounted while a terminal has not opened it. Handle line settings in tud_cdc_line_state_cb() and tud_cdc_line_coding_cb() if they affect the physical UART; TinyUSB does not configure that UART for you.

Device API or callback

What it does

tud_cdc_n_connected() / tud_cdc_n_ready()

Both require the device configured and not suspended; connected also needs DTR asserted, ready needs both data endpoints open. Neither checks TX FIFO room; use tud_cdc_n_write_available().

tud_cdc_n_available() / tud_cdc_n_read()

Reports and removes bytes received from the host.

tud_cdc_n_write_available() / tud_cdc_n_write()

Reports TX FIFO room and copies as many bytes as fit; preserve any unwritten remainder.

tud_cdc_n_write_flush()

Starts transmission of buffered bytes without waiting for the FIFO to fill.

tud_cdc_rx_cb() / tud_cdc_tx_complete_cb()

Announces newly buffered receive data or completion of a transmit transfer.

tud_cdc_line_state_cb() / tud_cdc_line_coding_cb()

Reports host DTR/RTS and baud/data/parity/stop settings so a UART bridge can apply them.

See CDC Dual Ports for multiple ports and CDC + MSC for a composite device.

Host

Set CFG_TUH_CDC to the required number of serial interfaces. Enable only the adapter families needed by the product:

#define CFG_TUH_CDC        1
#define CFG_TUH_CDC_FTDI   1
#define CFG_TUH_CDC_CP210X 1
#define CFG_TUH_CDC_CH34X  1
#define CFG_TUH_CDC_PL2303 1

The RX/TX software FIFO and endpoint buffers default to TUH_EPSIZE_BULK_MAX through CFG_TUH_CDC_RX_BUFSIZE, CFG_TUH_CDC_TX_BUFSIZE, CFG_TUH_CDC_RX_EPSIZE, and CFG_TUH_CDC_TX_EPSIZE. Increase FIFO sizes to tolerate application latency; endpoint sizes normally stay at the host bulk maximum. Optional CFG_TUH_CDC_LINE_CODING_ON_ENUM and CFG_TUH_CDC_LINE_CONTROL_ON_ENUM values apply initial serial settings as part of enumeration.

tuh_cdc_mount_cb(idx) reports a ready interface. Read data in tuh_cdc_rx_cb(idx) using tuh_cdc_read_available() and tuh_cdc_read(). Queue output with tuh_cdc_write() and call tuh_cdc_write_flush() when it should leave promptly.

Line-control functions such as tuh_cdc_set_baudrate() and tuh_cdc_set_line_coding() accept a completion callback. Their _sync forms block and should only be used where the host task can continue running. tuh_cdc_set_line_coding() works with every adapter family; for FTDI, CP210x, and CH34x it sends the baud rate and data format as two requests.

Host API or callback

What it does

tuh_cdc_mounted() / tuh_cdc_itf_get_info()

Tests an interface index and returns its device address and a rebuilt interface descriptor. bInterfaceClass reads CDC for every adapter family; the serial-driver type is not reported.

tuh_cdc_read_available() / tuh_cdc_read()

Reports and removes bytes buffered from the serial device.

tuh_cdc_write() / tuh_cdc_write_flush()

Copies output into the class FIFO and starts a USB transfer.

tuh_cdc_set_control_line_state() / tuh_cdc_set_line_coding()

Queues DTR/RTS or baud/framing changes and calls the supplied completion callback.

tuh_cdc_mount_cb() / tuh_cdc_umount_cb()

Creates or removes application state for a serial interface index.

tuh_cdc_rx_cb() / tuh_cdc_tx_complete_cb()

Announces buffered input or completion of queued class output.

The Host: CDC/MSC/HID example shows enumeration, 115200 8N1 setup, and bidirectional I/O.

Practical notes

  • USB CDC transfers bytes, not UART timing. Baud rate and framing are host requests that an application may honor, translate, or ignore.

  • A write call can accept fewer bytes than requested. Preserve and retry the remainder instead of silently dropping it.

  • For interactive traffic, flush after a logical message. For throughput, allow the FIFO to fill and flush less often.

Specifications used: Communications Devices Class, Revision 1.2 (Errata 1), and CDC PSTN Subclass, Revision 1.2, which defines ACM.