USB
USB介绍
USB,通用串行总线,支持热插拔,为了解决即插即用的需求,USB2.0比较常用。由于USB是主从模式的结构,设备与设备、主机与主机相互之间不能互联,为了解决这个问题,出现了USB OTG(on the go),同一个设备在不同场合下可以在主从机之间切换。
特点
usb2.0以上支持480Mb/s高速模式
性能 | 应用 | 特性 |
低速(1.5Mbps) 交互式设备 10-100kbps |
键盘鼠标 手写笔 外设 虚拟设备 |
成本低 热插拔 同时使用多个外设 |
全速(12Mbps) 电话、音频 压缩的视频 500kbps - 10Mbps |
话音 宽带 音频 麦克风 |
成本低 热插拔 同时使用多个外设 保证带宽和延迟 |
高速(480Mbps) 视频,大容量存储 25-400Mbps |
视频 大容量存储 图像 宽带 |
成本低 热插拔 同时使用多个外设 保证带宽与延迟 高带宽 |
供电方式
自供电:设备从外部电源获取电压
总线供电:设备从VBUS(5V)取电
总线供电区分低功耗和高功耗USB设备,低功耗设备最大功耗不超过100mA,高功耗设备枚举时候最大不超100mA,枚举完成配置结束后功耗不超500mA
设备在枚举过程中,通过设备的配置描述符向主机报告供电设置(自供电/总线供电)以及功耗要求
USB传输
一个传输有多个事务组成,一个事务有2/3个包
传输分为4种:批量传输、同步传输、中断传输、控制传输
USB发送数据低位优先
包的内容
Packet分四大类: 命令 (Token) 、Packet 帧首 (Start of Frame) 、Packet 数据 (Data) 、Packet 握手 (Handshake) Packet不同类型包,以上的组成部件有所不同
PID
PID只用0-3位,高4位是低4位的取反,用于校验PID
PID类型 | 名称 | PID[3:0] | 对应packet种类 |
Token 令牌包 | OUT | 0001 | 通知设备将要输出数据 |
IN | 1001 | 通知设备将要输入数据 | |
SOF | 0101 | 通知设备这是一个帧起始数据包 | |
SET UP | 1101 | 通知设备将要开始一个控制传输 | |
data 数据包 | DATA0 | 0011 | |
DATA1 | 1011 | ||
DATA2 | 0111 | ||
MDATA | 1111 | ||
Handshake 握手包 | ACK | 0010 | 确认 |
NAK | 1010 | 非确认 | |
STALL | 1110 | 挂起 | |
NYET | 0110 | 为准备好 | |
Special 特殊包 | PRE | 1100 | 前导(这是一个令牌包) |
ERR | 1100 | 错误(握手包) | |
SPLIT | 1000 | 分列事务(令牌包) | |
PING | 0100 | PING测试(这是一个令牌包) |
令牌包(Token Packet)
用来启动一次USB传输
SETUP 和 OUT的区别在于SETUP令牌包后只使用DATA0数据包,而且只能发送到设备的控制端点,且设备必须要接收,OUT令牌包没有这些限制
一次USB传输事务,以令牌包开始,然后数据包最后可能会有握手包结束。事务可能会有如下4种传输模式,控制传输、同步传输、中断传输和批量传输。如下,是一包的数据构成,payload是实际传输的数据。
//===================================================================================================================
USB内部8051的core,通过向8051下载固件来管理USB芯片的工作机制,右边有用户接口供用户操作
USB芯片:封装好USB协议,使得FPGA无须构造USB协议,在实际应用中可以将USB芯片当做FIFO,FPGA向USB写入数据,USB将数据发送PC
FLAGC:FIFOADR指定的FIFO的EMPTY标志
FLAGB:FIFOADR指定的FIFO的FULL标志
FLAGA:FIFOADR指定的FIFO的可操作标志
FIFOADR:地址分别对应00,01,10,11。具体使用哪个FIFO,作为输入还是输出,需要固件编写。
SLRD: FIFO读信号。同步读时,FIFO指针在SLRD有效时的每个IFCLK的上升沿递增;异步读时,FIFO读指针在SLRD的每个有效到无效的跳变沿时递增;
SLWR:FIFO写信号。同步写时,在SLWR有效时的每个IFCLK的上升沿时数据被写入,FIFO指针递增;异步写时,在SLWR的每个有效到无效的跳变沿时数据被写入,FIFO写指针递增。
SLCS:gates all other slave FIFO enable/strobes, FIFO片选标志,当输出高时,不可进行数据传输。
SLOE: Input-only output enable with programmable polarity for the slave FIFO. FPGA输出的,控制对FIFO读数据使能的信号。IC 输出使能,低电平有效。即在FPGA读的时候需要使其置低,写的时候拉高。也就是FIFO 输出使能
PKTEND:包结束标志信号
FD[15]-FD[0] FIFO数据双向总线
USB FIFO同步写数据
IFCLK :同步时钟
SWLR:写使能,低有效,和FLAGS信号是时序逻辑产生,组合逻辑输出,保证SLWR和FULL拉低同时变化
DATA:FIFO数据总线
FLAGS:泛指FLAGA B C三个标志信号,低电平有效
需要保证数据正确传输进入FIFO内部,不能写满
同步读
USB 异步读写
根据异步读时的时序图:可以看出SLRD信号的低电平有效时间最少为50ns,FIFO输出数据到FLAG输出有70ns的延迟,因此读数据到写请求输出前的判断必须要大于70ns,否则可能造成误判。而我们使用的FPGA时钟周期是20ns,在每一个状态中可能需要停留几个时钟周期。
FPGA通过控制信号以及读取到的EP FLAG来判断是进行读还是写;
FPGA从EP2(FLAGADDR = 2'b00)读出数据后发送到EP6(FLAGADDR = 2'b10)
USB 异步读写回环
module usb(
//sys
input clk ,
input rst_n ,
//input
input usb_flag_a ,//EP2空标志
input usb_flag_b ,//EP4空标志
input usb_flag_c ,//EP6满标志
//output
output reg [1:0] usb_addr ,
output reg usb_slcs ,
output reg usb_sloe ,
output reg usb_slwr ,
output reg usb_slrd ,
inout [15:0] usb_fd
);
//=========================================
//================define===================
//=========================================
parameter IDEL = 5'd0;
parameter RD_REQ = 5'd1;
parameter RD_DATA = 5'd2;
parameter RD_OVER = 5'd4;
parameter WR_REQ = 5'd8;
parameter WR_OVER = 5'd16;
reg [15:0] data_reg;//inout 输出接口数据存储
reg access_req;//表示EP2 有数据,EP6没有满,且不忙碌
reg busy;//busy 表示一次传输
reg usb_fd_en;
reg [4:0] usb_state;
reg [4:0] i;//延时操作计数
//=========================================
//================main code================
//=========================================
assign usb_fd = usb_fd_en ? data_reg : 16'bz;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
access_req <= 1'b0;
else if(usb_flag_a & usb_flag_c && (busy == 1'b0))
access_req <= 1'b1;
else
access_req <= 1'b0;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
usb_state <= IDEL;
usb_addr <= 2'b00;
usb_slcs <= 1'b0;
usb_sloe <= 1'b1;
usb_slwr <= 1'b1;
usb_slrd <= 1'b1;
usb_fd_en <= 1'b0;
end
else begin
case(usb_state)
IDEL:begin
usb_addr <= 2'b00;
usb_fd_en <= 1'b0;
i=5'd0;
if(access_req)begin
usb_state <= RD_REQ;
busy <= 1'b1;
end
else begin
usb_state <= IDEL;
busy <= 1'b0;
end
end
RD_REQ:begin
if(i == 'd2)begin
usb_slrd <= 1'b1;
usb_sloe <= 1'b0;
i <= i+ 1'b1;
end
else if(i == 'd8)begin
usb_slrd <= 1'b0;
usb_sloe <= 1'b0;
usb_state <= RD_DATA;
i <= 'd0;
end
else
i <= i+1;
end
RD_DATA:begin
if(i == 'd8)begin
usb_slrd <= 1'b1;
usb_sloe <= 1'b0;
data_reg <= usb_fd;
usb_state <= RD_OVER;
end
else
i <= i+1;
end
RD_OVER:begin
if(i == 'd4)begin
usb_slrd <= 1'b1;
usb_sloe <= 1'b1;
usb_addr <= 2'b10;
usb_state <= WR_REQ;
i <= 'd0;
end
else
i <= i+1;
end
WR_REQ:begin
if(i == 'd8)begin
usb_slwr <= 1'b1;
usb_state <= WR_OVER;
i <= 'd0;
end
else begin
usb_slwr <= 1'b0;
usb_fd_en <= 1'b1;
i <= i+1;
end
end
WR_OVER:begin
if(i == 'd4)begin
usb_fd_en <= 1'b0;
busy <= 1'b0;
i <= 'd0;
usb_state <= IDEL;
end
else
i <= i+1;
end
default:usb_state <= IDEL;
endcase
end
end
endmodule
USB传输图像 首先要把图像转换成bin文件,直接选择图像传输会发送多余数据(bmp文件前边包含了文件头信息,也就是前边会发送非图像信息)
图像数据转换成TXT传输会对TXT中的数据进行ASCII转码