Browse Source

update README

pull/12/head
WangXuan95 1 year ago
parent
commit
332290955c
  1. 528
      README.md
  2. 2
      RTL/usb_class/usb_audio_top.v

528
README.md

@ -1,4 +1,4 @@
![语言](https://img.shields.io/badge/语言-verilog_(IEEE1364_2001)-9A90FD.svg) ![仿真](https://img.shields.io/badge/仿真-iverilog-green.svg) ![部署](https://img.shields.io/badge/部署-quartus-blue.svg) ![部署](https://img.shields.io/badge/部署-vivado-FF1010.svg)
![语言](https://img.shields.io/badge/语言-verilog_(IEEE1364_2001)-9A90FD.svg) ![部署](https://img.shields.io/badge/部署-quartus-blue.svg) ![部署](https://img.shields.io/badge/部署-vivado-FF1010.svg)
[English](#en) | [中文](#cn)
@ -8,208 +8,208 @@
<span id="en">FPGA USB-device</span>
===========================
(Currently, English README is machine translated and has not been proofread. I will proofread it soon.)
To realize USB devices on FPGA, the usual solution are USB chips (such as CY7C68013), which leads to high circuit cost. This repo is an FPGA-based USB Full-Speed device core, which only require a simple circuit (just like STM32 microcontrollers) instead of additional USB chips.
USB 1.1 device controller. Realize various USB devices on FPGA. such as USB speaker and microphone, USB camera, USB disk, USB keyboard and USB serial port.
Based on this, I further implement USB audio, USB camera, USB disk, USB keyboard and USB-Serial devices on FPGA. They are all standard devices specified by USB, which can be plug and play without installing drivers.
To realize USB devices on FPGA, the usual technical route is to use USB chips (such as Cypress CY7C68013), which leads to high development costs of circuits and software. This library uses FPGA to implement a universal USB 1.1 (Full Speed) device controller, which can use a very simple circuit to implement USB devices like STM32 microcontroller, without relying on additional USB chips. Based on this, I also implemented USB audio, USB camera, USB flash disk, USB keyboard and USB-Serial on the FPGA. They are the standard devices specified by USB, so they can plug and play without installing drivers.
Features:
Features of this library:
- Pure Verilog implementation for universal FPGAs such as Xilinx, Altera, etc.
- The circuit is simple, **only need three FPGA pins, one resistor and one USB connector** (see [Circuit connection](#circuit_en)).
- Pure Verilog implementation for various FPGA models such as Xilinx, Altera, etc.
- The circuitry required is very simple, except for the FPGA, **Only three FPGA pins, one resistor and one USB interface socket are needed** (see [电路连接](#circuit)).
If you're not familiar with USB protocol stack, but want to quickly implement USB devices on FPGA, you can use some USB classes I provide:
If you're not familiar with the USB stack, but want to quickly implement a USB device, you can use some of the USB features I've packaged:
- **USB audio** is a USB Audio Class (UAC) device. It can let FPGA be a speaker and a microphone (they are both in stereo 2-channel, 48ksps). It provides streaming interfaces for FPGA developers to receive speaker data and send microphone data.
- **USB camera** is a USB Video Class (UVC) device. It can let FPGA be a USB camera, which provides a streaming interface for sending video data to PC.
- **USB flash drive** is a USB Mass Storage (MSC) device. It can let FPGA be a USB flash disk.
- **USB keyboard** is a USB Human Interface (HID) device. It can let FPGA be a USB keyboard, which provides a interface for FPGA developers to send "key press" action.
- **USB-Serial** is a USB Communication Device Class (USB-CDC) device. It can let FPGA be a USB serial port device, which provides interfaces for FPGA developers to receive and send data to PC.
- **USB-Serial-2channel**: is a composite device that includes two USB-CDC devices. It can let FPGA a two-channel serial port device, which provides interfaces for FPGA developers to receive and send data to PC.
- **USB audio**: is a composite device that includes a speaker and microphone (2-channel, 48ksps) and provides a streaming interface for receiving speaker audio data and sending microphone audio data.
- **USB camera**: Video can be transmitted to the computer (width and height can be customized), providing a streaming interface for sending video data.
- **USB flash drive**
- **USB keyboard**: Provide the control interface of "key press".
- **USB-Serial** Realize serial port equipment, and use minicom, putty, HyperTerminal, serial port assistant and other software to transmit data with FPGA on the computer.
- **USB-Serial-2ch**: is a composite device that includes 2 independent USB-Serial.
If you are familiar with the USB stack, you can use this library to develop more USB devices (see [Secondary development of USB-device](#usbcore)). It provides:
If you are familiar with USB protocol stack, you can use the usb device core in this repo to develop more USB devices (see [Development using USB core](#usbcore_en)). The core provides:
- Customize 1 device descriptor, 1 configuration descriptor, and 6 string descriptors.
- 4 IN endpoints (0x81 \ ~ 0x84), 4 OUT endpoints (0x01 \ ~ 0x04).
- The optional debug output interface prints the debug information to the computer through an additional UART, and the communication process of the USB data packet can be seen.
- 4 IN endpoints (0x81\~0x84), 4 OUT endpoints (0x01\~0x04).
- An optional debug interface for printing debug information to the computer via a UART, you can see the USB communication process through it.
 
## Effect display
## Demonstration of USB devices
| | Windows 设备管理器中看到的设备 |Effect display|
| | What you can see in Windows Device Manager |What you can see in softwares|
| :----------------: | :----------------------------: | :----------------------------: |
| **USB音频** |![](./figures/ls_audio.png)| ![](./figures/test_audio.png) |
| **USB摄像头** |![](./figures/ls_camera.png)| ![](./figures/test_camera.png) |
| **U盘** |![](./figures/ls_disk.png)| ![](./figures/test_disk.png) |
| **USB键盘** |![](./figures/ls_keyboard.png)| 每2秒按下一个英文字母键 |
| **USB-Serial** |![](./figures/ls_serial.png)| ![](./figures/test_serial.png) |
| **USB-Serial-2ch** |![](./figures/ls_serial2.png)| 同上 |
| **USB audio** |![](./figures/ls_audio.png)| ![](./figures/test_audio.png) |
| **USB camera** |![](./figures/ls_camera.png)| ![](./figures/test_camera.png) |
| **USB disk** |![](./figures/ls_disk.png)| ![](./figures/test_disk.png) |
| **USB keyboard** |![](./figures/ls_keyboard.png)| Press a key every 2 seconds |
| **USB Serial** |![](./figures/ls_serial.png)| ![](./figures/test_serial.png) |
| **USB Serial 2channel** |![](./figures/ls_serial2.png)| ditto |
 
## Compatibility
## Compatibility for Operation Systems
I tested the compatibility of these devices on different operating systems, as shown in the table below.
I tested the compatibility of these devices on different operating systems, as shown below.
| 兼容性测试 | Windows 10 |Linux Ubuntu 18.04| macOS 10.15 |
| | Windows 10 |Linux Ubuntu 18.04| macOS 10.15 |
| :----------------: | :----------------: | :----------------------------------: | :----------------: |
| **USB音频** | :heavy_check_mark: |:heavy_check_mark: (no recognition bug solved)| :heavy_check_mark: |
| **USB摄像头** | :heavy_check_mark: |:heavy_check_mark: | :x: |
| **U盘** | :heavy_check_mark: |:heavy_check_mark: | :heavy_check_mark: |
| **USB键盘** | :heavy_check_mark: |:heavy_check_mark: | :heavy_check_mark: |
| **USB-Serial** | :heavy_check_mark: |:heavy_check_mark: | :heavy_check_mark: |
| **USB-Serial-2ch** | :heavy_check_mark: |:heavy_check_mark: (Unrecognized bug resolved)| :heavy_check_mark: |
| **USB audio** | :heavy_check_mark: |:heavy_check_mark:| :heavy_check_mark: |
| **USB camera** | :heavy_check_mark: |:heavy_check_mark: | :x: * |
| **USB disk** | :heavy_check_mark: |:heavy_check_mark: | :heavy_check_mark: |
| **USB keyboard** | :heavy_check_mark: |:heavy_check_mark: | :heavy_check_mark: |
| **USB Serial** | :heavy_check_mark: |:heavy_check_mark: | :heavy_check_mark: |
| **USB Serial 2channel** | :heavy_check_mark: |:heavy_check_mark:| :heavy_check_mark: |
> :x: macOS recognizes my USB camera device, but it can't read the video, for an unknown reason, to be resolved later.
> :x: macOS recognizes my USB camera device, but it can't read the video. The reason is unknown and to be resolved later.
 
### Special thanks
- Thanks for [github.com/xiaowuzxc](https://github.com/xiaowuzxc) submitting the code for the USB speaker. I later expanded it to the current USB audio (speaker + microphone).
- Thanks to \ *\* \ *\* \ *8125@qq.com for solving the problem of one channel not being recognized in USB-Serial-2ch.
- Thanks [xiaowuzxc](https://github.com/xiaowuzxc) for submitting the code of a USB speaker device. I later expanded it to current USB audio device (speaker+microphone).
- Thanks *\*\*\*8125@qq.com for solving the problem of Linux cannot recongnize one of the channels of USB-Serial-2channel.
 
# <span id="circuit"> I Circuit connection</span>
# <span id="circuit_en">Circuit connection</span>
USB has `VBUS`, `GND`, `USB_D-`, `USB_D+` these 4 wires. Taking USB Type B connector (commonly known as USB square female connector) as an example, the four wires are defined as shown in the figure below.
USB has 4 wires: `VBUS`, `GND`, `USB_D-`, and `USB_D+` . Taking USB Type B connector as an example, the 4 wires are defined in the figure below.
|![USBTypeB](./figures/usb_typeb.png)|
| :-----------------------------------: |
|**Figure**: USB connector (square female) and cable.|
Please connect the circuit as shown in the figure below. Where `usb_dp_pull`, `usb_dp`, `usb_dn` are the three common IO pins of the FPGA (the level must be 3.3 V). Among
- Connection `USB_D-` of `usb_dn` FPGA. : warning: If it is a flying line connection, ensure that the length of the connecting line is within 10 cm. If it is a PCB connection, it should be connected to the `usb_dp` differential distribution line.
- Connection `USB_D+` of `usb_dp` FPGA. : warning: If it is a flying lead connection, make sure that the length of the connecting line is within 10 cm; if it is a PCB connection, make sure that it is connected to the `usb_dn` differential distribution line.
- The `usb_dp_pull` FPGA is connected through a 1.5kΩ resistor.
- The FPGA `GND` is connected to the USB connector.
- The USB connector `VBUS` is a 5V, 500ma power supply, which can be disconnected or supply power to the FPGA.
Please connect the circuit according to the figure below. Where `usb_dp_pull`, `usb_dp`, `usb_dn` are the three common IO pins of FPGA (must be 3.3 V). Note that:
- If you use flying leads for connection, ensure that the length of flying leads not longer than 10 cm.
- If you use PCB for connection, note that `USB_D-` and `USB_D+` are differential pairs.
- The `usb_dp_pull` should connect to `USB_D+` through a 1.5kΩ resistor.
- Don't forget to connect `GND`
- The `VBUS` pin of USB connector `VBUS` is a 5V power source that comes from USB-host, it can be ignored, or can supply power for FPGA.
```
_________________
| |
| usb_dp_pull |-------|
| usb_dp_pull* |-------|
| | |
| | |-| 1.5k resistor
| | | |
| | |_| ____________ __________
| | | | | |
| usb_dp |-------^---------| USB_D+ | |
| | | | USB cable |
| usb_dn |-----------------| USB_D- |<================>| Host PC
| | | | |
| GND |-----------------| GND | |
| | | | |
----------------- ------------ ----------
FPGA USB 连接座 电脑
图 : FPGA 连接 USB 的方法
| | |_| ____________ __________
| | | | | |
| usb_dp* |-------^-------------| USB_D+ | |
| | | | USB cable |
| usb_dn* |---------------------| USB_D- |<===========================>| Host PC
| | | | |
| GND |---------------------| GND | |
| | | | |
----------------- ------------ ----------
FPGA USB connector (Type-B, mini, micro, or Type-C) Host PC
*: usb_dp_pull, usb_dp, usb_dn are common 3V3 IO pins of FPGA.
Figure : Connect FPGA to USB
```
 
# II List of Code Documents
# II List of Design code
[RTL](./RTL) The folder contains all the code, which is divided into three folders according to the level:
[RTL](./RTL) The folder contains all the design source code, which is divided into 3 folders according to the level:
| 文件夹 | 层级 |Explain|
| Folder | Level |Description|
| :--------------------------------------: | :-------------: | :----------------------------------------------------------- |
| [RTL/fpga_examples](./RTL/fpga_examples) | 应用层 |Realize the specific application function on the basis of USB class. In order to facilitate testing, the application functions implemented here are very simple, such as loopback testing USB-Serial and generating black and white stripes to the USB camera. You can develop complex applications such as capturing data from a CMOS image sensor to a USB camera.|
| [RTL/usb_class](./RTL/usb_class) | USB class |Some USB classes are implemented on the basis of USB device core. For example, USB Communication Device Class (USB-CDC) is used to realize USB-Serial; USB Video Class (UVC) is used to realize camera.|
| [RTL/usbfs_core](./RTL/usbfs_core) | USB device core |A universal USB device core, which implements the processing of USB low-level signals, including from bit-level to transaction-level. Developers familiar with the USB stack can use it to develop more USB devices. See [Secondary development of USB device](#usbcore).|
| [RTL/fpga_examples](./RTL/fpga_examples) | Application |Realize specific applications based on USB class. To facilitate testing, the applications here are very simple. You can develop complex applications such as capturing data from a CMOS sensor and sending to the USB UVC core.|
| [RTL/usb_class](./RTL/usb_class) | USB class |Realize some USB class cores based on the USB device core.|
| [RTL/usbfs_core](./RTL/usbfs_core) | USB device core |A universal USB device core, which implements USB protocol stack from signal-level to transaction-level. Developers that know well about the USB protocol can use it to develop more USB devices. See [Development using USB core](#usbcore_en).|
 
Specifically, each code file is described as follows:
Specifically, each source code file is listed as follows:
| 文件夹 | 文件名 |Explain|
| Folder | File Name |Description|
| :--------------------------------------: | :----------------------: | :----------------------------------------------------------- |
| [RTL/fpga_examples](./RTL/fpga_examples) | fpga_top_usb_audio.v |Connect the speaker of the USB _ audio _ top. V to the microphone in a loop, and the sound from the speaker will be recorded by the microphone.|
| [RTL/fpga_examples](./RTL/fpga_examples) | fpga_top_usb_camera.v |Generates a black and white stripe for the USB _ camera _ top. V, which can be seen with the camera software|
| [RTL/fpga_examples](./RTL/fpga_examples) | fpga_top_usb_disk.v |The USB flash disk of 24 KB FAT16 file system is implemented with USB _ disk _ top. V.|
| [RTL/fpga_examples](./RTL/fpga_examples) | fpga_top_usb_keyboard.v |Nerating a key signal to the USB _ keyboard _ top. V every 2 seconds;|
| [RTL/fpga_examples](./RTL/fpga_examples) | fpga_top_usb_serial.v |By looping back the sending and receiving of USB _ serial _ top. V, the transmitted characters are echoed back to the computer|
| [RTL/fpga_examples](./RTL/fpga_examples) | fpga_top_usb_serial2.v |Connect the send and receive loops of the USB _ serial2 _ top. V, and the characters sent on the computer will be echoed|
| [RTL/usb_class](./RTL/usb_class) | usb_audio_top.v |Composite device, including 2 USB Audio Class (UAC), implementation|
| [RTL/usb_class](./RTL/usb_class) | usb_camera_top.v |USB Video Class (UVC) **USB camera**|
| [RTL/usb_class](./RTL/usb_class) | usb_disk_top.v |USB Mass Storage Class (USB-MSC) Implementation|
| [RTL/usb_class](./RTL/usb_class) | usb_keyboard_top.v |USB Human Interface Device Class (USB-HID) Implementation|
| [RTL/usb_class](./RTL/usb_class) | usb_serial_top.v |USB Communication Device Class (USB-CDC) Implementation|
| [RTL/usb_class](./RTL/usb_class) | usb_serial2_top.v |Composite device, containing 2 USB-CDCs, implementation of|
| [RTL/usbfs_core](./RTL/usbfs_core) | **usbfs_core_top.v** |Top module of USB device core|
| [RTL/usbfs_core](./RTL/usbfs_core) | usbfs_transaction.v |Implement USB transaction-level, which is called by usbfs _ core _ top. V.|
| [RTL/usbfs_core](./RTL/usbfs_core) | usbfs_packet_rx.v |Implement USB packet-level RX, which is called by the usbfs _ core _ top. V.|
| [RTL/usbfs_core](./RTL/usbfs_core) | usbfs_packet_tx.v |Realize USB packet-level TX, called by usbfs _ core _ top. V.|
| [RTL/usbfs_core](./RTL/usbfs_core) | usbfs_bitlevel.v |Realize USB bit-level and be called by usbfs _ core _ top. V.|
| [RTL/usbfs_core](./RTL/usbfs_core) | usbfs_debug_monitor.v |Collects debug information (does not interfere with USB functionality) and is called by the usbfs _ core _ top. V.|
| [RTL/usbfs_core](./RTL/usbfs_core) | uart_tx.v |Convert the debugging information to a UART signal, which is called by the usbfs _ core _ top. V.|
The following describes how to use each USB class provided by this library one by one. It will be introduced [Secondary development based on USB device core](#usbcore) at the end.
| [RTL/fpga_examples](./RTL/fpga_examples) | fpga_top_usb_audio.v |Simple demo of using usb_audio_top.v. Let FPGA be a USB speaker & microphone with loopback connection, so that the speaker's voice will recorded by the microphone.|
| [RTL/fpga_examples](./RTL/fpga_examples) | fpga_top_usb_camera.v |Simple demo of using usb_camera_top.v. Let FPGA be a USB camera that generates a black and white stripe video.|
| [RTL/fpga_examples](./RTL/fpga_examples) | fpga_top_usb_disk.v |Simple demo of using usb_disk_top.v. Let FPGA be a USB flash disk with a 24 KB FAT16 file system.|
| [RTL/fpga_examples](./RTL/fpga_examples) | fpga_top_usb_keyboard.v |Simple demo of using usb_keyboard_top.v. Let FPGA be a USB keyborad that pressing a key every 2 seconds.|
| [RTL/fpga_examples](./RTL/fpga_examples) | fpga_top_usb_serial.v |Simple demo of using usb_serial_top.v. Let FPGA be a USB serial port device.|
| [RTL/fpga_examples](./RTL/fpga_examples) | fpga_top_usb_serial2.v |Simple demo of using usb_serial2_top.v. Let FPGA be a two-channel USB serial port device.|
| [RTL/usb_class](./RTL/usb_class) | usb_audio_top.v |use **usbfs_core_top.v** to implement USB speaker & microphone|
| [RTL/usb_class](./RTL/usb_class) | usb_camera_top.v |use **usbfs_core_top.v** to implement USB Video Class (UVC) camera|
| [RTL/usb_class](./RTL/usb_class) | usb_disk_top.v |use **usbfs_core_top.v** to implement USB Mass Storage Class (MSC) disk|
| [RTL/usb_class](./RTL/usb_class) | usb_keyboard_top.v |use **usbfs_core_top.v** to implement USB Human Interface Device Class (HID) keyboard|
| [RTL/usb_class](./RTL/usb_class) | usb_serial_top.v |use **usbfs_core_top.v** to implement USB Communication Device Class (CDC) serial port|
| [RTL/usb_class](./RTL/usb_class) | usb_serial2_top.v |use **usbfs_core_top.v** to implement a composite device, including 2 USB-CDC serial ports|
| [RTL/usbfs_core](./RTL/usbfs_core) | **usbfs_core_top.v** |Top module of the USB device core|
| [RTL/usbfs_core](./RTL/usbfs_core) | usbfs_transaction.v |USB transaction-level controller, called by usbfs_core_top.v.|
| [RTL/usbfs_core](./RTL/usbfs_core) | usbfs_packet_rx.v |USB packet-level RX controller, called by usbfs_core_top.v.|
| [RTL/usbfs_core](./RTL/usbfs_core) | usbfs_packet_tx.v |USB packet-level TX controller, called by usbfs_core_top.v.|
| [RTL/usbfs_core](./RTL/usbfs_core) | usbfs_bitlevel.v |USB bit-level controller (PHY) , called by usbfs_core_top.v.|
| [RTL/usbfs_core](./RTL/usbfs_core) | usbfs_debug_monitor.v |Collects and send out debug information. only for debug|
| [RTL/usbfs_core](./RTL/usbfs_core) | usbfs_debug_uart_tx.v |Convert the debug information to a UART signal. only for debug|
The following sections describe how to use these USB classes.
 
# Ⅲ USB audio
The USB audio device in this library implements speaker + microphone. The code file calling relationship is as follows. Please add these files to the FPGA project, compile and burn them to the FPGA.
The USB audio device implements speaker + microphone. The file hierarchy is as follows. Please add these files to the FPGA project, compile and program it to the FPGA.
- RTL/fpga_examples/**fpga_top_usb_audio.v**
- RTL/usb_class/**usb_audio_top.v**
- RTL/usbfs_core/**usbfs_core_top.v**
- Other.sv files in RTL/usbfs _ core/ (not listed individually)
- Other .v files in RTL/usbfs_core/
> The USB core of this :warning: library requires a 60 MHz drive clock. Altera's altpll primitive is **fpga_top_usb_audio.v** called to convert the crystal's 50MHz clock to a 60MHz clock. If your FPGA is not a Altera Cyclone IV, remove the altpll part of the code and use the corresponding primitive or IP core to generate the 60 MHz clock. For Xilinx FPGAs, for example, Clock Wizard IP can be used.
> :warning: The USB core of this repo requires a 60 MHz driving clock. Since I use Altera Cyclone IV, an `altpll` primitive module is used in my code to convert inputted 50MHz clock to 60MHz clock. If your FPGA is not a Altera Cyclone IV, you should remove `altpll` module and use the corresponding primitive or IP core to generate 60 MHz clock. For example, for Xilinx FPGAs, you can use Clock Wizard IP.
### Test
After the USB is plugged in, open Windows Device Manager and you should see the speaker and microphone devices:
After the USB is plugged in, open the Windows Device Manager, you would find a device:
![](./figures/ls_audio.png)
Because **fpga_top_usb_audio.v** the speaker and the microphone are connected in a loop, the playback of the speaker is recorded by the microphone. To test, first select the device as the audio output device:
Because **fpga_top_usb_audio.v** loopback connects the speaker and the microphone, the played voice of the speaker will be recorded by the microphone.
For testing, first select the device as the audio output device:
![](./figures/select_audio.png)
Then play a random music. Then use any recording software or video recording software (such as obstudio), select FPGA-USB-Audio as the input microphone, and record an audio or video. In the end you will find that the recorded audio is the same as the music you play.
Then play a music. Meanwhile use any recording software or video recording software (such as obstudio), select FPGA-USB-audio as the input microphone, and record an audio. Finally you will find that the recorded audio is the same as the music you played.
### Application development
You can develop more complex audio applications based on this simple example, for which you need to pay attention to **usb_audio_top.v** the module interface. See the code comments for details, so I won't repeat them here.
You can develop more complex audio applications based on this simple example, for which you need to pay attention to the in/out ports of **usb_audio_top.v** . See the code comments for details.
 
# IV USB camera
The calling relationship of the code file of the USB camera device in this library is as follows. Please add these files to the FPGA project, compile and burn them to the FPGA.
The file hierarchy is as follows. Please add these files to the FPGA project, compile and program it to the FPGA.
- RTL/fpga_examples/**fpga_top_usb_camera.v**
- RTL/usb_class/**usb_camera_top.v**
- RTL/usbfs_core/**usbfs_core_top.v**
- Other.sv files in RTL/usbfs _ core/ (not listed individually)
- Other .v files in RTL/usbfs_core/
> The USB core of this :warning: library requires a 60 MHz drive clock. Altera's altpll primitive is **fpga_top_usb_camera.v** called to convert the crystal's 50MHz clock to a 60MHz clock. If your FPGA is not a Altera Cyclone IV, remove the altpll part of the code and use the corresponding primitive or IP core to generate the 60 MHz clock. For Xilinx FPGAs, for example, Clock Wizard IP can be used.
> :warning: The USB core of this repo requires a 60 MHz driving clock. Since I use Altera Cyclone IV, an `altpll` primitive module is used in my code to convert inputted 50MHz clock to 60MHz clock. If your FPGA is not a Altera Cyclone IV, you should remove `altpll` module and use the corresponding primitive or IP core to generate 60 MHz clock. For example, for Xilinx FPGAs, you can use Clock Wizard IP.
### Test
After the USB is plugged in, open the Windows Device Manager and you should see the camera device:
After the USB is plugged in, open the Windows Device Manager, you would find a device:
![](./figures/ls_camera.png)
Open the camera software that comes with Windows 10, and you should see a scrolling black and white stripe:
Open the "camera" software of Windows, you would see a scrolling black and white stripe:
![](./figures/test_camera.png)
### Application development
You can develop more complex camera applications based on this simple example, for which you need to pay attention to **usb_camera_top.v** the module interface (see code comments for details).
You can develop more camera applications based on this simple example, for which you need to pay attention to the in/out ports of **usb_camera_top.v**
#### Parameters of USB _ camera _ top. V.
#### Parameters of usb_camera_top.v
The key parameters are described here:
The key parameters are listed here:
```verilog
@ -219,33 +219,39 @@ parameter [13:0] FRAME_W = 14'd320, // video-frame width in pixels, must b
parameter [13:0] FRAME_H = 14'd240, // video-frame height in pixels, must be a even number
```
You can set the width and height of the video frame with `FRAME_W` and `FRAME_H`. `FRAME_TYPE` Desirable `"MONO"` or `"YUY2"`.
You can set the width and height of the video frame by modifying parameter `FRAME_W` and `FRAME_H`.
As for paramter `FRAME_TYPE` , it can be `"MONO"` or `"YUY2"` .
##### FRAME_TYPE="MONO"
`FRAME_TYPE="MONO"` Is a grayscale mode, and each pixel corresponds to a lightness value of 1 byte. For example, for a 4x3 video frame, the module reads the following 12 bytes successively from the outside world:
`FRAME_TYPE="MONO"` Is grayscale mode. Each pixel is a 1-byte luminance value (0-255).
For example, for a 4x3 video frame, each frame has 12 pixels. While working, the user should send following 12 bytes successively to the module:
```
Y00 Y01 Y02 Y03 Y10 Y11 Y12 Y13 Y20 Y21 Y22 Y23
```
Where Y00 is the lightness value of row 0, column 0; Y01 is the lightness value of row 0, column 1;..
Where Y00 is the luminance value of row0 column0; Y01 is the luminance value of row0, column1; ......
##### FRAME_TYPE="YUY2"
`FRAME_TYPE="YUY2"` A color mode, also known as YUYV, in which each pixel has an independent 1-byte lightness value (Y), while two adjacent pixels share a 1-byte blue chrominance (U) and a 1-byte red chrominance (Y). For example, for a 4x2 video frame, the module reads the following 16 bytes successively from the outside world:
`FRAME_TYPE="YUY2"` is color mode, also known as YUYV, in which each pixel has an independent 1-byte luminance value (Y), while two adjacent pixels share a 1-byte blue chroma value (U) and a 1-byte red chroma value (V).
For example, for a 4x2 video frame, the user should send following 12 bytes successively to the module:
```
Y00 U00 Y01 V00 Y02 U02 Y03 V02 Y10 U10 Y11 V10 Y12 U12 Y13 V12
```
Where (y00, u00, v00) is the pixel at the 0th row and the 0th column; (y01, u00, v00) is the pixel at the 0th row and the 1st column; (y02, u02, v02) are the pixels at the 2nd row and the 2nd column; and (y03, u02, v02) are the pixels at the 3rd row and 3rd column.
Where (Y00, U00, V00) is the pixel of row0 column0; (Y01, U00, V00) is the pixel of row0 column1; (Y02, U02, V02) is the pixel of row0 column2; (Y03, U02, V02) is the pixel of row0 column3. (Y12, U10, V10) is the pixel of row1 column0; ...
#### USB _ camera _ top. V signal
#### Ports of usb_camera_top.v
The signal **usb_camera_top.v** used to read the pixel from the outside is:
The ports of **usb_camera_top.v** used to read the pixel from the outside is:
```verilog
@ -255,42 +261,46 @@ output reg vf_req, // 00000000000000000100010001000100010
input wire [ 7:0] vf_byte, // // a byte of pixel data
```
Video frames **usb_camera_top.v** are continuously read and sent to the Host-PC via the above signals. At the beginning of each video frame, `vf_sof` a cycle of high levels occurs. The next highest level will then `vf_req` occur **N** intermittently, where **N** is the number of bytes of the video frame, for `FRAME_TYPE="MONO"`, **N** = frame width X frame height; For `FRAME_TYPE="YUY2"`, **N** = 2 × frame width × frame height. Each time `vf_req=1`, the outside world should provide a byte (pixel data) onto the `vf_byte` signal, which should be asserted on `vf_req=1` the fourth clock cycle `vf_byte` at the latest and remain asserted until the next time `vf_req=1`.
**usb_camera_top.v** will continuously input and sent frames to the Host-PC.
At the beginning of each video frame, `vf_sof=1` pulses for one cycle. Then `vf_req=1` pulses for **N** cycles, where **N** is the number of bytes of the video frame, for `FRAME_TYPE="MONO"`, **N** = frame width × frame height; For `FRAME_TYPE="YUY2"`, **N** = 2 × frame width × frame height. Each time when `vf_req=1`, the outside world should provide a byte onto `vf_byte` signal, which should be valid at most 4 cycles after `vf_req=1` and keep until the next time when `vf_req=1`.
### Frame rate and performance
This module sends the video to the Host-PC with a fixed bandwidth. The larger the video frame size, the smaller the frame rate. The theoretical bandwidth of USB Full Speed is 12Mbps. In fact, the module sends 800 bytes of pixel data (400 pixels) every 1ms. Therefore, the approximate calculation formula of the frame rate is:
This module sends the video to the Host-PC with a fixed speed. The larger the video frame size, the smaller the frame rate. The theoretical bandwidth of USB Full Speed is 12Mbps. In fact, the module sends 800 bytes of pixel data (400 pixels) every 1ms. Therefore, the approximate calculation formula of the frame rate is:
Frame Rate = 400000/ (Frame Width * Frame Height)
Frame Rate = 400000/ (Frame Width × Frame Height)
 
# Ⅴ U disk
The calling relationship of the code file of the U disk device in this library is as follows. Please add these files to the FPGA project, compile and burn them to the FPGA.
The file hierarchy is as follows. Please add these files to the FPGA project, compile and program it to the FPGA.
- RTL/fpga_examples/**fpga_top_usb_disk.v**
- RTL/usb_class/**usb_disk_top.v**
- RTL/usbfs_core/**usbfs_core_top.v**
- Other.sv files in RTL/usbfs _ core/ (not listed individually)
- Other .v files in RTL/usbfs_core/
> The USB core of this :warning: library requires a 60 MHz drive clock. Altera's altpll primitive is **fpga_top_usb_disk.v** called to convert the crystal's 50MHz clock to a 60MHz clock. If your FPGA is not a Altera Cyclone IV, remove the altpll part of the code and use the corresponding primitive or IP core to generate the 60 MHz clock. For Xilinx FPGAs, for example, Clock Wizard IP can be used.
> :warning: The USB core of this repo requires a 60 MHz driving clock. Since I use Altera Cyclone IV, an `altpll` primitive module is used in my code to convert inputted 50MHz clock to 60MHz clock. If your FPGA is not a Altera Cyclone IV, you should remove `altpll` module and use the corresponding primitive or IP core to generate 60 MHz clock. For example, for Xilinx FPGAs, you can use Clock Wizard IP.
### Test
After the USB is plugged in, open Windows Device Manager and you should see a hard drive:
After the USB is plugged in, open the Windows Device Manager, you would find a device:
![](./figures/ls_disk.png)
Windows File Explorer should see the hard drive with a "file" example. Txt ". You can add, modify and delete files in this hard disk. Since it is implemented with the FPGA's on-chip memory (BRAM), all your modifications will disappear when the FPGA is powered off or reburned. The free space of this hard disk is only 3.5 KB, which is basically useless and only for testing.
And you would see a new disk in Windows File Explorer, with one file "example,txt" in it.
![](./figures/test_disk.png)
Since it is implemented with the FPGA's on-chip memory (BRAM), all your modifications will disappear when the FPGA is powered off or re-programed. The free space of this hard disk is only 3.5 KB, which is basically useless and only for testing.
### Application development
You can develop larger or more complex USB-disks based on this simple example, for which you need to pay attention to **usb_disk_top.v** the module interface (see code comments for details).
You can develop larger or more complex USB-disks based on this simple example, for which you need to pay attention to the in/out ports **usb_disk_top.v** (see code comments for details).
The key signals are described here, including:
The key ports including:
```verilog
@ -301,43 +311,45 @@ output reg [ 7:0] mem_wdata, // byte to write
input wire [ 7:0] mem_rdata, // byte to read
```
These signals are used for reading and writing **Storage space of hard disk**. `mem_addr` Is a 41-bit byte address, so the addressing space is 2 ^ 41 = 2 TB. However, the actual hard disk storage space must be less than 2 TB, so only the addresses from `mem_addr=0` to `mem_addr=硬盘容量` are valid. At each clock cycle:
These signals are used for reading and writing the **Storage space of hard disk**. `mem_addr` Is a 41-bit byte address, so the accessable addressing space is 2^41=2TB.
At each clock cycle:
- If `mem_wen=1`, the Host wants to write one byte of data to the device, the write address is `mem_addr`, and the write data is `mem_wdata`;
- If `mem_wen=0` the device needs to read a byte of data, the read address is `mem_addr`, and the read data should be sent to the `mem_rdata` next cycle.
- If `mem_wen=0` the device needs to read a byte of data, the read address is `mem_addr`, and the read data should appear on `mem_rdata` on the next cycle.
This interface is very easy to connect to the BRAM of FPGA, so we use BRAM to realize the storage space of hard disk.
This interface is very easy to connect to the BRAM of FPGA.
In order for disk to be recognized as a formatted hard disk, you can provide an initial data to the BRAM, which contains a file system. The BRAM **fpga_top_usb_disk.v** in implements a FAT16 file system with a total size of 24KB.
In order for disk to be recognized as a formatted hard disk, you can provide an initial data to the BRAM, which contains a file system.
> :warning: A file system is a data structure used to organize files and is stored on the hard disk as the files themselves. The production method is more complicated and will not be repeated here. If you need to make a customized U disk device, you can contact me through issue.
> :warning: A file system is a data structure used to organize files and is stored on the hard disk. The production method is quite complicated and will not be describe here. If you need to make a customized U disk device, you can contact me through issue or email.
 
# VI USB keyboard
The calling relationship of the code file of the USB keyboard device in this library is as follows. Please add these files to the FPGA project, compile and burn them to the FPGA.
The file hierarchy is as follows. Please add these files to the FPGA project, compile and program it to the FPGA.
- RTL/fpga_examples/**fpga_top_usb_keyboard.v**
- RTL/usb_class/**usb_keyboard_top.v**
- RTL/usbfs_core/**usbfs_core_top.v**
- Other.sv files in RTL/usbfs _ core/ (not listed individually)
- Other .v files in RTL/usbfs_core/
> The USB core of this :warning: library requires a 60 MHz drive clock. Altera's altpll primitive is **fpga_top_usb_keyboard.v** called to convert the crystal's 50MHz clock to a 60MHz clock. If your FPGA is not a Altera Cyclone IV, remove the altpll part of the code and use the corresponding primitive or IP core to generate the 60 MHz clock. For Xilinx FPGAs, for example, Clock Wizard IP can be used.
> :warning: The USB core of this repo requires a 60 MHz driving clock. Since I use Altera Cyclone IV, an `altpll` primitive module is used in my code to convert inputted 50MHz clock to 60MHz clock. If your FPGA is not a Altera Cyclone IV, you should remove `altpll` module and use the corresponding primitive or IP core to generate 60 MHz clock. For example, for Xilinx FPGAs, you can use Clock Wizard IP.
### Test
After the USB is plugged in, open Windows Device Manager and you should see a keyboard device:
After the USB is plugged in, open the Windows Device Manager, you would find a device:
![](./figures/ls_keyboard.png)
The keyboard presses the English letter keys every 2 seconds. Open a notepad to see the effect.
The keyboard will press a English letter key every 2 seconds.
### Application development
You can develop more complex keyboard applications based on this simple example, for which you need to pay attention to **usb_keyboard_top.v** the module interface (see code comments for details).
You can develop more complex keyboard applications based on this simple example, for which you need to pay attention to the in/out ports of **usb_keyboard_top.v** (see code comments for details).
Here, the signal used to transmit the key signal is described:
Note the following signals:
```verilog
@ -346,36 +358,36 @@ input wire [15:0] key_value, // Indicates which key to press, NOT ASCII cod
input wire key_request, // when key_request=1 pulses, a key is pressed.
```
`key_request` Usually needs to maintain 0, when you need to press a key, need to let `key_request=1` a cycle, at the same time on `key_value` the input code corresponding to the key. Refer to https://www.usb.org/sites/default/files/hut1_21_0.pdf Section 10 for the definition of key code. For example, keys' a '- `key_value=16'h0004~16'h001D` ' Z 'correspond, and keys' 1'- `key_value=16'h001E~16'h0027` '0' correspond.
`key_request` usually needs to maintain 0, when you need to press a key, let `key_request=1` for a cycle, meanwhile set a key code on `key_value` . Refer to https://www.usb.org/sites/default/files/hut1_21_0.pdf Section 10 for the definition of key code. For example, keys 'A'-'Z' corresponds to `key_value=16'h0004~16'h001D`
 
# Ⅶ USB-Serial
The calling relationship of the code file of the USB-Serial device in this library is as follows. Please add these files to the FPGA project, compile and burn them to the FPGA.
The file hierarchy is as follows. Please add these files to the FPGA project, compile and program it to the FPGA.
- RTL/fpga_examples/**fpga_top_usb_serial.v**
- RTL/usb_class/**usb_serial_top.v**
- RTL/usbfs_core/**usbfs_core_top.v**
- Other.sv files in RTL/usbfs _ core/ (not listed individually)
- Other .v files in RTL/usbfs_core/
> The USB core of this :warning: library requires a 60 MHz drive clock. Altera's altpll primitive is **fpga_top_usb_serial.v** called to convert the crystal's 50MHz clock to a 60MHz clock. If your FPGA is not a Altera Cyclone IV, remove the altpll part of the code and use the corresponding primitive or IP core to generate the 60 MHz clock. For Xilinx FPGAs, for example, Clock Wizard IP can be used.
> :warning: The USB core of this repo requires a 60 MHz driving clock. Since I use Altera Cyclone IV, an `altpll` primitive module is used in my code to convert inputted 50MHz clock to 60MHz clock. If your FPGA is not a Altera Cyclone IV, you should remove `altpll` module and use the corresponding primitive or IP core to generate 60 MHz clock. For example, for Xilinx FPGAs, you can use Clock Wizard IP.
### Test
After the USB is plugged in, open the Windows Device Manager and you should see a USB-serial device:
After the USB is plugged in, open the Windows Device Manager, you would find a device:
![](./figures/ls_serial.png)
In this example, the **usb_serial_top.v** received data is converted from lowercase letters to uppercase letters according to ASCII code, and then looped back to the sending interface. You can send data to Serial Port with minicom, putty, HyperTerminal, and Serial Assistant software on Host-PC, and the sent data will be echoed (with lowercase letters converted to uppercase letters). Take the serial port assistant as an example, as shown in the figure below.
In this example, the **usb_serial_top.v** received data is converted from lowercase letters to uppercase letters (ASCII code), and then looped back to the sending interface. You can send data to Serial Port using minicom, putty, HyperTerminal, or Serial Assistant software on Host-PC, and the sent data will be echoed (with lowercase letters converted to uppercase letters). As shown in figure below.
![](./figures/test_serial.png)
> :warning: Because the Serial-Port is not a true UART, it is also called **Virtual serial port**. Setting the baud rate, data bit, check bit, and stop bit of the virtual serial port will not have any effect.
> :warning: Because this USB-CDC-based Serial-Port is not a true UART, it is also called **Virtual serial port**. So there will be no any effects when you change baud rate, data bit, check bit, and stop bits.
### Application development
You can develop more complex Serial-Port communication applications based on this simple example, for which you need to pay attention to **usb_serial_top.v** the module interface (see the code comments for details).
You can develop more complex Serial-Port communication applications based on this simple example, for which you need to pay attention to the in/out ports of **usb_serial_top.v** (see the code comments for details).
The key signals are described here, including:
@ -391,85 +403,85 @@ input wire send_valid, // when device want to send a data byte, set s
output wire send_ready, // send_ready handshakes with send_valid. send_ready=1 indicates send-buffer is not full and will accept the byte on send_data. send_ready=0 indicates send-buffer is full and cannot accept a new byte.
```
The signal of host-to-device is relatively simple. Every time a data byte is received, `recv_valid` the high level of a cycle appears, and the byte appears at the same time `recv_data`.
The signal of host-to-device is relatively simple. Every time a data byte is received, `recv_valid` will become high of one cycle, and the byte will appear on `recv_data` at the same time.
The device-to-host signal is in the opposite direction, and there is an `send_ready` extra signal, `send_ready=0` indicating that the send buffer inside the module is full and cannot send new data for the time being. `send_ready` And `send_valid` form a handshake signal, when the user needs to send a byte, should let `send_valid=1`, at the same time let the byte appear again `send_data`. At `send_valid=1 && send_ready=1` that point, the byte is successfully sent to the send buffer, and the user can proceed to send the next byte. The handshake mechanism is similar to AXI-stream.
The device-to-host signal is in the opposite direction, and there is an `send_ready` signal, `send_ready=0` indicating that the send buffer inside the module is full and cannot send new data temporarily. `send_ready` And `send_valid` form a handshake signal, when the user needs to send a byte, he should let `send_valid=1`, at the same time let the byte appear on `send_data`. When `send_valid=1 && send_ready=1` , the byte is successfully sent to the send buffer, and the user can proceed to send the next byte. This handshake mechanism is similar to AXI-stream.
There is a send buffer of 1024 bytes **usb_serial_top.v** in. If the throughput rate of the data to be sent is not large, the send buffer will never be full, and the signal can also be ignored `send_ready`. However, when the data throughput rate is large, which may cause the sending buffer to be full, some data may be lost if the situation is ignored `send_ready=0`.
There is a send buffer of 1024 bytes in **usb_serial_top.v** . If the send throughput is not large, the send buffer will never be full, in this case you can ignore `send_ready`. However, when the send throughput is large, which may cause the sending buffer to be full, then `send_ready` shouldn't be ignored.
 
# Ⅷ Dual-channel USB-Serial
The calling relationship of the code file of the dual-channel USB-Serial device in this library is as follows. Please add these files to the FPGA project, compile and burn them to the FPGA.
The file hierarchy is as follows. Please add these files to the FPGA project, compile and program it to the FPGA.
- RTL/fpga_examples/**fpga_top_usb_serial2.v**
- RTL/usb_class/**usb_serial2_top.v**
- RTL/usbfs_core/**usbfs_core_top.v**
- Other.sv files in RTL/usbfs _ core/ (not listed individually)
- Other .v files in RTL/usbfs_core/
> The USB core of this :warning: library requires a 60 MHz drive clock. Altera's altpll primitive is **fpga_top_usb_serial2.v** called to convert the crystal's 50MHz clock to a 60MHz clock. If your FPGA is not a Altera Cyclone IV, remove the altpll part of the code and use the corresponding primitive or IP core to generate the 60 MHz clock. For Xilinx FPGAs, for example, Clock Wizard IP can be used.
> :warning: The USB core of this repo requires a 60 MHz driving clock. Since I use Altera Cyclone IV, an `altpll` primitive module is used in my code to convert inputted 50MHz clock to 60MHz clock. If your FPGA is not a Altera Cyclone IV, you should remove `altpll` module and use the corresponding primitive or IP core to generate 60 MHz clock. For example, for Xilinx FPGAs, you can use Clock Wizard IP.
### Test
After the USB is plugged in, open the Windows Device Manager and you should see 2 USB-serial devices:
After the USB is plugged in, open the Windows Device Manager, you would find two Serial devices:
![](./figures/ls_serial2.png)
The test method is the same as that of the single-channel USB-Serial, which will not be described here.
It's behavior is as same as the single-channel USB-Serial, which will not be described here.
### Application development
You can develop a more complex Serial-Port communication application based on this simple example. For this, you need to pay attention to **usb_serial2_top.v** the module interface (see the code comment for details). Its usage is the same as that of the single-channel USB-Serial, except that the sending and receiving interfaces have become dual-channel, which will not be repeated here.
You can develop a more complex Serial-Port communication application based on this simple example. For this, you need to pay attention to the in/out ports of **usb_serial2_top.v** (see the code comment for details). Its usage is as same as the single-channel USB-Serial, except that the sending and receiving interfaces become dual-channel, which will not be repeated here.
 
# <span id="usbcore"> Ⅸ Secondary development based on USB device core</span>
 
You can use to **usbfs_core_top.v** develop other USB devices, which provide:
# <span id="usbcore_en"> Ⅸ Development using USB device core</span>
- Customize 1 device descriptor, 1 configuration descriptor, and 6 string descriptors.
- In addition to the control endpoint (0 x00), four IN endpoints (0x81 \ ~ 0x84) and four OUT endpoints (0x01 \ ~ 0x04) are provided.
- The optional debug output interface prints the debug information to the computer through an additional UART, and the communication process of the USB data packet can be seen.
You can use my USB device core (**usbfs_core_top.v**) to develop more USB devices. The core provides:
The parameters and input and output signals of the are described below **usbfs_core_top.v**.
- Customize 1 device descriptor, 1 configuration descriptor, and 6 string descriptors.
- Four IN endpoints (0x81\~0x84) and four OUT endpoints (0x01\~0x04) .
- An optional debug interface for printing debug information to the computer via a UART, you can see the USB communication process through it.
### Parameters of usbfs _ core _ top. V.
The parameters and in/out ports of **usbfs_core_top.v** are described below.
**usbfs_core_top.v** The parameters are shown in the following table.
### Parameters of usbfs_core_top.v
| usbfs_core_top 的参数 | 类型 |Explain|
| Parameters | Type |Explain|
| --------------------- | --------------------------------------- | -------------------------------------------- |
| `DESCRIPTOR_DEVICE` | `logic[7:0][18]` (字节数组,长度为18) |Device descriptor|
| `DESCRIPTOR_STR1` | `logic[7:0][64]` (字节数组,长度为64) |String descriptor 1|
| `DESCRIPTOR_STR2` | `logic[7:0][64]` (字节数组,长度为64) |String Descriptor 2|
| `DESCRIPTOR_STR3` | `logic[7:0][64]` (字节数组,长度为64) |String Descriptor 3|
| `DESCRIPTOR_STR4` | `logic[7:0][64]` (字节数组,长度为64) |String Descriptor 4|
| `DESCRIPTOR_STR5` | `logic[7:0][64]` (字节数组,长度为64) |String Descriptor 5|
| `DESCRIPTOR_STR6` | `logic[7:0][64]` (字节数组,长度为64) |String Descriptor 6|
| `DESCRIPTOR_CONFIG` | `logic[7:0][512]` (字节数组,长度为512) |Configuration descriptor|
| `EP00_MAXPKTSIZE` | `logic[7:0]`| control endpoint 最大包大小 |
| `EP81_MAXPKTSIZE` | `logic[9:0]`| IN endpoint 0x81 最大包大小 |
| `EP82_MAXPKTSIZE` | `logic[9:0]`| IN endpoint 0x82 最大包大小 |
| `EP83_MAXPKTSIZE` | `logic[9:0]`| IN endpoint 0x83 最大包大小 |
| `EP84_MAXPKTSIZE` | `logic[9:0]`| IN endpoint 0x84 最大包大小 |
| `EP81_ISOCHRONOUS` |0 or 1| IN endpoint 0x81 是否是 isochronous 传输模式 |
| `EP82_ISOCHRONOUS` |0 or 1| IN endpoint 0x82 是否是 isochronous 传输模式 |
| `EP83_ISOCHRONOUS` |0 or 1| IN endpoint 0x83 是否是 isochronous 传输模式 |
| `EP84_ISOCHRONOUS` |0 or 1| IN endpoint 0x84 是否是 isochronous 传输模式 |
| `EP01_ISOCHRONOUS` |0 or 1| IN endpoint 0x01 是否是 isochronous 传输模式 |
| `EP02_ISOCHRONOUS` |0 or 1| IN endpoint 0x02 是否是 isochronous 传输模式 |
| `EP03_ISOCHRONOUS` |0 or 1| IN endpoint 0x03 是否是 isochronous 传输模式 |
| `EP04_ISOCHRONOUS` |0 or 1| IN endpoint 0x04 是否是 isochronous 传输模式 |
| `DEBUG` |TRUE or FALSE| 是否启用调试接口 |
> :warning: According to the USB 1.1 specification, when an endpoint is in isochronous transfer mode, the maximum packet size can be any value from 8 \ to 1023. When the endpoint is in interrupt or bulk transfer mode, the maximum packet size can only be 8, 16, 32, or 64.
### Usbfs _ core _ top. V signal
| `DESCRIPTOR_DEVICE` | `[18*8-1:0]` (can contain 18 bytes) |Device descriptor|
| `DESCRIPTOR_STR1` | `[64*8-1:0]` (can contain 64 bytes) |String descriptor 1|
| `DESCRIPTOR_STR2` | `[64*8-1:0]` (can contain 64 bytes) |String Descriptor 2|
| `DESCRIPTOR_STR3` | `[64*8-1:0]` (can contain 64 bytes) |String Descriptor 3|
| `DESCRIPTOR_STR4` | `[64*8-1:0]` (can contain 64 bytes) |String Descriptor 4|
| `DESCRIPTOR_STR5` | `[64*8-1:0]` (can contain 64 bytes) |String Descriptor 5|
| `DESCRIPTOR_STR6` | `[64*8-1:0]` (can contain 64 bytes) |String Descriptor 6|
| `DESCRIPTOR_CONFIG` | `[512*8-1:0]` (can contain 512 bytes) |Configuration descriptor|
| `EP00_MAXPKTSIZE` | `[7:0]` | max packet size of control endpoint |
| `EP81_MAXPKTSIZE` | `[9:0]` | max packet size of IN endpoint 0x81 |
| `EP82_MAXPKTSIZE` | `[9:0]` | max packet size of IN endpoint 0x82 |
| `EP83_MAXPKTSIZE` | `[9:0]` | max packet size of IN endpoint 0x83 |
| `EP84_MAXPKTSIZE` | `[9:0]` | max packet size of IN endpoint 0x84 |
| `EP81_ISOCHRONOUS` |0 or 1| Is IN endpoint 0x81 isochronous? |
| `EP82_ISOCHRONOUS` |0 or 1| Is IN endpoint 0x82 isochronous? |
| `EP83_ISOCHRONOUS` |0 or 1| Is IN endpoint 0x83 isochronous? |
| `EP84_ISOCHRONOUS` |0 or 1| Is IN endpoint 0x84 isochronous? |
| `EP01_ISOCHRONOUS` |0 or 1| Is OUT endpoint 0x01 isochronous? |
| `EP02_ISOCHRONOUS` |0 or 1| Is OUT endpoint 0x02 isochronous? |
| `EP03_ISOCHRONOUS` |0 or 1| Is OUT endpoint 0x03 isochronous? |
| `EP04_ISOCHRONOUS` |0 or 1| Is OUT endpoint 0x04 isochronous? |
| `DEBUG` |TRUE or FALSE| Enable Debug interface ? |
> :warning: According to USB 1.1 specification, when an endpoint is in isochronous transfer mode, the maximum packet size can be any value from 8 \ to 1023. When the endpoint is in interrupt or bulk transfer mode, the maximum packet size can only be 8, 16, 32, or 64.
### Ports of usbfs_core_top.v
#### Clock and Reset
The `clk` signal needs to be clocked at 60 MHz:
The `clk` signal needs to be 60 MHz:
```verilog
@ -477,7 +489,7 @@ The `clk` signal needs to be clocked at 60 MHz:
input wire clk, // 60MHz is required
```
The reset signal `rstn` should be set to high level during normal operation. If it is necessary to stop the operation, it can be `rstn` set to low level. At this time, if the USB is plugged into the Host-PC, the Host-PC will detect that the USB is unplugged.
The reset signal `rstn` should be set to high level during normal operation. If it is necessary to stop the operation, set `rstn` to low. At this time, if the USB is plugged into the Host-PC, the Host-PC will detect that the USB is unplugged.
```verilog
@ -487,7 +499,7 @@ input wire rstn, // active-low reset, reset when rstn=0 (USB will unpl
#### USB Signal
The following 3 signals need to be drawn to the pins of the FPGA and connected to the USB interface as per [电路连接方法](#circuit).
The following 3 signals need to be connect according to [Circuit connection](#circuit_en).
```verilog
@ -498,7 +510,9 @@ inout usb_dp, // USB D+
inout usb_dn, // USB D-
```
The `usb_rstn` signal indicates whether the USB is connected, high for connected and low for not connected. There are two possible reasons for no connection: either the USB cable is pulled out from the Host, or the FPGA side is actively reset ( `rstn=0`).
#### Signal for indicating whether the USB is plugged.
The `usb_rstn` signal indicates whether the USB is connected, high for connected and low for disconnected. There are two possible reasons for disconnection: either the USB cable is not plugged in the Host, or the FPGA side is in resetting state ( `rstn=0`).
```verilog
@ -508,7 +522,11 @@ output reg usb_rstn, // 1: connected , 0: disconnected (when USB cable unp
#### USB-transfer and USB-frame detection signal
The start of USB-transfer and USB-frame is indicated when the following two signals `sot` and `sof` are high for one cycle, respectively. USB-transfer refers to the whole process of USB transfer, including control transfer, interrupt transfer, bulk transfer and isochronous transfer. The USB-frame starts from the SOF token sent by the USB-host every 1ms, which can be used to guide the isochronous transfer.
When `sot` and `sof` are high for one cycle, it indicates that a USB-transfer or a USB-frame is detected, respectively.
USB-transfer refers to the whole process of USB transfer, including control transfer, interrupt transfer, bulk transfer and isochronous transfer.
USB-frame means a SOF token is sent from USB-host to USB-device every 1ms, which can be used to guide the isochronous transfer.
```verilog
@ -519,7 +537,7 @@ output reg sof, // detect a start of USB-frame
#### Response signal of control transfer
The following three signals `ep00_setup_cmd` `ep00_resp_idx` `ep00_resp` provide the interface for responding to a control transfer.
The following three signals `ep00_setup_cmd` `ep00_resp_idx` `ep00_resp` provide the interface for control transfer.
```verilog
@ -530,21 +548,23 @@ output wire [ 8:0] ep00_resp_idx,
input wire [ 7:0] ep00_resp,
```
According to the USB specification, control transfer is performed only on the control endpoint (0x00), and the Host will first send an 8-byte SETUP command. The device may respond with data to the Host. Based on the fields in `bmRequestType[6:5]` the SETUP command, control transfer can be divided into three categories:
According to the USB specification, control transfer is performed only on control endpoint (0x00), and the Host will first send an 8-byte SETUP command. The device may respond data packets to the Host. Based on the fields of `bmRequestType[6:5]` of the SETUP command, control transfer can be divided into three categories:
- Standard control transfer ( `bmRequestType[6:5]=0`)
- Class-specific control transfer ( `bmRequestType[6:5]=1`)
- Vendor-specific control transfer ( `bmRequestType[6:5]=2`)
Standard control transfer is used to respond to descriptor and other data **usbfs_core_top.v**, which is processed internally and does not need to be concerned by the developer. The developer only needs to specify the descriptor with parameter. Class-specific control transfer and vendor-specific control transfer are related to the implementation of specific devices, and developers can respond to them through these three signals. For example, the UVC device provided by this library uses it to respond to the UVC Video Probe and Commit Controls, while the HID device uses it to respond to the HID descriptor. In addition, some simple devices do not need Class-specific control transfer and Vendor-specific control transfer at all, so developers can ignore these three signals.
Standard control transfer is used to respond to descriptor and other data, which is processed internally in **usbfs_core_top.v** and does not need to be concerned by the developer. The developer only needs to specify the descriptor with parameter.
Class-specific control transfer and vendor-specific control transfer are related to the implementation of specific devices. Developers can respond to them through these three signals. For example, the UVC device provided by this repo uses it to respond to the UVC Video Probe and Commit Controls. In addition, some simple devices do not need Class-specific control transfer and Vendor-specific control transfer at all, so developers can ignore these three signals.
When a control transfer is performed, `ep00_setup_cmd` the 8-byte SETUP command appears on the signal first. The `ep00_resp_idx` signal is then incremented from 0, representing the byte in which the response is currently required. The developer needs to type the th `ep00_resp_idx` byte of the response data on the `ep00_resp` signal at any time.
When a control transfer is performed, the 8-byte SETUP command will appear on `ep00_setup_cmd` first. Then `ep00_resp_idx` signal will increase from 0, representing the byte address that the response is currently required. The developer needs to set `ep00_resp` to the corresponding byte at next cycle.
Taking the UVC device as an example, the following code detects whether the SETUP command requires the device to respond to the UVC Video Probe and Commit Controls. It responds to `UVC_PROBE_COMMIT` the first `ep00_resp_idx` byte in the array on the `ep00_resp` signal, otherwise it responds to `0x00` :
Taking the UVC device as an example, the following code detects whether the SETUP command requires the device to respond to the UVC Video Probe and Commit Controls.
```verilog
// 举例:在 UVC 设备中,当 host 请求 UVC Video Probe and Commit Controls 时,应该使用以下写法进行响应:
// In the UVC device, the host requests UVC Video Probe and Commit Controls, the following code is to respond this request:
always @ (posedge clk)
if(ep00_setup_cmd[7:0] == 8'hA1 && ep00_setup_cmd[47:16] == 32'h_0001_0100 )
ep00_resp <= UVC_PROBE_COMMIT[ep00_resp_idx];
@ -552,17 +572,17 @@ always @ (posedge clk)
ep00_resp <= '0;
```
For the content of the command and response data of control transfer, please refer to the specific protocol specification.
For the content of the command and response data of control transfer, please refer to the specific USB class's specification.
#### IN endpoint (0x81 \ ~ 0x84) data input signal
#### IN endpoint (0x81\~0x84) signals
The following 4 groups of signals correspond to 4 IN endpoints and are used to send device-to-host IN packets.
The following 4 groups of signals correspond to 4 IN endpoints and are used to send packets from device to host.
For example, if the FPGA needs to send an IN packet on the IN endpoint 0x81, the following is required:
- First, let `ep81_valid=1` and hold, while holding the 0th byte of the packet on `ep81_data`.
- `ep81_ready` And `ep81_valid` form a handshake signal. Each `ep81_ready` occurrence of a periodic high indicates that a byte has been successfully transmitted.
- In `ep81_ready=1` the next cycle, if the IN packet transmission is finished, the command `ep81_valid=0` is required. If the IN packet still has bytes to send, it will `ep81_data` be kept `ep81_valid=1` and updated to new bytes to be sent.
- First, let `ep81_valid=1` and hold, meanwhile holding the 0th byte of the packet on `ep81_data`.
- `ep81_ready` and `ep81_valid` form a pair of handshake signals. Each time when `ep81_ready=ep81_valid=1` , a byte is successfully transmitted.
- At the next cycle when `ep81_ready=1` , if the entire IN packet transmission is finished, let `ep81_valid=0` . If the IN packet still has bytes to send, keep `ep81_valid=1` and let `ep81_data` to be the next byte to be sent.
```verilog
@ -585,11 +605,11 @@ input wire ep84_valid, // when device want to send a data byte, asser
output wire ep84_ready, // handshakes with valid. ready=1 indicates the data byte can be accept.
```
#### OUT endpoint (0x01 \ ~ 0x04) data output signal
#### OUT endpoint (0x01\~0x04) signals
The following four groups of signals correspond to four OUT endpoints and are used to receive the OUT packet of the host-to-device.
The following four groups of signals correspond to four OUT endpoints and are used to receive the OUT packet from host to device.
For example, when `ep01_valid` a cycle of high occurs, a byte in the OUT packet is received, and the byte appears `ep01_data` on the. In addition, the boundary of the packet can be detected by the `sot` signal mentioned before.
For example, when `ep01_valid=1` for one cycle, a byte of OUT packet is received, the byte appears on `ep01_data` . In addition, the boundary of different packets can be detected by the `sot` signal mentioned before.
```verilog
@ -614,7 +634,9 @@ output wire ep04_valid, // when out_valid=1 pulses, a data byte is rec
#### Debug output interface
The following signals are used to print debug information to the outside world. The debug information is a stream of ASCII code bytes and is human readable. At `debug_en=1` that time, `debug_data` a byte appears on the.
To enable Debug interface, set the parameter `DEBUG=1` . Otherwise the debug interface will not output any data.
The following signals are used to print debug information to the outside world. The debug information is a stream of printable ASCII code bytes. When `debug_en=1` , one byte appears on `debug_data` .
```verilog
@ -625,7 +647,9 @@ output wire [ 7:0] debug_data, //
output wire debug_uart_tx // debug_uart_tx is the signal after converting {debug_en,debug_data} to UART (format: 115200,8,n,1). If you want to transmit debug info via UART, you can use this signal. If you want to transmit debug info via other custom protocols, please ignore this signal and use {debug_en,debug_data}.
```
In order to facilitate the use, I will also convert the `{debug_en,debug_data}` byte to bit UART output signal `debug_uart_tx`, which can be `debug_uart_tx` connected to the UART of the computer, and use the serial port assistant and other software to view the debugging information. Note that the UART should be configured with baud rate = 115200, data bits = 8, no parity bits, and stop bits = 1.
In order to facilitate the use, I will also convert the `{debug_en,debug_data}` to a UART output signal `debug_uart_tx` . You can connect the UART to PC, and use a Serial Port software (minicom, HyperTermainal, etc) to monitor the debugging information.
Note that the UART configurations are : baud rate=115200, data bits=8, no parity bits.
The following figure shows the debug data printed on the UART when my USB UVC device is plugged into the computer. As you can see, this is a descriptor enumeration process.
@ -633,9 +657,9 @@ The following figure shows the debug data printed on the UART when my USB UVC de
| :----------------------------------------------------: |
|**Figure**: Debugging data printed on the UART when the USB UVC device is plugged into the computer.|
> When :warning: using the debug interface, use the module parameters `DEBUG="TRUE"`. At `DEBUG="FALSE"` that time, `debug_en` 0 is maintained, and `debug_uart_tx` 1 is maintained (no debug information is output).
> :warning: Because the transmission speed of UART is slow, when a large amount of debugging information is generated, some debugging information will be discarded by UART. For example, when UVC transmits video, the information printed by UART is incomplete because of the large amount of data transmitted. Therefore, if the debugging information needs to be viewed in the process of a large amount of data communication, the UART cannot be used, but other high-speed communication methods are used to send it `{debug_en, debug_data}` to the Host-PC for viewing.
> :warning: Because the speed of UART is slow, when a large amount of debugging information is generated, some debugging information will be discarded. For example, when UVC transmits video, the information printed by UART is incomplete. If you want to view the full debugging information when large amount of USB data, you should use other high-speed communication to send `{debug_en, debug_data}` to Host-PC instead of UART.
 
@ -670,7 +694,9 @@ The following figure shows the debug data printed on the UART when my USB UVC de
USB 1.1 device 控制器。可在 FPGA 上实现各种 USB 设备。比如 USB扬声器和麦克风、USB摄像头、U盘、USB键盘、USB串口 。
为了在 FPGA 上实现 USB 设备,通常的技术路线是使用 USB 芯片 (例如 Cypress CY7C68013),导致电路和软件的开发成本较高。本库用 FPGA 实现一个通用的 USB 1.1 (Full Speed) device 控制器,可以像 STM32 单片机那样,用非常简单的电路来实现 USB 设备,而不依赖额外的 USB 芯片。基于此,我还在 FPGA 上实现了 USB音频、USB摄像头、U盘、USB键盘、USB-Serial (串口),它们是 USB 所规定的标准设备,因此不需要安装驱动就能即插即用。
为了在 FPGA 上实现 USB 设备,通常的技术路线是使用 USB 芯片 (例如 Cypress CY7C68013),导致电路和软件的开发成本较高。本库用 FPGA 实现一个通用的 USB 1.1 (Full Speed) device 控制器,可以像 STM32 单片机那样,用非常简单的电路来实现 USB 设备,而不依赖额外的 USB 芯片。
基于此,我还在 FPGA 上实现了 USB音频、USB摄像头、U盘、USB键盘、USB-Serial (串口),它们是 USB 所规定的标准设备,因此不需要安装驱动就能即插即用。
本库的特点:
@ -679,7 +705,7 @@ USB 1.1 device 控制器。可在 FPGA 上实现各种 USB 设备。比如 USB
如果你不熟悉 USB 协议栈,但想快速实现某种 USB 设备,可以使用我封装的一些 USB 功能:
- **USB音频** : 是一个复合设备,包括扬声器和麦克风 (双声道, 48ksps) ,提供接收扬声器音频数据、发送麦克风音频数据的流式接口。
- **USB音频** : 包括扬声器和麦克风 (双声道, 48ksps) ,提供接收扬声器音频数据、发送麦克风音频数据的流式接口。
- **USB摄像头** : 可向电脑传输视频(宽和高可自定义),提供发送视频数据的流式接口。
- **U盘**
- **USB键盘**:提供"按键按下"的控制接口。
@ -792,7 +818,7 @@ USB 具有 `VBUS`, `GND`, `USB_D-`, `USB_D+` 这4根线。以 USB Type B 连接
| [RTL/fpga_examples](./RTL/fpga_examples) | fpga_top_usb_keyboard.v | 每2秒生成一个按键信号给 usb_keyboard_top.v |
| [RTL/fpga_examples](./RTL/fpga_examples) | fpga_top_usb_serial.v | 把 usb_serial_top.v 的发送和接收回环连接,电脑上发送的字符会被回显 |
| [RTL/fpga_examples](./RTL/fpga_examples) | fpga_top_usb_serial2.v | 把 usb_serial2_top.v 的发送和接收回环连接,电脑上发送的字符会被回显 |
| [RTL/usb_class](./RTL/usb_class) | usb_audio_top.v | 复合设备,包括 2 个 USB Audio Class (UAC) ,实现 **USB扬声器+麦克风** |
| [RTL/usb_class](./RTL/usb_class) | usb_audio_top.v | 实现 **USB扬声器+麦克风** |
| [RTL/usb_class](./RTL/usb_class) | usb_camera_top.v | USB Video Class (UVC) 实现 **USB摄像头** |
| [RTL/usb_class](./RTL/usb_class) | usb_disk_top.v | USB Mass Storage Class (USB-MSC) 实现 **U盘** |
| [RTL/usb_class](./RTL/usb_class) | usb_keyboard_top.v | USB Human Interface Device Class (USB-HID) 实现 **USB键盘** |
@ -804,7 +830,7 @@ USB 具有 `VBUS`, `GND`, `USB_D-`, `USB_D+` 这4根线。以 USB Type B 连接
| [RTL/usbfs_core](./RTL/usbfs_core) | usbfs_packet_tx.v | 实现 USB packet-level TX,被 usbfs_core_top.v 调用 |
| [RTL/usbfs_core](./RTL/usbfs_core) | usbfs_bitlevel.v | 实现 USB bit-level,被 usbfs_core_top.v 调用 |
| [RTL/usbfs_core](./RTL/usbfs_core) | usbfs_debug_monitor.v | 收集调试信息(不干扰 USB 的功能),被 usbfs_core_top.v 调用 |
| [RTL/usbfs_core](./RTL/usbfs_core) | uart_tx.v | 将调试信息转为一个 UART 信号,被 usbfs_core_top.v 调用 |
| [RTL/usbfs_core](./RTL/usbfs_core) | usbfs_debug_uart_tx.v | 将调试信息转为一个 UART 信号,被 usbfs_core_top.v 调用 |
下文逐一介绍本库提供的每一个 USB class 的使用方法。最后会介绍 [基于 USB device core 的二次开发](#usbcore) 。
@ -817,13 +843,13 @@ USB 具有 `VBUS`, `GND`, `USB_D-`, `USB_D+` 这4根线。以 USB Type B 连接
- RTL/fpga_examples/**fpga_top_usb_audio.v**
- RTL/usb_class/**usb_audio_top.v**
- RTL/usbfs_core/**usbfs_core_top.v**
- RTL/usbfs_core/里的其它.sv文件(不逐个列出了)
- RTL/usbfs_core/里的其它.v文件(不逐个列出了)
> :warning: 本库的 USB core 需要 60MHz 的驱动时钟。**fpga_top_usb_audio.v** 里调用了 Altera 的 altpll 原语来把晶振的 50MHz 时钟转为 60MHz 时钟。如果你的 FPGA 不是 Altera Cyclone IV ,请删掉 altpll 部分的代码,然后用对应的原语或 IP 核来生成 60MHz 时钟。例如对于 Xilinx FPGA ,可以使用 Clock Wizard IP 。
### 测试
USB插入后,打开 Windows 设备管理器,应该能看到扬声器和麦克风设备:
USB插入后,打开 Windows 设备管理器,应该能看到音频设备:
![](./figures/ls_audio.png)
@ -846,7 +872,7 @@ USB插入后,打开 Windows 设备管理器,应该能看到扬声器和麦
- RTL/fpga_examples/**fpga_top_usb_camera.v**
- RTL/usb_class/**usb_camera_top.v**
- RTL/usbfs_core/**usbfs_core_top.v**
- RTL/usbfs_core/里的其它.sv文件(不逐个列出了)
- RTL/usbfs_core/里的其它.v 文件(不逐个列出了)
> :warning: 本库的 USB core 需要 60MHz 的驱动时钟。**fpga_top_usb_camera.v** 里调用了 Altera 的 altpll 原语来把晶振的 50MHz 时钟转为 60MHz 时钟。如果你的 FPGA 不是 Altera Cyclone IV ,请删掉 altpll 部分的代码,然后用对应的原语或 IP 核来生成 60MHz 时钟。例如对于 Xilinx FPGA ,可以使用 Clock Wizard IP 。
@ -889,13 +915,13 @@ Y00 Y01 Y02 Y03 Y10 Y11 Y12 Y13 Y20 Y21 Y22 Y23
##### FRAME_TYPE="YUY2"
`FRAME_TYPE="YUY2"` 是一种彩色模式,又称为 YUYV ,每个像素具有独立的 1字节明度值(Y),而相邻的两个像素共享1字节的蓝色度(U)和1字节的红色度(Y) 。例如,对于一个 4x2 的视频帧,该模块会先后从外界读取以下16个字节:
`FRAME_TYPE="YUY2"` 是一种彩色模式,又称为 YUYV ,每个像素具有独立的 1字节明度值(Y),而相邻的两个像素共享1字节的蓝色度(U)和1字节的红色度(V) 。例如,对于一个 4x2 的视频帧,该模块会先后从外界读取以下16个字节:
```
Y00 U00 Y01 V00 Y02 U02 Y03 V02 Y10 U10 Y11 V10 Y12 U12 Y13 V12
```
其中 (Y00, U00, V00) 是第0行第0列的像素;(Y01, U00, V00) 是第0行第1列的像素;(Y02, U02, V02) 是第0行第2列的像素;(Y03, U02, V02) 是第0行第3列的像素;……
其中 (Y00, U00, V00) 是第0行第0列的像素;(Y01, U00, V00) 是第0行第1列的像素;(Y02, U02, V02) 是第0行第2列的像素;(Y03, U02, V02) 是第0行第3列的像素;(Y10, U10, V10) 是第1行第0列的像素;……
#### usb_camera_top.v 的信号
@ -925,7 +951,7 @@ input wire [ 7:0] vf_byte, //
- RTL/fpga_examples/**fpga_top_usb_disk.v**
- RTL/usb_class/**usb_disk_top.v**
- RTL/usbfs_core/**usbfs_core_top.v**
- RTL/usbfs_core/里的其它.sv文件(不逐个列出了)
- RTL/usbfs_core/里的其它.v文件(不逐个列出了)
> :warning: 本库的 USB core 需要 60MHz 的驱动时钟。**fpga_top_usb_disk.v** 里调用了 Altera 的 altpll 原语来把晶振的 50MHz 时钟转为 60MHz 时钟。如果你的 FPGA 不是 Altera Cyclone IV ,请删掉 altpll 部分的代码,然后用对应的原语或 IP 核来生成 60MHz 时钟。例如对于 Xilinx FPGA ,可以使用 Clock Wizard IP 。
@ -973,7 +999,7 @@ input wire [ 7:0] mem_rdata, // byte to read
- RTL/fpga_examples/**fpga_top_usb_keyboard.v**
- RTL/usb_class/**usb_keyboard_top.v**
- RTL/usbfs_core/**usbfs_core_top.v**
- RTL/usbfs_core/里的其它.sv文件(不逐个列出了)
- RTL/usbfs_core/里的其它.v文件(不逐个列出了)
> :warning: 本库的 USB core 需要 60MHz 的驱动时钟。**fpga_top_usb_keyboard.v** 里调用了 Altera 的 altpll 原语来把晶振的 50MHz 时钟转为 60MHz 时钟。如果你的 FPGA 不是 Altera Cyclone IV ,请删掉 altpll 部分的代码,然后用对应的原语或 IP 核来生成 60MHz 时钟。例如对于 Xilinx FPGA ,可以使用 Clock Wizard IP 。
@ -1008,7 +1034,7 @@ input wire key_request, // when key_request=1 pulses, a key is pressed
- RTL/fpga_examples/**fpga_top_usb_serial.v**
- RTL/usb_class/**usb_serial_top.v**
- RTL/usbfs_core/**usbfs_core_top.v**
- RTL/usbfs_core/里的其它.sv文件(不逐个列出了)
- RTL/usbfs_core/里的其它.v文件(不逐个列出了)
> :warning: 本库的 USB core 需要 60MHz 的驱动时钟。**fpga_top_usb_serial.v** 里调用了 Altera 的 altpll 原语来把晶振的 50MHz 时钟转为 60MHz 时钟。如果你的 FPGA 不是 Altera Cyclone IV ,请删掉 altpll 部分的代码,然后用对应的原语或 IP 核来生成 60MHz 时钟。例如对于 Xilinx FPGA ,可以使用 Clock Wizard IP 。
@ -1056,7 +1082,7 @@ output wire send_ready, // send_ready handshakes with send_valid. send
- RTL/fpga_examples/**fpga_top_usb_serial2.v**
- RTL/usb_class/**usb_serial2_top.v**
- RTL/usbfs_core/**usbfs_core_top.v**
- RTL/usbfs_core/里的其它.sv文件(不逐个列出了)
- RTL/usbfs_core/里的其它.v文件(不逐个列出了)
> :warning: 本库的 USB core 需要 60MHz 的驱动时钟。**fpga_top_usb_serial2.v** 里调用了 Altera 的 altpll 原语来把晶振的 50MHz 时钟转为 60MHz 时钟。如果你的 FPGA 不是 Altera Cyclone IV ,请删掉 altpll 部分的代码,然后用对应的原语或 IP 核来生成 60MHz 时钟。例如对于 Xilinx FPGA ,可以使用 Clock Wizard IP 。
@ -1088,30 +1114,30 @@ USB插入后,打开 Windows 设备管理器,应该能看到2个 USB-serial
**usbfs_core_top.v** 的参数如下表。
| usbfs_core_top 的参数 | 类型 | 说明 |
| --------------------- | --------------------------------------- | -------------------------------------------- |
| `DESCRIPTOR_DEVICE` | `logic[7:0][18]` (字节数组,长度为18) | 设备描述符 |
| `DESCRIPTOR_STR1` | `logic[7:0][64]` (字节数组,长度为64) | 字符串描述符1 |
| `DESCRIPTOR_STR2` | `logic[7:0][64]` (字节数组,长度为64) | 字符串描述符2 |
| `DESCRIPTOR_STR3` | `logic[7:0][64]` (字节数组,长度为64) | 字符串描述符3 |
| `DESCRIPTOR_STR4` | `logic[7:0][64]` (字节数组,长度为64) | 字符串描述符4 |
| `DESCRIPTOR_STR5` | `logic[7:0][64]` (字节数组,长度为64) | 字符串描述符5 |
| `DESCRIPTOR_STR6` | `logic[7:0][64]` (字节数组,长度为64) | 字符串描述符6 |
| `DESCRIPTOR_CONFIG` | `logic[7:0][512]` (字节数组,长度为512) | 配置描述符 |
| `EP00_MAXPKTSIZE` | `logic[7:0]` | control endpoint 最大包大小 |
| `EP81_MAXPKTSIZE` | `logic[9:0]` | IN endpoint 0x81 最大包大小 |
| `EP82_MAXPKTSIZE` | `logic[9:0]` | IN endpoint 0x82 最大包大小 |
| `EP83_MAXPKTSIZE` | `logic[9:0]` | IN endpoint 0x83 最大包大小 |
| `EP84_MAXPKTSIZE` | `logic[9:0]` | IN endpoint 0x84 最大包大小 |
| `EP81_ISOCHRONOUS` | 0 或 1 | IN endpoint 0x81 是否是 isochronous 传输模式 |
| `EP82_ISOCHRONOUS` | 0 或 1 | IN endpoint 0x82 是否是 isochronous 传输模式 |
| `EP83_ISOCHRONOUS` | 0 或 1 | IN endpoint 0x83 是否是 isochronous 传输模式 |
| `EP84_ISOCHRONOUS` | 0 或 1 | IN endpoint 0x84 是否是 isochronous 传输模式 |
| `EP01_ISOCHRONOUS` | 0 或 1 | IN endpoint 0x01 是否是 isochronous 传输模式 |
| `EP02_ISOCHRONOUS` | 0 或 1 | IN endpoint 0x02 是否是 isochronous 传输模式 |
| `EP03_ISOCHRONOUS` | 0 或 1 | IN endpoint 0x03 是否是 isochronous 传输模式 |
| `EP04_ISOCHRONOUS` | 0 或 1 | IN endpoint 0x04 是否是 isochronous 传输模式 |
| `DEBUG` | "TRUE" 或 "FALSE" | 是否启用调试接口 |
| usbfs_core_top 的参数 | 类型 | 说明 |
| --------------------- | --------------------------- | ----------------------------------------- |
| `DESCRIPTOR_DEVICE` | `[18*8-1:0]` (最长18字节) | 设备描述符 |
| `DESCRIPTOR_STR1` | `[64*8-1:0]` (最长64字节) | 字符串描述符1 |
| `DESCRIPTOR_STR2` | `[64*8-1:0]` (最长64字节) | 字符串描述符2 |
| `DESCRIPTOR_STR3` | `[64*8-1:0]` (最长64字节) | 字符串描述符3 |
| `DESCRIPTOR_STR4` | `[64*8-1:0]` (最长64字节) | 字符串描述符4 |
| `DESCRIPTOR_STR5` | `[64*8-1:0]` (最长64字节) | 字符串描述符5 |
| `DESCRIPTOR_STR6` | `[64*8-1:0]` (最长64字节) | 字符串描述符6 |
| `DESCRIPTOR_CONFIG` | `[512*8-1:0]` (最长512字节) | 配置描述符 |
| `EP00_MAXPKTSIZE` | `[7:0]` | control endpoint 最大包大小 |
| `EP81_MAXPKTSIZE` | `[9:0]` | IN endpoint 0x81 最大包大小 |
| `EP82_MAXPKTSIZE` | `[9:0]` | IN endpoint 0x82 最大包大小 |
| `EP83_MAXPKTSIZE` | `[9:0]` | IN endpoint 0x83 最大包大小 |
| `EP84_MAXPKTSIZE` | `[9:0]` | IN endpoint 0x84 最大包大小 |
| `EP81_ISOCHRONOUS` | 0 或 1 | IN endpoint 0x81 是否是 isochronous 模式 |
| `EP82_ISOCHRONOUS` | 0 或 1 | IN endpoint 0x82 是否是 isochronous 模式 |
| `EP83_ISOCHRONOUS` | 0 或 1 | IN endpoint 0x83 是否是 isochronous 模式 |
| `EP84_ISOCHRONOUS` | 0 或 1 | IN endpoint 0x84 是否是 isochronous 模式 |
| `EP01_ISOCHRONOUS` | 0 或 1 | OUT endpoint 0x01 是否是 isochronous 模式 |
| `EP02_ISOCHRONOUS` | 0 或 1 | OUT endpoint 0x02 是否是 isochronous 模式 |
| `EP03_ISOCHRONOUS` | 0 或 1 | OUT endpoint 0x03 是否是 isochronous 模式 |
| `EP04_ISOCHRONOUS` | 0 或 1 | OUT endpoint 0x04 是否是 isochronous 模式 |
| `DEBUG` | "TRUE" 或 "FALSE" | 是否启用调试接口 |
> :warning: 根据 USB 1.1 specification ,当一个 endpoint 是 isochronous 传输模式时,最大包大小可取 8\~1023 的任意值。当 endpoint 是 interrupt 或 bulk 传输模式时,最大包大小只能取 8, 16, 32, 或 64 。
@ -1145,6 +1171,8 @@ inout usb_dp, // USB D+
inout usb_dn, // USB D-
```
#### 用来指示USB是否被插入的信号
`usb_rstn` 信号指示了 USB 是否连接,高电平代表已连接;低电平代表未连接。未连接可能是有两种情况:要么USB线被从 Host 上拔出,要么 FPGA 侧主动进行复位( `rstn=0`
```verilog
@ -1255,6 +1283,8 @@ output wire ep04_valid, // when out_valid=1 pulses, a data byte is rec
#### 调试输出接口
要使用调试接口,需要把模块参数 `DEBUG` 设为 1,否则调试接口不会有任何输出。
以下信号用来向外界打印调试信息。调试信息是一个 ASCII 码字节流,是人类可读的。当 `debug_en=1` 时, `debug_data` 上出现一个字节。
```verilog
@ -1265,7 +1295,9 @@ output wire [ 7:0] debug_data, //
output wire debug_uart_tx // debug_uart_tx is the signal after converting {debug_en,debug_data} to UART (format: 115200,8,n,1). If you want to transmit debug info via UART, you can use this signal. If you want to transmit debug info via other custom protocols, please ignore this signal and use {debug_en,debug_data}.
```
为了方便使用,我还将 `{debug_en,debug_data}` 字节流转化位 UART 输出信号 `debug_uart_tx` ,可以将 `debug_uart_tx` 连接到电脑的 UART 上,用串口助手等软件来查看调试信息。注意 UART 的配置应该为 波特率=115200, 数据位=8,无校验位,停止位=1 。
为了方便使用,我还将 `{debug_en,debug_data}` 字节流转化位 UART 输出信号 `debug_uart_tx` ,可以将 `debug_uart_tx` 连接到电脑的 UART 上,用串口助手等软件来查看调试信息。
注意: UART 的配置应该为 波特率=115200, 数据位=8,无校验位,停止位=1 。
下图展示了我的 USB UVC 设备插入电脑时 UART 上打印的调试数据。可以看到这是一个描述符枚举的过程。
@ -1273,8 +1305,6 @@ output wire debug_uart_tx // debug_uart_tx is the signal after convertin
| :----------------------------------------------------: |
| **图**:USB UVC 设备插入电脑时 UART 上打印的调试数据。 |
> :warning: 使用调试接口时,要令模块参数 `DEBUG="TRUE"` 。当 `DEBUG="FALSE"` 时,`debug_en` 保持0 ,且 `debug_uart_tx` 保持1 (不会输出任何调试信息)。
> :warning: 因为 UART 的传输速度较慢,当大量的调试信息产生时,会有一部分调试信息被 UART 丢弃。例如当 UVC 进行视频传输时,因为传输的数据量很大,UART 打印的信息是不完整的。因此如果需要在大量数据通信的过程中查看调试信息,就不能用 UART ,而是用其它高速的通信方式将 `{debug_en, debug_data}` 发给 host-PC 来查看。
 

2
RTL/usb_class/usb_audio_top.v

@ -20,7 +20,7 @@ module usb_audio_top #(
// USB reset output
output wire usb_rstn, // 1: connected , 0: disconnected (when USB cable unplug, or when system reset (rstn=0))
// user data : audio output (host-to-device, such as a speaker), and audio input (device-to-host, such as a microphone).
output reg audio_en, // a 48kHz pulse, that is, audio_en=1 for 1 cycle every 1250 cycle. Note that 60MHz/48kHz=1250, where 60MHz is clk frequency.
output reg audio_en, // a 48kHz pulse, that is, audio_en=1 for 1 cycle every 1250 cycles. Note that 60MHz/48kHz=1250, where 60MHz is clk frequency.
output reg [15:0] audio_lo, // left-channel output: 16-bit signed integer, which will be valid when audio_en=1
output reg [15:0] audio_ro, // right-channel output: 16-bit signed integer, which will be valid when audio_en=1
input wire [15:0] audio_li, // left-channel input : 16-bit signed integer, which will be sampled when audio_en=1

Loading…
Cancel
Save