Home

Awesome

USB_CDC verilog module

USB_CDC is a Verilog implementation of the Full Speed (12Mbit/s) USB communications device class (or USB CDC class). It implements the Abstract Control Model (ACM) subclass.

USB_CDC can be configured through CHANNELS parameter to implement from 1 to a maximum of 7 CDC channels.

Windows 10 provides a built-in driver (Usbser.sys) for USB CDC devices. A USB_CDC device is automatically recognized by Windows 10 as a virtual COM port, and a serial port terminal application such as CoolTerm can be used to communicate with it.

macOS and Linux provide built-in drivers for USB CDC ACM devices too. On macOS, the virtual COM gets a name like /dev/cu.usbmodem14601, whereas, on Linux, it gets a name like /dev/ttyACM0. Linux requires that the user account belongs to the dialout group to grant permissions for virtual COM access.

The USB_CDC idea was born from the awesome Luke Valenty's TinyFPGA board. TinyFPGA uses a "bit-banged" USB port implemented in the FPGA fabric for communication with the host PC. David Williams, with his TinyFPGA-BX USB serial module, changed Luke's code to allow USB communication for FPGA designs. David's code uses the same clock for both USB internal stuff and data interface with FPGA application designs. Instead, USB_CDC aims to use a different asynchronous clock to allow a lower clock frequency for FPGA application designs.

Furthermore, USB_CDC was designed from scratch. This allowed to:

Applications

Block Diagram and Pinout

Clocks

Reset

FIFO out (from the USB host)

FIFO in (to the USB host)

USB I/O buffers

USB device status

FIFO interface

USB_CDC provides a FIFO interface to transfer data to/from FPGA application. Both in_* and out_* channels use the same transmission protocol.

Data is consumed on rising app_clk when both valid and ready signals are high (red up arrows on the picture). Tsetup and Thold depend on FPGA/ASIC technology.

The valid signal is high only when new data is available. After data is consumed and there is no new data available, the valid signal is asserted low.

Verilog Configuration Parameters

USB_CDC has few Verilog parameters that allow customizing some module features.

VENDORID and PRODUCTID

VENDORID and PRODUCTID define USB vendor ID (VID) and product ID (PID).
For TinyFPGA: VID=0x1D50 and PID=0x6130.
For Fomu: VID=0x1209 and PID=0x5BF0.
By default, they are not defined (VENDORID=0x0000 and PRODUCTID=0x0000).

IN_BULK_MAXPACKETSIZE and OUT_BULK_MAXPACKETSIZE

IN_BULK_MAXPACKETSIZE and OUT_BULK_MAXPACKETSIZE define maximum bulk data payload sizes for IN and OUT bulk transactions. The allowable full-speed values are only 8, 16, 32, and 64 bytes. The default value for both is 8.

CHANNELS

CHANNELS defines how many CDC channels to implement. It is possible to implement from a minimum of 1 (default) to a maximum of 7 channels.

BIT_SAMPLES

BIT_SAMPLES defines the number of samples taken on USB dp/dn lines for each bit. Full Speed USB has a bit rate of 12MHz, so the clk clock has to be BIT_SAMPLES times faster. For example, the default value of 4 needs a clk frequency of 48MHz (see the picture below). BIT_SAMPLES has to be ≥ 4.

USE_APP_CLK and APP_CLK_FREQ

USE_APP_CLK parameter configures if the FPGA application uses the same USB_CDC internal stuff clock (USE_APP_CLK = 0) or a different asynchronous one (USE_APP_CLK = 1). If USE_APP_CLK = 0 then app_clk input is not used and can be connected to a constant value such as 1'b0.

When USE_APP_CLK = 1, APP_CLK_FREQ parameter defines the app_clk frequency in MHz.

To improve data throughput for lower app_clk frequencies, APP_CLK_FREQ parameter selects one of two different approaches to synchronize data that cross the two clock domains:

Overall, the USB Full-speed protocol caps data throughput to 1.5MB/s. So, with freq(clk) ≥ 48MHz, data throughput is 1.5MB/s if freq(app_clk) > 1.5MHz, otherwise it is freq(app_clk) bytes.

Examples

A few examples with complete implementation on both Fomu and TinyFPGA-BX are present in the examples directory. In addition, simulation testbenches are provided for each one.

Logic Resource Utilization

The USB_CDC code alone (with IN/OUT data in simple loopback configuration and all verilog parameters to default) shows the following logic resource utilization from iCEcube2:

Logic Resource Utilization:
---------------------------
    Total Logic Cells: 1158/7680
        Combinational Logic Cells: 734      out of   7680      9.55729%
        Sequential Logic Cells:    424      out of   7680      5.52083%
        Logic Tiles:               212      out of   960       22.0833%
    Registers: 
        Logic Registers:           424      out of   7680      5.52083%
        IO Registers:              0        out of   1280      0
    Block RAMs:                    0        out of   32        0%
    Warm Boots:                    0        out of   1         0%
    Pins:
        Input Pins:                1        out of   63        1.5873%
        Output Pins:               2        out of   63        3.1746%
        InOut Pins:                2        out of   63        3.1746%
    Global Buffers:                4        out of   8         50%
    PLLs:                          1        out of   1         100%

The clock timing summary is:

                   1::Clock Frequency Summary
 =====================================================================
Number of clocks: 1
Clock: clk_usb           | Frequency: 76.60 MHz  | Target: 48.01 MHz  |

Directory Structure

.
├── README.md                            --> This file
├── usb_cdc                              --> USB_CDC verilog files
│   ├── bulk_endp.v
│   ├── ctrl_endp.v
│   ├── in_fifo.v
│   ├── out_fifo.v
│   ├── phy_rx.v
│   ├── phy_tx.v
│   ├── sie.v
│   └── usb_cdc.v
└── examples                             --> Example designs
    ├── Fomu
    │   :
    │
    └── TinyFPGA-BX
        ├── hdl
        │   ├── demo
        │   │   ├── demo_fpga.vhd        --> Top level (VHDL)
        │   │   ├── demo.v               --> Top level (verilog)
        │   │   :
        │   │
        │   └── loopback
        │       ├── loopback.v           --> Top level (verilog)
        │       :
        │
        ├── iCEcube2                     --> iCEcube2 projects
        │   ├── demo
        │   │   ├── usb_cdc_sbt.project  --> iCEcube2 project file
        │   │   :
        │   │
        │   └── loopback
        │       ├── usb_cdc_sbt.project  --> iCEcube2 project file
        │       :
        │
        ├── OSS_CAD_Suite                --> OSS CAD Suite projects
        │   ├── Makefile
        │   ├── input
        │   │   ├── demo
        │   │   │   :
        │   │   └── loopback
        │   │       :
        │   │
        │   └── output
        │       :
        │
        └── python                       --> test files
            └── demo
                ├── run.py
                :