作者:孙立辉 刘院英 和志强
一、引言
USB总线因其传输速度快、占用资源少以及真正的即插即用等诸多优点,受到了广大开发者的青睐,已经成为很多计算机设备的一种基本配置。目前被广泛采用的USB设备开发方案主要有以下两种(1)利用USB设备端接口芯片加微控制器结构。如国内用的比较多的Philips公司的PDIUSBD12/ISP1581等。(2)采用USB
单片机。采用这两种方案要求开发者彻底理解USB协议的细节,并编写出固件程序。固件的运行要占用微控制器的时间和空间资源,实际
通信效率不会很高。也有人用
FPGA实现固件的功能,但这种方案开发和调试的难度很大。本人在实际工作中用FPGA外部直接连接一片USB协议芯片FT245BM,实现了FPGA与PC机的USB通信,该方法不用微控制器,减少了元器件的个数,并且占用FPGA资源很少,FPGA仍然可以实现其他逻辑功能,系统设计的灵活性很大。
二、FT245BM简介
FT245BM由FTDI (Future Technology Devices Int. Ltd.)公司推出,该芯片的主要功能是进行USB和并行I/O口之间的协议转换。芯片一方面可从主机通过USB串行总线接收数据,并将其转换为并行I/O口的数据流格式发送给外设;另一方面外设可通过并行I/O口将数据转换为USB串行数据格式传回主机。中间的转换工作全部由芯片自动完成,开发者无须考虑固件的设计。该芯片提供了通用的并行I/O口方便与微控制器、FPGA或其他外设接口。在PC机端安装了FTDI公司提供的驱动程序,只需熟悉简单的VB、VC编程,就可很容易地进行上位机软件开发。
关于FT245BM的内部结构及详细地引脚介绍读者可以参考其他相关资料,在此仅对与本设计相关的内容作一个介绍。FT245BM内含两个FIFO数据缓冲区,一个是128字节的接收缓冲区,另一个是384字节的发送缓冲区。它们用作USB数据与并行I/O口数据的交换缓冲区。FIFO实现与外界(微控制器、FPGA或其它器件)的接口,主要通过8根数据线D0~D7、读写控制线RD#和WR#以及FIFO发送缓冲区空标志TXE#和FIFO接收缓冲区非空标志RXF#来完成数据交互。TXE#为低表示当前FIFO发送缓冲区为空,为高表示当前FIFO发送缓冲区满或者正在存储前一个字节,禁止向缓冲区中写数据。RXF#为低表示当前FIFO的接收缓冲区非空。RD#信号由低变高将从FIFO缓冲区中读取数据。当RD#变低时将数据送到数据总线。RXF#为高不能从FIFO读数据。读写时序见图1和图2。
三、FT245BM与FPGA的接口设计
3.1 硬件
威廉希尔官方网站
设计
图3是FT245BM的USB与FPGA的接口威廉希尔官方网站
,FPGA选用ALTERA EPF1K50TC-144,其中D0~D7是FT245BM与FPGA交换数据的数据总线,USB_RD#、USB_WR、USB_TXE#、USB_RXF#是相关的控制总线。
图3 FT245BM与FPGA的接口威廉希尔官方网站
3.2 FPGA收发状态机设计
下面是用Verilog HDL 描述的FPGA收发状态机,为便于读者理解FPGA对FT245BM的读写过程,本文将接收和发送状态机分开给出。当然在实际应用中也可以将接收和发送操作合成一个状态机来实现。
3.2.1 接收状态机
接收状态机主要功能是查询USB_RXF引脚的状态,当检测到USB_RXF变低,即可获知上位机已经将数据写入到FT245BM的缓冲区,然后产生读控制时序,将FT245BM接收缓冲区中的数据读入到FPGA的缓冲区。重复以上步骤直到将一帧数据读完,然后执行相应的帧处理操作。下面是用Verilog HDL描述的接收状态机。
@always (posedge clk ) /*clk为FPGA工作时钟。
if(rst && USB_RXF==0)
begin
case(Rstate)
Rstate0:
begin
USB_RD<=0; /*产生读信号的下降沿
Rstate<=Rstate1;
end
Rstate1:
begin
RframeBuf[Rpointer]<=USB_DATA; /*读FT245BM芯片FIFO的当前字节
Rstate<=Rstate2;
end
Rstate2:
begin
if(Rpointer== FrameLen-1) /*如果已经接收到完整的一帧,则转Rstate3,
begin
Rstate<=Rstate3;
Rpointer<=0;
end
else /*一帧未接收完,转Rstate0继续接收
begin
Rstate<=Rstate0;
Rpointer<=Rpointer+1;
end
USB_RD<=1;
end
Rstate3: /*处理收到的帧
begin
Rstate<=Rstate0;
/*在此添加处理帧的代码,本文略*/
end
end
else
begin
Rstate<=Rstate0;
USB_RD<=1;
End