FPGA通信第一篇--USB2.0


FPGA通信第一篇–USB2.0

1 初识USB

1.1 简介

USB(UniversalSerialBus)是一种支持热插拔的高速串行传输总线,它使用差分信号来传输数据。在USB1.0和USB1.1版本中,只支持1.5Mb/s的低速模式和12Mb/s的全速模式,在USB2.0和USB3.0中,又分别加入了480Mb/s的高速模式和5Gb/s的超高速模式。USB2.0被设计成为向下兼容的模式,当有全速(USB1.1)或者低速(USB1.0)设备连接到高速(USB2.0)主机时,主机可以通过分离传输来支持它们。一条USB总线上,可达到的最高传输速度等级由该总线上最慢的“设备”决定。

USB是一种轮询总线,由Host发起所有的数据传输。大部分总线传输包含3个包(packet)。每个传输都由Host先发出令牌包(TokenPacket),明确传输类型、传输方向、USB设备地址和端点号。对应地址的USB设备接收并解析包。一次传输可以由Host发向设备,也可以由设备发送至Host,方向由令牌包说明。传输中的数据过程是可选的,即有的传输没有数据过程。在低速/全速设备中,一次传输由4个包组成。


1.2 USB通信流程

从USB系统角度而言,一个逻辑上的USB设备是一个端点的集合。分组的端点构成一个接口。USB系统通过默认控制管道来管理设备。客户端软件使用管道来管理接口,通过主机上的Buffer和USB设备上的端点来请求数据。主机控制器打包数据并将数据包发送出去,如图1.2所示。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h50Yj6rR-1655469851084)(/images/USB2.0/1.2.jpg " ")]

端点(Endpoint)是USB设备上可被独立识别的端口,是Host和Device通讯流的逻辑终点,是USB设备中可以进行数据收发的最小单元。一系列相互独立的端点在一起构成了USB逻辑设备。当设备连入USB总线时会被分配一个唯一的地址,设备上每一个端点有唯一的端点号。设备可决定每个端点的数据传输方向(输入或输出)。因此,使得每个端点可被唯一寻址。每个端点的属性包括总线访问频率、带宽、端点号、最大包长度、传输类型和数据传输方向。

每个USB设备必须要有一个端点0,其作用为对设备枚举和对设备进行一些基本的控制功能,端点0也被称为控制端点。并且它与其他的端点还有一个不同之处在于端点0的数据传输方向是双向的,即端点0既可以给主机发送数据,也可以接收主机发送过来的数据,而其它端点均为单向。
除了控制端点以外,每个USB设备允许有一个或多个非0端点。低速设备最多只有两个非0端点。高速和全速设备最多支持15组端点。除了端点0,其余的端点在设备配置之前不能与主机通信,只有向主机报告这些端点的特性并被确认后才能被激活。

管道(Pipe)是主机和设备端点之间数据传输的模型,共有两种类型的管道:无格式的流管道(StreamPipe)和有格式的信息管道(MessagePipe)。

流管道:数据从流通道一端流进的顺序与它们从流通道另一端流出时的顺序是一样的(先进先出),并且流通道中的通信流总是单向的。

信息管道:信息管道与端点的关系同流通道与端点的关系是不同的。首先,主机向USB设备发出一个请求;接着,就是数据的传送;最后,是一个状态阶段(这部分即一次命令请求的过程)。为了能够容纳请求/数据/状态的变化,信息管道要求数据有一个格式,此格式保证了命令能够被可靠地传送和确认。信息管道允许双方向的信息流。任何USB设备一旦上电就存在一个信息管道,即默认的控制管道,USB主机通过该管道来获取设备的描述、配置、状态,并对设备进行配置。
USB系统中的数据传输,宏观看是在Host和USB功能设备之间进行。微观看是在应用软件的Buffer和USB功能设备的端点之间进行。一般来说端点都有Buffer,可以认为USB通讯就是应用软件Buffer和设备端点Buffer之间的数据交换,交换的通道称为管道。通常需要多个管道来完成数据交换,因为同一管道只支持一种类型的数据传输。用在一起来对设备进行控制的若干管道称为设备的接口,这就是端点、管道和接口的关系。

USB采用“令牌包”-“数据包”-“握手包”的传输机制,在令牌包中指定数据包去向或者来源的设备地址和端点,从而保证了只有一个设备对被广播的数据包/令牌包作出响应。握手包表示了传输的成功与否。

USB采用轮询的广播机制传输数据,所有的传输都由主机发起,任何时刻整个USB体系内仅允许一个数据包的传输,即不同物理传输线上看到的数据包都是同一被广播的数据包。


1.3传输类型

USB的传输模式有4种,分别是控制传输(ControlTransfer)、中断传输(InterruptTransfer)、批量传输或叫块传输(BulkTransfer)、实时传输或叫同步传输(IsochronousTransfer)。

(1)控制传输
控制传输是一种可靠的双向传输,是最重要也是最复杂的。一次控制传输分为三个(或两个)阶段:建立(Setup)、数据(DATA)(可能没有)以及状态(Status)。每个阶段都由一次或多次(数据阶段)事务(Transaction)传输组成。在USB设备初次接到主机后,主机通过控制传输来交换信息、设备地址和读取设备的描述符,使得主机识别设备,并安装相应的驱动程序。控制传输是双向的传输,必须有IN和OUT两个方向上的特定端点号的控制端点来完成两个方向上的控制传输。
控制传输通过控制管道在应用软件和Device的控制端点之间进行,控制传输过程中传输的数据是有格式定义的,USB设备或主机可根据格式定义解析获得的数据含义。其他三种传输类型都没有格式定义。控制传输对于最大包长度有固定的要求。对于高速设备该值为64Byte,对于低速设备该值为8Byte,全速设备可以是8/16/32/64Byte。

最大包长度表征了一个端点单次接收/发送数据的能力,实际上反应的是该端点对应Buffer的大小。Buffer越大,单次可接收/发送的数据包越大,反之亦反。当通过一个端点进行数据传输时,若数据的大小超过该端点的最大包长度时,需要将数据分成若干个数据包传输。并保证除最后一个包外,所有的包长度均等于该最大包长度。这也就是说如果一个端点收到/发送了一个长度小于最大包长度的包,即意味着数据传输结束。

控制传输在访问总线时也受到一些限制,如高速端点的控制传输不能占用超过20%的微帧,全速和低速的则不能超过10%。在一帧内如果有多余的未用时间,并且没有同步和中断传输,可以用来进行控制传输。

与批量传输相比,在流程上并没有多大区别,区别只在于该事务传输发生的端点不一样、支持的最大包长度不一样、优先级不一样等这样一些对用户来说透明的东西。

(2)中断传输
中断传输是一种轮询的传输方式,是一种单向的传输。Host通过固定的间隔对中断端点进行查询,若有数据传输或可以接收数据则返回数据或发送数据。否则返回NAK,表示尚未准备好。中断传输的延迟有保证,但并非实时传输,它是一种延迟有限的可靠传输,支持错误重传。对于高速/全速/低速端点,最大包长度分别可以达到1024/64/8Bytes。高速中断传输不得占用超过80%的微帧时间,全速和低速不得超过90%。中断端点的轮询间隔由在端点描述符中定义,全速端点的轮询间隔可以是1255ms,低速端点为10255ms,高速端点为(2interval-1)×125us,其中interval取1到16之间的值。

主机在排定中断传输任务时,会根据对应中断端点描述符中指定的查询间隔发起中断传输。中断传输有较高的优先级,仅次于同步传输。同样中断传输也采用PID翻转的机制来保证收发端数据同步。

中断传输方式总是用于对设备的查询,以确定是否有数据需要传输。因此中断传输的方向总是从USB设备到主机。

除高速高带宽中断端点外,一个微帧内仅允许一次中断事务传输。高速高带宽端点最多可以在一个微帧内进行三次中断事务传输,传输高达3072字节的数据。

所谓单向传输,并不是说该传输只支持一个方向的传输。而是指在某个端点上该传输仅支持一个方向,或输出、或输入。如果需要在两个方向上进行某种单向传输,需要占用两个端点,分别配置成不同的方向,可以拥有相同的端点编号。

中断传输由OUT事务和IN事务构成,用于键盘、鼠标等HID设备的数据传输。中断传输在流程上除不支持PING之外,其他的跟批量传输是一样的。他们之间的区别也仅在于事务传输发生的端点不一样、支持的最大包长度不一样、优先级不一样等这样一些对用户来说透明的东西。

(3)批量传输
批量传输由OUT事务和IN事务构成,是一种可靠的单向传输,但延迟没有保证,它尽量利用可以利用的带宽来完成传输,适合数据量比较大的传输。低速USB设备不支持批量传输,高速批量端点的最大包长度为512,全速批量端点的最大包长度可以为8、16、32、64。用于传输大量数据,要求传输不能出错,但对时间没有要求,适用于打印机、存储设备等批量传输在访问USB总线时,相对其他传输类型具有最低的优先级,USB主机总是优先安排其他类型的传输,当总线带宽有富余时才安排批量传输。高速的批量端点必须支持PING操作,向主机报告端点的状态。NYET表示否定应答,没有准备好接收下一个数据包,ACK表示肯定应答,已经准备好接收下一个数据包。它通过在硬件级执行“错误检测”和“重传”来确保Host与device之间“准确无误”地传输数据,即可靠传输。一次事务由三种包组成:令牌包、数据包和握手包。

若数据量比较大,将采用多次批量事务传输来完成全部数据的传输,传输过程中数据包的PID按照DATA0-DATA1-DATA0-…的顺序发送数据包,只有成功的事务传输才会导致PID翻转,也就是说发送段只有在接收到ACK后才会翻转PID,发送下一个数据包,否则会重试本次事务传输。同样,若在接收端发现接收到的数据包不是按照此顺序翻转的,比如连续收到两个DATA0,那么接收端认为第二个DATA0是前一个DATA0的重传。

此外,若成功则将错误次数计数器清0,否则累加该计数器。USB允许连续3次以下的传输错误,错误时会重试该传输,若成功则将错误次数计数器清零,否则累加该计数器。超过三次后,Host认为该端点功能错误(STALL),放弃该端点的传输任务。一次批量传输由1次到多次批量事务传输组成。

(4)等时传输
等时传输是一种实时的、不可靠的传输,不支持错误重发机制。只有高速和全速端点支持等时传输,高速等时端点的最大包长度为1024,低速的为1023。由OUT事务和IN事务构成。有两个特殊地方:第一,在等时传输的IN和OUT事务中是没有返回包阶段的;第二,在数据包阶段所有的数据包都为DATA0。等时传输由令牌包和数据包两种包组成。等时传输不支持“握手包”和“重传能力”,所以它是不可靠传输。等时传输适用于必须以固定速率抵达或在指定时刻抵达,可以容忍偶尔错误的数据上。实时传输一般用于麦克风、喇叭、UVCCamera等设备。等时传输有最高的优先级除高速高带宽等时端点外,一个微帧内仅允许一次等时事务传输,高速高带宽端点最多可以在一个微帧内进行三次等时事务传输,传输高达3072字节的数据。全速等时传输不得占用超过80%的帧时间,高速等时传输不得占用超过90%的微帧时间。等时端点的访问也和中断端点一样,有固定的时间间隔限制。


2 如何使用USB

2.1 FPGA与USB通信

FPGA与USB芯片通讯的接口原理图如图2.1所示,两者严格按照规定的FIFO握手协议进行数据传输。其中握手信号有:SLOE、SLRD、SLWR为使能信号和读写控制信号;FLAGB为空满的标志信号;IFCLK提供FPGA写时钟信号;FIFOADR[1:0]为USB片内端点地址;FD[15:0]为16位传输数据。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QiVcxnTB-1655469851085)(/images/USB2.0/2.1.jpg " ")]

其中PKTEND、SLOE、SLWR、SLRD、FLAGB的设置需要结合FX2LP固件代码中的引脚极性寄存器(FIFOPINPOLAR)的值。

为保证数据的准确传输,需在FPGA中进行SlaveFIFO状态机设计,SlaveFIFO表示的是一种外部从属FIFO,及通过片外的控制信号对片内的RAM进行存储操作。此处的通讯设计中,FPGA与USB芯片就是属于一种从属关系,FPGA提供数据与控制信号,控制USB芯片中的存储单元进行存储与提取。如图2.2所示为SlaveFIFO控制状态机(假定FLAGB等均低电平有效),在FPGA内部实现的硬件电路。IDLE表示等待状态,当使能与端点地址已就绪,USB芯片反馈为非空时,每个时钟进入一个STATE并进行一次16位有效数据的传输。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1amdIGk1-1655469851086)(/images/USB2.0/2.2.jpg " ")]

参照官方实例,写出符合其固件代码的FPGA与USB通信代码,通过 CyConsole 软件可以检测 USB 芯片接收到 FPGA 输出的数据,判断数据是否成功上传至上位机。如图 2.3所示为一个 USB 数据包,包中存有 512字节的数据(0-255、0-255的累加数),说明数据已经成功从 FPGA转送至 USB 接口。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gaG9TrXZ-1655469851087)(/images/USB2.0/2.3.jpg " ")]


2.2 USB固件代码修改

USB固件代码是USB通信三部曲之一,想要设计修改出符合自己要求的固件代码,需要了解其描述符、寄存器等重要参数。

2.2.1常用描述符配置

USB描述符也可以看作是USB设备的身份证明。常用的描述符有设备、配置、接口、端点和字符串。各个USB设备只有一个设备描述符。但是,一个设备可以有多种配置、接口、端点和字符串描述符。设备执行枚举时,终端阶段中有一个步是读取设备描述符,并选择需要使能的设备配置类型。每一次操作只能使能一种配置。

(1)设备描述符
设备描述符描述有关USB设备的一般信息。它包含全局适用于设备和所有设备配置的信息,如设备需要满足的USB规范、设备配置编号、设备支持的协议、供应商标识(VID,每个公司只能从USB实施者论坛获得唯一的VID)、产品标识(PID,与数据包ID不同)、一个序列号(如果设备有)以及端点0的最大数据包大小等。

(2)配置描述符
配置描述符描述了关于特定设备配置的信息,如接口数量、供电方式和最大功耗等。描述符包含一个bConfigurationValue字段,该字段的值用作SetConfiguration()请求的参数时,会使设备采用所描述的配置。描述符描述配置提供的接口数量,每个接口可以独立运行。配置完成后,设备可能会对配置进行有限的调整。如果某个特定接口具有备用设置,则可以在配置后选择备用设备。

(3)接口描述符
接口描述符描述配置中的特定接口,如端点数量、接口类别和协议等。一个配置提供一个或多个接口,每个接口具有零个或多个端点描述符,用于描述配置中的一组唯一端点。当配置支持多个接口时,特定接口的端点描述符将遵循GetConfiguration()请求返回的数据中的接口描述符。接口描述符总是作为配置描述符的一部分返回。接口描述符不能通过GetDescriptor()或SetDescriptor()请求直接访问。

(4)端点描述符
在一个设备中所使用的全部端点都有自己的描述符,这些描述符会提供主机必须获取的端点信息,如端点方向、传输类型、最大数据包长度和轮询间隔等。一个端点描述符不能通过GetDescriptor()或SetDescriptor()请求直接访问,而是作为配置描述符的一部分返回。

(5)字符串描述符
字符串描述符是一种可选的描述符,它为用户提供了有关设备的可读信息。该描述符中所包含的信息显示了以下内容:设备名称、生产厂家、序列号或不同接口、配置的名称。如果设备没有使用字符串,必须将前面所述的所有描述符中的字符串附加字段的值设置为00h。否则在枚举过程中,USB主机会尝试去获取字符串描述符,如果没有,枚举就会失败。


2.2.2常用寄存器配置

slavefifo模式下常用寄存器如下:

  1. CPUCS
  2. FIFOPINPOLAR
  3. PINFLAGSAB/CD
  4. PORTACFG
  5. IFCONFIG
  6. EP2/4/6/8CFG
  7. FIFORESET
  8. EP2/4/6/8FIFOCFG
  9. EP1OUTCFG
  10. EP2/4/6/8AUTOINLENH/L
  11. EP1INCFG
  12. EP2/4/6/8ISOINPKTS

(1)CPUCS:CPU控制和状态寄存器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BGw3WyQP-1655469851087)(/images/USB2.0/2.2.2.1.jpg " ")]
PORTCSTB:PORTC访问产生RD和WR选通。
100和128引脚EZ-USB封装有两个输出引脚RD和WR,可用于同步I/OPORTC上的数据传输。当PORTCSTB=1时,启用此功能。对PORTC的任何读取都会激活RD选通,而对PORTC的任何写入都会激活WR选通。RD和WR选通被置位两个CLKOUT周期;更新PORTC引脚后,WR选通将置位两个CLKOUT周期。
如果设计使用128引脚EZ-USB并将片外存储器连接到地址和数据总线,则该位应设置为零。这是因为RD和WR引脚也是用于读写片外存储器的标准选通管,因此对I/O端口C的正常读/写会中断对该存储器的正常访问。
CLKSPD[1:0]:CPU时钟速度。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CjrEPubX-1655469851088)(/images/USB2.0/2.2.2.2.jpg " ")]
这些位设置CPU时钟速度。在硬复位时,这些位默认为“00”(12MHz)。固件可以随时修改这些位
CLKINV:反转CLKOUT信号。0不反转,1反转。
CLKOE:驱动CLKOUT引脚。0引脚悬空。1引脚驱动。
8051RES:8051重置。USB主机向该位写入“1”以重置8051,向该位写入“0”以运行8051。只有USB主机可以写入该位(通过0xA0固件加载命令)。

(2)FIFOPINPOLAR:从设备FIFO接口引脚极性寄存器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WtqnMP9L-1655469851088)(/images/USB2.0/2.2.2.3.jpg " ")]
SlaveFIFO引脚极性设置均为0低有效,1高有效。其中PF极性没有提供寄存器设置,为高有效。

(3)PINFLAGSAB/CD:从设备FIFOFLAGA-FLAGD引脚配置寄存器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4gIs4ZWy-1655469851089)(/images/USB2.0/2.2.2.4.jpg " ")]
EZ-USB有四个FIFO标志输出引脚,FLAGA、FLAGB、FLAGC和FLAGD。这些标志可以编程为使用每个FIFO的四个选择位来表示各种FIFO标志。PINFLAGSAB寄存器控制FLAGA和FLAGB信号,PINFLAGSCD寄存器控制FLAGC和FLAGD信号。所有四个标志的四位编码是相同的,如图2.5所示。在“FLAGx”符号中,“x”可以是A、B、C或D。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DFDPTOhU-1655469851089)(/images/USB2.0/2.5.jpg " ")]
注:FLAGD默认为EP2-PF。

(4)PORTACFG:I/OPORTA备用配置寄存器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qGq2OG9o-1655469851089)(/images/USB2.0/2.2.2.6.jpg " ")]
FLAGD:FlagD备用配置。当IFCFG[1:0]=11时,将此位设置为“1”会将PA7引脚配置为FLAGS,这是一个可编程的FIFO标志。
SLCS: 备用配置。如果IFCFG[1:0]=11,将此位设置为“1”会将PA7引脚配置为 ,即从设备FIFO芯片选择。
INT[1:0]:备用配置启用中断。将这些位设置为“1”会将这些PORTA引脚配置为INT1或INT0引脚。
注:该寄存器的b7、b6都影响引脚PA7。如果两个位都设置,则FLAGD优先。

(5)IFCONFIG:接口配置(端口、GPIF、从设备FIFO)寄存器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qpwfsMMR-1655469851090)(/images/USB2.0/2.2.2.7.jpg " ")]
IFCLKSRC:FIFO时钟内部/外部时钟源选择,0外部时钟源,1内部时钟源。
3048MHZ:内部FIFO/GPIP模式下的时钟频率,0代表30MHz,1代表48MHz。
IFCLKOE:IFCLK时钟输出使能,0关闭,1打开。
IFCLKPOL:IFCLK输出反转使能,0不反转,1反转。
ASYNC:SlaveFIFO同步/异步工作方式选择,0同步,1异步。
GSTATE:选择是否将GSTATE[2:0]在PORTE[2:0]输出,0关闭,1使能。
IFCFG[1:0]:选择接口模式(端口、GPIF或从设备FIFO)。00:I/O方式;01:reserved;11:SlaveFIFO方式;10:GPIF方式。

(6)EP2/4/6/8CFG:端点2、4、6和8配置寄存器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8IHFUZpH-1655469851090)(/images/USB2.0/2.2.2.8.jpg " ")]
VALID:激活端点。0停用端点,1激活端点(默认)。
DIR:设置端点方向。0为OUT,1为IN。
TYPE[1:0]:定义端点类型。00:无效;01:等时;10:批量(默认);11:中断。
SIZE:设置端点缓冲区的大小。端点4和8只能是512字节。端点2和6是可选择。0:512字节;1:1024字节
BUF[1:0]:缓冲类型/数量。00:四倍;01:无效;10:双倍;11:三倍。
注:当EZUSB分配缓冲区空间时,将忽略Valid位(例如,BUF[1:0]优先于Valid位)。当您没有使用端点配置中的所有端点时,禁用未使用的通过向相应EPxCFG寄存器的“有效”位写入零,而不会干扰寄存器中其他位的默认状态。

(7)FIFORESET:FIFO复位寄存器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OGQfBsGX-1655469851091)(/images/USB2.0/2.2.2.9.jpg " ")]
NAKALL:NAK所有来自主机的传输。
EP[3:0]:端点号。通过写入所需的端点编号(2,4,6,8),EZ-USB逻辑重置单个端点。
通过向该寄存器写入0x80可以对来自主机的所有传输进行NAK,然后写入0x82、0x84、0x86或0x88以继续NAKALL并复位单个FIFO。这会将端点FIFO标志和字节计数恢复到它们的默认状态。写入0x00可以恢复正常操作。
(8)EP2/4/6/8FIFOCFG:端点2、4、6和8/从设备FIFO配置寄存器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0TwKhzKG-1655469851091)(/images/USB2.0/2.2.2.10.jpg " ")]
NFM1:FIFO状态标志是否提前一个字节有效选择,IN端点满减1,1使能,0非使能。
OEP1:FIFO状态标志是否提前一个字节有效选择,OUT端点空加1,1使能,0非使能。
AUTOOUT:在前面,我们说SlaveFIFO方式下的数据传输过程不需要FX2固件的参与,实际上是不确切的,应该说,FX2固件可以不参与数据传输过程,也可以参与。AUTOOUT即可设置。如果设置AUTOOUT为1,则就如上面所说的,FX2固件只需要完成初始化工作,真正的数据传输是不需要FX2固件的参与的,具体的说,当FX2从主机收到一包数据时,外部逻辑即可看到FIFO端点缓冲区状态的改变,然后从中取数。如果设置AUTOOUT为0,则数据传输过程就需要FX2参与了,此时当FX2从主机收到一包数据时,FIFO端点缓冲区状态的改变并不会立刻在端口显现,而是固件先看到FIFO端点状态的改变,此时,FX2固件可以做三件事情:
a.向OUTPKTEND中的SKIP位写0,使FIFO端点状态的改变在端口显现,从而使外部逻辑可以从FIFO端点中读取数据;
b.向OUTPKTEND中的SKIP位写1,丢掉这包数据,这样就相当于主机从来就没有发送这一包数据,外部逻辑当然也不能从FIFO端点中读到这一包数据了;
c.从新编辑这一包数据,设置完全重写整个包的数据,再写EPxBC寄存器,把数据传给外部逻辑。
在FX2复位之后,如果其OUT端点缓冲区内有一包数据未处理,这包数据并不会自动传给外部逻辑。所以,为保证OUT端点缓冲区内没有未处理数据,在resetFX2后,要清空一下OUT端点缓冲区,具体做法就是向SKIP位写1(OUT端点缓冲区有几个缓冲区就写几次)。
AUTOIN:AutoIN和AutoOUT有一点不同,在AutoOUT里,包的大小只能是512或1024,而在AutoIN里,包的大小可以任意设定,甚至可以是0字节,这可以通过EPxAUTOINLENTH/L设置。
和AUTOOUT类似,当设置AUTOIN=0时,FX2固件可以传输,丢弃,修改外部逻辑传过来的数据,这通过向INPTKEND寄存器的SKIP写不同的值实现。
ZEROLENIN:是否允许传输0字节,1使能,0非使能。
WORDWIDE:8Bit,16Bit选择。当选择8Bit模式时,PortB将是FD[7:0];当选择16Bit模式时,PortD将是FD[15:8],1则为16位,0则为8位。

(9)EP2/4/6/8AUTOINLENH/L端点AUTOIN长度设置(仅IN端点有效)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V6tKHJYf-1655469851091)(/images/USB2.0/2.2.2.10.jpg " ")]
PL[10:0]设置AUTOIN时自动传输的包大小。
注:包大小不能大于IN端点的缓冲区的大小。PL10仅端点2和6有效。所有端点的默认数据包大小为512字节。注意EP2和EP6的最大长度为1024字节,EP4和EP8的最大长度为512字节,与端点结构保持一致

(10)EP2/4/6/8ISOINPKTS:每个帧寄存器的端点2ISOIN数据包
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uNjG6ICY-1655469851092)(/images/USB2.0/2.2.2.11.jpg " ")]
AADJ:自动调整。如果AADJ设置为“1”,则FX2LP自动管理高速、高带宽等时IN端点的数据PID排序,这些端点需要每个微帧中的额外事务。收到微帧中的第一个IN令牌后,FX2LP逻辑评估INFIFO中已提交数据包的填充度。如果逻辑检测到包含少于1024字节的提交短数据包,则不会在微帧中发送超出短数据包的其他数据包。如果INFIFO没有提交的数据包,则在微帧中发送单个零长度数据包。如果INFIFO充满1024字节的数据包,则微帧中发送的数据包数量受INPPF[1:0]设置的限制。在高速和全速模式下,如果INFIFO没有提交的数据包,EZUSB会发送一个零长度的IN数据包。如果AADJ设置为“0”,对于微帧内的IN事务,FX2LP始终以与INPPF[1:0]中指定的每个微帧的数据包数量相对应的数据PID开始。例如,如果INPPF[1:0]=10(每微帧两个数据包),即使数据包很短,或者没有数据,FX2LP也会为微帧中的第一个IN事务返回DATA1的数据PID可用于微帧中的下一个IN事务。在全速模式下,EZ-USB每帧仅发送一个数据包,而不管EPxISOINPKTS寄存器设置如何。
INPPF[1:0]:每帧IN数据包。如果EP2是ISOCHRONOUSIN端点,则这些位确定每个微帧(高速模式)要发送的数据包数量。允许的值为1、2或3。

(11)EP1OUT/INCFG:端点1-OUT/IN配置寄存器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LMuQ2pUU-1655469851092)(/images/USB2.0/2.2.2.12.jpg " ")]
VALID:激活端点。0停用端点,1激活端点(默认)
TYPE[1:0]:定义端点类型。00:无效;01:等时;10:批量(默认);11:中断。


2.2.3固件代码修改

在详细了解USB固件代码中常用的描述符和寄存器配置信息之后,在赛普拉斯官方实例的基础上对其进行修改,使其能满足实际使用需求。FX2LP固件模块的组合情况如图2.6所示。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lfLeavvp-1655469851093)(/images/USB2.0/2.6.jpg " ")]
fw.c为赛普拉斯框架文件,其包含main函数,执行了USB维持的大部分操作(如进行枚举),并且每当需要自定义时,它将调用应用代码(Slave.c)中特定名称的外部函数。执行各个日常操作的步骤后,该函数将调用Slave.c所提供的外部函数,即TD_Init。(前缀TD表示“任务调度”。然后,它进入一个无限循环,以通过CONTROL端点0检查SETUP数据包的到来。该循环还会检查USB暂停事件,但从设备FIFO应用不会使用该循环。每次进入该循环时,该函数都将调用Slave.c文件中提供的外部函数TD_Poll。
dscr.a51为描述符文件,是一个包含用于特定USB器件的描述符数据的8051汇编语言模块,主要负责修改端点方向、传输类型等参数。
slave.c是从设备FIFO应用的用户代码文件,主要包括TD_Init和TD_Poll等函数,可对从设备FIFO参数进行初始化设置等操作。
对于用户来说,主要通过修改描述符文件中的端点描述符和用户代码中的TD_Init和TD_Poll,来满足开发需求。值得注意的是,在从设备FIFO同步读写应用中,当内部时钟源IFCLK有FPGA端提供时,需要在TD_Poll函数中通过更改IFCONFIG.7获取来自FPGA的IFCLK。
修改固件代码所用软件为Keil,在修改之前需要对开发环境进行相应配置。当需要将固件代码烧录至子板所带EPPROM中时,需要将生成的.hex文件改为.iic文件。具体操作步骤如下:
在工程文件夹下右键或者选择Project—>OptionsforTarget’Targer1’,选择Output选项,选中RunUserProgram#1选择如图2.7所示。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tOIrAo3A-1655469851093)(/images/USB2.0/2.7.jpg " ")]
在上图中,需要对RunUserProgramRun#1中进行写下面命令:
xxxx(安装套件中的bin文件夹下hex2bin软件路径)-i-f0xC2-obulkloop.iicbulkloop.hex
命令中中-i表示输出为.iic文件;–f0xC2,表示烧写后,将USB设备再次插入到主机设备上之后,采用C2的启动方式(从外部EEPROM中启动,读取VID,PID等);-o表示将输入文件.hex转换成.iic文件。
设置完之后,点击编译即可输出.iic文件。


2.3 USB上位机

由于电路系统使用的是基于EZ-USBFX2LP系列的USB2.0芯片,可通过使用CyAPI函数类在上位机中对USB芯片进行通信。

由于在校准过程中,数据连续上传且不间断,因此单独创建一个线程用于USB数据通信,如图2.4所示为USB通信程序。进入USB通讯线程,首先获取USB设备句柄与USB端点数目,再开启线程函数准备开始接收数据。在数据接收的过程中,需要将数据从应用软件Buffer中提取出来作后续集中处理。待存满一次实验所需数据后,停止数据接收并关闭线程函数,USB通信程序结束。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I2G3B9fw-1655469851093)(/images/USB2.0/2.8.jpg “图2.8 USB通信程序流程图”)]
需要注意的是,CyAPI函数类负责接收数据函数有同步XferData方法和异步BeginDataXfer/WaitForXfer/FinishDataXfer方法。针对小数据、数据不连续的情况下,使用同步XferData方法更为适用;而对于连续大数据,需要使用多次传输事务的情况下,使用异步BeginDataXfer/WaitForXfer/FinishDataXfer方法更好。


3 USB丢数实验

针对组内32bit数据连续批量传输时,传输结果出现数据丢失的现象,对批量传输进行了测试,之后有对同样可用于大数据传输的等时传输进行了测试,与批量传输进行比对。

3.1批量(BULK)传输

针对批量传输的特性,认为在整个系统的数据传输过程中,USB与上位机间的数据传输是可靠的,丢数源应在FPGA与USB间的数据通信阶段。

系统数据传输的过程为:首先将FPGA产生的数据源会源源不断的写入USB端点的缓存区,当上位机下达传输指令时,如果传输成功,则会将端点缓冲区内数据写入上位机接收缓冲区内,上位机在进行数据处理前需要先将接收缓冲区内的数据取出放入线程中进行处理,并且在取出后会准备下一阶段的数据传输。

在这一过程中,有几个关键点:
(1)USB端点的缓冲区最大可容纳4kB数据,因此当数据流过大时,端点缓冲区会出现不可用状态,只有当其有空余空间时,才会允许数据写入。
(2)上位机的接收缓冲区相当于“一个大小固定,只有一个门的封闭空间”,因此在接收数据时,无法对其进行任何操作,只有接收完成后,才能对其进行相应处理。
因此,对于USB来说,其写入数据是连续的,读出数据是间断的。同时根据BULK传输速率不恒定的特点,其相邻两次读出数据事务的间隔时间也不恒定,当间隔时间过长,则会出现USB端点缓冲区数据溢出情况,即丢数现象。

对于BULK传输方式的丢数,只要保证其在最差的传输情况下,FPGA产生数据源与USB端点间的外加缓冲区不会被写满,就可以避免丢数。为此,采用FPGA片内FIFO IP核作为外加缓冲区,设置其工作模式为异步,大小为128kB。同时FPGA与USB的通信方式为从设备FIFO(Slave FIFO)模式,上位机工作模式为多线程,一个线程负责USB接收数据,一个线程负责数据处理(进制转换、保存TXT文件)。

当数据流为9.6Mbps时,相邻两数据作差曲线如图3.1所示,有明显的丢数现象发生。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fW9GmByk-1655469851094)(/images/USB2.0/3.1.jpg " ")]
当数据流为6.4Mbps时,相邻两数据作差曲线如图3.2所示,没有发生丢数现象。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Cv6p5mlp-1655469851094)(/images/USB2.0/3.1.jpg " ")]


### 3.2等时(ISOC)传输
根据ISOC传输特点,其丢数源即可能出现在FPGA与USB通信阶段,也可能发生在USB与上位机通信阶段。

基本流程与BULK类似,唯一区别在于该过程没有握手判断,数据包以恒定速率传输,不论传输是否成功,都会发送新的数据包。此外,ISOC传输要求接收缓冲区长度和端点的传输大小(SetXferSize)必须是端点的MaxPktSize的8倍。因为USB 2.0 规范允许单个设备每微帧请求最多三个同步数据包,这将使微帧中的最大带宽为 3072 字节。因此当端点的MaxPktSize设置为3072字节时,其接收缓冲区大小应为24576字节。

针对ISOC传输的数据不可靠性,需要先确保数据在USB与上位机通讯前没有因为前端的缓冲区溢出而丢数,考虑到所设置的外加缓冲区FIFO IP核深度为128kB,加上USB端点缓冲区3072B,总共可保证写入33536个32bit数。该实验结果如表3.1所示。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O4J05EFv-1655469851094)(/images/USB2.0/l3.1.jpg " ")]

根据表中数据,可以初步判定,只要FPGA与USB通信阶段不出现因数据溢出造成的数据丢失,则整个系统就不会出现数据丢失。

为了对比BULK传输效果,当数据流为6.4Mbps时,发送10444800个32bit数据时,,ISOC实际只接受到了40856576字节数据(即10214144个32bbit数据),如图3.3(a)所示。与之相比,BULK传输实际接收了41779200字节数据(即10444800个32bit数据)符合发送的数据量,如图3.3(b)所示。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bkgk3fPN-1655469851095)(/images/USB2.0/3.3.jpg " ")]


### 3.3 补充实验
之前的批量传输实验上位机采用的是单次批量事务(一次1个任务队列,每个队列一个包),这里结合等时传输实验,参照官方测速实例,采用多次批量事务(一次64个任务队列,每个队列64个包)进行了补充实验,并加上了曲线绘制功能(每51200个数据绘制一次图形)结果如图3.4所示。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NPliViBP-1655469851095)(/images/USB2.0/3.4.jpg " ")]
图3.4中Successes表示接收成功次数,Failures表示接收失败次数,BytesXferred表示成功接收的总字节数,误差曲线为相邻接收数据的作差值。此外,接收总字节数与实际发送的字节数相同,并且实际测试过程中误差曲线也没有突发调变,一直是误差值为1的直线。最终得出通过调整传输任务队列的个数和每次传输操作的数据包数量可以提高数据速率。


## 4 结论
数据丢失的原因多种多样,不仅在等时(ISOC)传输是这样,在任何USB传输中也是如此。硬件和软件故障,外部条件都是造成数丢失的因素之一。 但是,在其他 USB 传输中,比如 BULK传输模式由于其具有握手包及数据重传机制,可以纠正损坏,但在等时(ISOC)传输中不可能。

本文叙述了一种解决USB传输丢数的方案,即将数据丢失的重心集中在FPGA与USB通信阶段,通过扩大数据发送端的缓冲区大小,来提升数据稳定传输的极限值,并通过实验验证了其可行性。但是本文实验内容上存在一定局限性,由于FPGA片内FIFO存储空间有着一定的限制,只能测试128k大小的外加缓冲区下的情况,后续可以考虑利用外部存储芯片(如SDRAM,DDR2等)进行更细致的实验,给出更加具体可行性的相关参数指标。


参考

[1] Cypress官网实例

[2] 异步FIFO最小深度计算

[3] usb fx2 cy68013 Cyapi使用心得

[4] CY68013 FPGA通信联调总结

[5] 小梅哥FPGA USB上位机开发笔记(一)

由于是直接拷贝我的个人博客的原文,所以文中图片连接存在问题,时间问题后续会进行修改,感兴趣的可以直接去我的个人博客

[6] 个人博客地址


你可能感兴趣的:(FPGA通信技术,fpga开发,物联网)