USB Virtual Serial Port Design for Embedded Systems
2026-04-06 06:21:48··#1
Introduction: In modern embedded systems, asynchronous serial communication interfaces are often used as standard peripherals in microcontrollers and embedded systems. However, as personal computer peripherals use serial ports less and less, serial ports are gradually disappearing from personal computers, especially laptops. Embedded developers often find that their newly purchased computers lack serial ports, or that users' computers at debugging sites lack serial ports, creating an awkward situation. Conversely, modern personal computers generally have more than four USB ports. Could USB ports be used to replace serial ports for communication between PCs and embedded systems? 1. Feasibility of Using USB Virtual Serial Ports to Replace Physical Serial Ports First, more and more devices with USB interfaces are emerging, such as microcontrollers with USB interfaces or standalone USB interface devices. Moreover, the cost of these devices is now very close to that of using RS232 level conversion chips. Second, some USB-to-serial interface chips have also appeared on the market. These chips have a serial port on one end and a USB interface on the other, internally performing the serial-to-USB protocol conversion. When this chip is connected to a personal computer via USB, it appears as a serial device in the operating system. This means the USB interface is transparent to traditional serial debugging tools (HyperTerninal) and user serial-based applications, eliminating the need for developers to modify PC-side debugging and applications. However, the USB class of these devices does not belong to the standard USB device class, requiring additional device drivers to be installed on Windows and Linux operating systems. Furthermore, because it's not a built-in operating system driver, and communication involves multiple conversions from serial to serial and from USB device to USB host, it's often difficult to determine whether the problem lies with the serial port or the USB when debugging. Therefore, the embedded system should connect directly to the PC via a USB bus interface (through an on-chip USB interface or an external USB interface chip), with the microcontroller directly handling the USB virtual serial port protocol conversion. Among the USB standard subclasses, there is a class called CDC, which can implement virtual serial communication protocols. Since most operating systems (Windows and Linux) come with device drivers supporting CDC classes, they can automatically recognize CDC devices, eliminating the burden of writing dedicated device drivers and simplifying driver installation. 2. What is the CDC Class ? The CDC class is short for USB Communication Device Class. It's a subclass defined by the USB organization specifically for various communication devices (telecommunications equipment and medium-speed network communication equipment). Depending on the communication device it targets, the CDC class is further divided into the following models: USB Traditional Pure Telephone Service (POTS) model, USB ISDN model, and USB network model. The USB Traditional Pure Telephone Service model can be further divided into Direct Line Control Model, Abstract Control Model, and USB Telephone Model, as shown in Figure 1. The virtual serial port discussed in this article belongs to the Abstract Control Model under the USB Traditional Pure Telephone Service model. Figure 1. Typically, a CDC class consists of two interface subclasses: a Communication Interface Class and a Data Interface Class. The author primarily manages and controls the device through the Communication Interface Class, while transmitting data through the Data Interface Class. These two interface subclasses occupy different numbers and types of endpoints, as shown in Figure 2. For the different CDC class models mentioned above, the terminal point requirements for their corresponding interfaces are also different. For example, the abstract control model discussed here requires a control endpoint and an optional interrupt endpoint for the communication interface class. The data interface subclass requires an isochronous endpoint with input (IN) and an isochronous endpoint with output (OUT). The control endpoint is mainly used for enumerating USB devices and setting the baud rate and data types (data bits, stop bits, and start bits) of the virtual serial port. The isochronous endpoint in the output direction is used for the host to send data to the slave device, equivalent to the TXD line in a traditional physical serial port (from the microcontroller's perspective). The isochronous endpoint in the input direction is used for the slave device to send data to the host, equivalent to the RXD line in a traditional physical serial port. Figure 2.3 provides a brief introduction to the AT89C5131. To implement USB bus communication in a microcontroller-based embedded system, a dedicated external USB bus interface chip (such as Philips' D12) is typically used. However, this approach increases both cost and PCB board size. Therefore, Atmel's AT89C5131 microcontroller, which integrates a USB 2.0 full-speed slave interface, was used instead. The AT89C5131 is a 52-core microcontroller. In terms of memory, it integrates 32KB of Flash memory for code storage and 1KB of EEPROM memory for user data storage. Users can use the on-chip bootloader or Flash API to perform ISP or IAP programming on the Flash and EEPROM memories via the USB interface or other interfaces (such as UART and I2C bus). Furthermore, the AT89C5131 integrates a 10-bit ADC, an I2C bus interface, and a PCA module, among other peripherals. The structure of the AT89C5131's USB 2.0 full-speed slave interface is shown in Figure 3, which includes a USB D+/D- interface buffer, a digital phase-locked loop, a serial interface engine (SIE), and a universal function interface (UFI). The digital phase-locked loop (PLL) uses the microcontroller's clock as input to generate the 48MHz clock required by other parts of the USB interface. The serial interface engine completes the encoding and decoding of the USB communication physical layer NRZI code, CRC generation, and verification and error correction. The general-purpose interface includes a dual-port data memory, one end of which is connected to the serial interface engine, and the other end is connected to the microcontroller via a data bus, allowing the microcontroller to control and communicate with the USB 2.0 slave interface through special function registers. Figure 3 shows that the AT89C5131's USB 2.0 full-speed slave interface contains 7 endpoints, with endpoint 0 configured as the default control endpoint. The other endpoints, 1 through 6, can be configured for control, burst, interrupt, and isochronous modes through special registers. Since each endpoint is controlled, its status is identified, and its data is accessed by a separate set of registers, directly mapping these registers to the 51 microcontroller's special function register address space would be insufficient. Therefore, the seven sets of registers at these seven endpoints actually use the same set of register addresses in the microcontroller's address space. A special function register (UEPNUM) is used to select which endpoint register set is actually being used, thus significantly saving address space and enabling the integration of other special peripherals. 4. Implementation of the CDC Class Based on AT89C5131: The hardware connection between the AT89C5131 and the USB interface is simple. A B-type USB socket is selected because, according to the USB specification, slave devices use B-type USB sockets, and master devices use A-type USB sockets. The D+ and D- pins of the B-type USB socket are connected to the D+ and D- pins on the AT89C5131, respectively. Then, a 1.5 kΩ pull-up resistor is connected between the power supply and D+. According to the USB specification, the USB master device determines whether the slave device is a full-speed or low-speed device by the absolute voltage levels on D+ and D- when the slave device is plugged in. Since the AT89C5131 is a full-speed device, D+ needs to be pulled up. The following describes the microcontroller software design and implementation of the virtual serial port. First, let's look at the terminal point allocation. Following the requirements of the CDC class abstract control model for terminal points, terminal points 0 and 1 are assigned to the communication interface subclass as the control terminal point (for enumeration and serial port parameter settings) and the interrupt terminal point, respectively. Terminal points 2 and 3 are assigned to the data interface subclass as the IN and OUT terminal points, respectively. Data from the virtual serial port is primarily transmitted through these two terminal points. Since the behavior of each terminal point is relatively independent, yet the control process for each terminal point is similar, we will take terminal point 2, which serves as the IN terminal point for the data interface, as an example to illustrate how the software operates and controls the terminal points. Its control flowchart is shown in Figure 4. Terminal point 2 is an IN terminal point. Its main function is to simulate the TXD line of the physical serial port and send data to the master device. When the master device sends an IN request, if the FIFO is not empty, the contents of the FIFO are sent to the master device; if the FIFO is empty, an empty packet is sent as a response. When the AT89C5131 receives an IN request, it triggers a USB interrupt (if enabled). In the interrupt handler, as shown in Figure 4, it first determines which endpoint is the trigger source. If it's endpoint 2, it maps the USB register set to the set for endpoint 2, then fills the serial data to be sent into the FIFO register (UEPDATX), sets the TXRDY bit of UEPSTAX to indicate that the data in the FIFO is ready, and the USB interface automatically responds to the IN request and sends the data in the FIFO. The program can then exit the interrupt service routine. The processing for other endpoints is similar. The software uses Keil C51 as the compilation system. To facilitate integration with other programs in the system, it adopts the standard character device API interfaces usb_getc() and usb_putc(), giving the program good portability. The application layer functions (usb_getc() and usb_putc()) and the USB interrupt handler exchange data through two first-in-first-out (FIFO) circular queues (TX and RX), effectively acting as a buffer for sending and receiving data and preventing buffer overflow. 5. Summary Implementing a USB virtual serial port based on the CDC class on a microcontroller is well-suited to the development of current computer peripheral interfaces. Furthermore, because this interface is still mapped as a serial port in the PC operating system, it avoids the need for extensive rewriting of PC-side debugging programs and applications.