电子小牛

【嵌入式】【原创】基于XILINX 的USB2.0 开发全攻略~~~赞!

0
阅读(5866)


最近网上比较火USB3.0 。。我看着也痒痒,但是无奈之前没有相关的经验,只有看开发个USB2.0 玩玩,,各位大神轻轻的拍砖,我怕疼,也请大家给点建议哦。。。。。

    小僧每次用U盘的时候,总会在想能否自己做一个USB【1】呢?这样的话,以后还可以兼容各种稀奇古怪的接口,这会儿手头正好有XILINX的开发板,就顺手来了个,,,

我的设计是基于USB的协议原理,参考了Cypress Semiconductor 公司的Cy7C68013,设计出了一款支持全速和USB2.0控制器。并通过了FPGA的速度测试。具体的配置方式在下面的链接:http://china.cypress.com/?rID=14319

大家可以下载用户手册看看。

下面是研究模块信息:

1、收发UTMI模块;

2、存储器;

3、仲裁接口模块;

4、协议层pl模块;

5、控制盒寄存模块;

6、功能接口模块;

7、翻译协议模块;

在包组装模块PA设计中,采用了并行算法对数据包进行CRC校验。在PL模块设计中,用了3级缓冲包进行模块处理。提高了数据和校验的速率,


USB 功能设备芯片结构分析:

1、USB功能测试仪



 


USB 协议分析~~~~~~~

USB 主机是由客户软件、USB 系统软件和 USB 总线接口共 3 部分组成。其中客户软件主要是让 USB 控制器顺利与外设通信,是由界面应用程序和 USB 控制器驱动程序组成。USB 总线接口包括主控制器与根集线器两个部分。主控制器主要负责读取事务处理列表,这些列表是由 HCD 产生的。如图  所示,这些列表组成 USB 包,在总线上传输时开始于 SOF 包,结束于 EOF 包在总线上的传输。SOF 包是第一个在每帧/微帧中传输的信息包,在后面剩余的每帧/微帧时间里,USB 控制器可以传输其他任何事务处理。USB 主控制器的内部集成着根集线器,它是 USB2.0 控制器中的一个连接起点。

 

USB设备架构~~~~

如图 2-2 所示,这就是 USB2.0 完整的设备架构,主要用来说明USB2.0 控制器的特性。由图我们可以知道:一个 USB2.0 设备控制器是由多个配置、多个接口和多个端点组成的,其中设备控制器和配置是一对多的关系,配置和接口是一对多的关系,接口和端点也是一对多的关系,能设备的抽象。我们要注意,在 USB 设备使用之前,要指明其采用哪个接口和配置。实际上,数据传输是由端点完成的,而接口和配置只是对 USB 功能设备的抽象。我们要注意,在 USB 设备使用之前,要指明其采用哪个接口和配置。

USB的连接~~~~~

 

USB 主机和外设之间是以通信流的方式去连接的。而 USB 主机和逻辑外设间的连接实际上是外设接口和主机缓存通过管道、通信流、缓存和端点之间的“交流”过程。USB 是由主机端发起所有的传输事务,然后再采用主从式(master to slave)结构 

当主机用集线器发现了某个设备就连接到该系统,通过向管道和集线器传送命令使此设备进入复位状态。此时设备会将地址设成编号为 0的地址,然后通过次地址去接收主机的请求命令。这个阶段所完成的主要任务是主机发送请求命令而从设备中读取到有关设备的信息。

当设备描述符中的数据长度信息被主机读取后,会用请求命令来为设备分配到一个正式的地址。然后 USB 主机对此设备的通信会以其设备地址为基础,同时在得到特性信息与设备的能力后,选择此设备的配置信息。对设备的列举过程是分别完成的,主机会将得到的信息保存在数据库中,以备其他的应用程序使用。

 

设备的管道和端点是 USB 传输中两个难理解的概念

USB 数据传输类型~~~

 

在 USB 总线上,客户软件启动了所有与 USB 设备单元的数据传输,这里的传输包括 4 个过程:先是启动 USB 总线上面的驱动程序;接着是打开 USB2.0 驱动上的程序;再接着是打开客户软件;最后才是
USB2.0 主控制器。USB 传输类型有四种,分别是中断传输(Interrupt Transfer)、同步传输(Isochronous Transfer)、控制传输(Control Transfer)和批量传输(Bulk Transfer)。其中低速设备只支持中断传输和控制传输。
USB 的数据传输一般是在主机软件和 USB 设备上某个端点间发生的。它们之间的结合就称为管道。通常,每一个管道中的数据流传输都是独立的,一个特定的 USB 设备可以有多个管道。比分说,当某个特定的USB 设备有了一个端点定义后,支持数据从主机传送到 USB 设备的管道,而当其他的端点配置完成后,支持把 USB 设备的数据传送给主机。 

 

 

USB 的事务处理~~~~

主机与常用的 USB 设备之间需要进行数据传输,它的基本单位就是由一系列格式的信息包组成的 USB 事务处理(transcation)。一个 USB事务处理(transcation)是由数据阶段、令牌阶段和握手阶段这三个阶段组成,它是由所含信息包的种类来决定的,这三个阶段的功能如下:
数据阶段:主要负责传输数据,其长度最大可以达 1034 字节;
令牌阶段:表示事务处理的开始,且定义了传输类型,是由主机发出的;

握手阶段:用来检测传输的数据是否能够接收成功,并且将事物处理的状态返回。必须指出的是,所有的事务处理都是从第二阶段的令牌包开始,但可能不包含数据阶段和握手阶段。

 字段定义~~~~

 

.标记(Token):含有输出(OUT),输入(IN),帧起始(SOF),
建立(SETUP)四种PID名。
2.数据(Date):含有数据0(DATA0),数据1(DATA1)两种PID名
3.握手(Handshake):含有确认(ACK),不确认(NAK),停止
(STALL),无回应(NYET)四种PID名。
4.专用(Special):含有前同步(PRE)这种PID名

 

 

 3. 地址字段
功能部件地址(ADR)字段可以指定功能部件,它是由标记PID的值来决定是数据包的发出地还是它的目的地。如表2-2所示,ADR有7
位,一共能确定128个地址。作用是能作输入、输出和建立标记用。

4. 数据字段
数据字段一定是整数字节,它的变动范围是0-1023字节之间。数据位在移出时必须遵循低位在前的规则。如果传输的类型发生改变,则USB的大小也会随之变化。
5. 帧号字段
在11位的帧号字段中,每个帧的发送都会在SOF标记中。通过主机,每过一帧即会将内容加一,一直持续这样操作,直到达到最大值时,就会把此时的值重新置零。6. 循环冗余校验字段
发送端和接收端通过CRC来校验令牌包和数据包中的非PID字段,它能校验出单、双位错误。发送端用来产生CRC码,接收端用来译出CRC码,它们分别在每个字段进行填充位之前产生CRC码以及填充位删除之前译出CRC码。当CRC失败时,接收端就会不接收这些字段甚至整个包,因为它会以为该包的某些字段已经损坏,从而起到保护数据包和标记包中的非PID字段作用。

 

USB2.0 控制器的设计~~~~

目前,在市面上出现的 USB 接口芯片种类非常多,全速的有National Semiconductor 的 USBN9602,Philips 的 PDIUSBD12
和Cypress 的 EZ系列等。高速的有 NEC 的 IPD720122和 Philips 的ISP1581等。本论文设计的目标芯片参考的是 Cypress Semiconductor公司 EZ-USB FX2 的 CY7C68013,它内部含有了串行接口引擎和USB2.0 收发器,还集成了能够编程的外围接口,是世界上首款集成了USB2.0 的控制器。本论文设计的芯片功能基本与 FX2 相同并能优化其内部结构的控制器,与 FX2 不同的地方是内部没有集成微控制器。

 

 

根据本设计要求,本人采用 TOP-DOWN 的设计方式,在参考 USB的功能模型后将本次设计的 USB2.0 控制器分为以下 6 个功能模块,分别是:协议翻译模块 PHY、USB 收发器 UTMI、存储器接口和仲裁器
(Memory Interface and Arbiter)、功能接口(Function Interface)、协议层 PL(Protocal Layer)和控制和状态寄存器(Function /Status Register)。其模块结构图如 4-2 所示。各个模块主要完成的功能将在下面具体的设
计中介绍到。

在划分好 USB2.0 控制器的功能模块后,接着对所有的子模块进行分析,主要是分析模块的翻译协议模块 PHY、控制和状态寄存器、UTMI接口及协议层PL,得出各个模块的设计方案。本设计所需的Verilog HDL源代码文件结构图如图 4-3 所示。

本人根据 USB2.0 协议设计了上面的状态间转换机制功能,主要包
括把总线分成 J 状态、K 状态、SEO 状态和 SE1 状态共 4 种状态,选择
总线上的一种总线事件如挂起通知信号、唤醒信号和复位信号是由这 4
种状态的持续时间长短决定的
[27]
。其中,总线上 SE0 状态、空闲状态和一般的时间是通过三个计时器来完成的,通过改变总线上的电平,来响
应相应的计时器。由图 4-5 可以看到,设计的 UTMI 接口共有上电/功能复位、挂起、正常操作和复位 4 个状态,当 USB2.0 设备控制器的数据在 USB 总线上正常传输时,UTMI 接口才能和协议层 PL 间进行数据的传递。当处于复位状态时,USB 可以在 FS 和 HF 之间进行转换;当完成挂起状态后,会停止控制器内部里面的操作,然后通告信号告诉UTMI,在唤醒信号到来后,激活状态,则控制器退出挂起状态。下面给出设备全速(FS)和高速(HS)之间的状态转换的部分代码:
always @(posedge clk)
if(mode_set_fs) mode_hs <= 1'b0;
else
if(mode_set_hs) mode_hs <= 1'b1;
always @(posedge clk)
if(suspend_clr) USB_suspend <= 1'b0;
else
if(suspend_set) USB_suspend <= 1'b1;
always @(posedge clk)
if(attached_clr) USB_attached <= 1'b0;
else
if(attached_set) USB_attached <= 1'b1;
always @(posedge clk)
if(fs_term_off) TermSel <= 1'b0;
else
if(fs_term_on) TermSel <= 1'b1;
always @(posedge clk)
if(xcv_set_fs) XcvSelect <= 1'b1;
else
if(xcv_set_hs) XcvSelect <= 1'b0;
always @(posedge clk)
if(bit_stuff_off) OpMode <= 2'b10;
else
if(bit_stuff_on) OpMode <= 2'b00;
always @(posedge clk)
USB_reset <= USB_reset_d;
4.2.3 数据传递
数据传递部分主要是实现 UTMI 接口与协议层 PL 间的数据传输,不处理任何数据。它有两个 FIFO,分别是 RxFIFO 和 TxFIFO,用于接收数据和发送数据,过程是这样的:收发器把数据信号 DataIn 通过x_data 信号发送给协议层 PL,与此同时,协议层 PL 会输出数据信号DataOut,把这信号回传递给 UTMI,这是由信号 tx_data 完成的,一旦控制器里面有全局复位时,就把这部分的所有引脚信号清零。

 4.3 协议层 PL 模块的设计
协议层PL处理模块是USB2.0控制器的核心部分,主要是完成USB数据的读写以及 USB 事务的传输控制功能。从收发器传来的数据包在协议层 PL 完成识别和翻译,在 USB 包从外面传输来时,协议层会由USB2.0 协议中的事务传输机制分清数据的事务类型,根据这选择正确的数据包,之后协议层会把这些传输过来的 USB 包传送给存储器接口和仲裁器里去。信息包的封包和拆包也要由 PL 完成,并且还要对信息进行解析。如图 4-6 所示,协议层 PL 主要由三个部分组成,分别是:
包组装 PA(Packet Assembly)、协议引擎 PE(Protocal Engine)和包拆装 PD(Packet Disassembly)。

 


 

 

其中,包组装 PA 的作用是由 PID 和 CRC 校验数据把那些将要发送的数据进行封包,然后把数据传给收发器 UTMI。协议引擎 PE 是协议模块 PL 的核心,主要负责协调 PA、PD 与 IDMA 之间的数据传输。
包拆装 PD 主要负责将收到的数据进行解包,把那些不含有包结尾域和同步域的数据解出 PID 的值和 CRC 校验域,功能刚好与包组装 PA 相反。IDMA 主要负责 PA 和 PD 到缓冲区的数据传输通道保持通畅,给协议引擎 PE 减压。
PA 模块的状态转换过程是这样的:当协议模块收到握手信号 ACK命 令 时 , PA 做 好 发 送 握 手 包 PID 的 准 备 , 当 设 备 要 发 起OUT/SETUP/SOF 传输时,PA 就做好令牌包 PID 发送状态,这些要发送的包是由 PID、端口地址、CRC16 校验值和设备地址组成的,而 SOF包是由 PID、CRC16 和帧号组成。当把 IN 和 SOF 包发送完后,PA 就处于空闲状态,而对于 OUT 和 SETUP 包,PA 则进入 EOP 状态。当数据缓冲区状态为空闲时,则发送 CRC16 校验值,不然就等把数据缓冲器中的数据发送完后,让 PA 进入空闲状态。其中令牌包和数据包的
各个类型对应不同的 PID 值,PA 组装的 USB 包的 PID 值是由协议引擎告知的,下面给出包组装选择 PID 值的代码:

 

 

always @(token_pid_sel)
case(token_pid_sel) // 选择发送令牌包类型
2'd0: token_pid = { ~`USBF_T_PID_ACK, `USBF_T_PID_ACK};
2'd1: token_pid = { ~`USBF_T_PID_NACK, `USBF_T_PID_NACK};
2'd2: token_pid = {~`USBF_T_PID_STALL, `USBF_T_PID_STALL};

2'd3: token_pid = { ~`USBF_T_PID_NYET, `USBF_T_PID_NYET};
endcase
always @(data_pid_sel)
case(data_pid_sel) // 选择发送数据包类型
2'd0: data_pid = { ~`USBF_T_PID_DATA0, `USBF_T_PID_DATA0};
2'd1: data_pid = { ~`USBF_T_PID_DATA1, `USBF_T_PID_DATA1};
2'd2: data_pid = { ~`USBF_T_PID_DATA2, `USBF_T_PID_DATA2};
2'd3: data_pid = { ~`USBF_T_PID_MDATA, `USBF_T_PID_MDATA};
endcase

CRC校验代码

 

主端点采用的是双缓冲设计,USB 设备控制器的双缓冲设计的实质是:让当前使用的缓冲区和我们备用的缓冲区交替使用。我们来看数据通过缓冲区传输的过程:当设备接收到来自主机的数据后,如果是单缓冲设备,在它接收到一个数据后就要等多路转换器取走这一数据后才能接收主机发送的下一个数据,这样就降低了传输的速率,而我们用的双缓冲设计就能克服这个。其实我们用备用的缓冲区,实质上就是把标准的缓冲区容量扩充到 2 倍了。同步传输缓冲区声明长度为 64 字节或者128 字节,其地址指针实际上是在 128 字节或者 256 字节之间往返;批
量传输地址指针需要外部控制,因为批量传输在缓冲区切换时需要主动生成中断通知设备端 MCU,并且允许重传(同步传输没有重传功能),当向主机发送的数据包后等待 ACK 超时时,MCU 会自动将地址重置,
以备重新发送缓冲区数据。一般情况下,设备控制器与 RAM 存储区交换数据的过程是:先由控制器告知存储区,再让一般存储区控制,而当发生大量数据传输时,设备控制器会占用其大量资源。我们的解决办法是通过 DMA 传输,将设备解放出来。

 

下面给出此模块的代码:
module USBf_mem_arb( phy_clk, wclk, rst,
sram_adr, sram_din, sram_dout, sram_re, sram_ write , // SSRAM接口信号
madr, mdout, mdin, write, mreq, mack, // IDMA存储器接口信号
wadr, wdout, wdin, write, wreq, wack // 握手存储器接口信号
);
parameter SSRAM_HADR = 14;
input phy_clk, wclk, rst;

output [SSRAM_HADR:0] sram_adr;
input [31:0] sram_din;
output [31:0] sram_dout;
output sram_re, sram_ write;
input [SSRAM_HADR:0] madr;
output [31:0] mdout;
input [31:0] mdin;
input write;
input mreq;
output mack;
input [SSRAM_HADR:0] wadr;
output [31:0] wdout;
input [31:0] wdin;
input write;
input wreq;
output wack;
wire wsel;
reg [SSRAM_HADR:0] sram_adr;
reg [31:0] sram_dout;
reg sram_ write;
wire mack;
wire mcyc;
reg wack_r;
assign wsel = (wreq | wack) & !mreq;
// 地址路径
always @(wsel or wadr or madr)
if(wsel) sram_adr = wadr;
else sram_adr = madr;
always @(wsel or wwe or wreq or mwe or mcyc)
if(wsel) sram_ write = wreq & write;
else sram_ write = mwe & mcyc;
assign sram_re = 1'b1;
// IDMA阶段
assign mdout = sram_din;
assign mack = mreq;
assign mcyc = mack; // Qualifier for writes
// 握手阶段
assign wdout = sram_din;
assign wack = wack_r & !mreq;
`ifdef USBF_ASYNC_RESET
always @(posedge phy_clk or negedge rst)

`else
always @(posedge phy_clk)
`endif
if(!rst) wack_r <= 1'b0;
else wack_r <= wreq & !mreq & !wack;
endmodule

 

 

仿真结果

 

仿真
[32]
是实现 FPGA 设计的一个重要环节,仿真的目的就是初步检查自己设计的电路是否正确,我们这里做的是功能仿真,主要是检查设计的电路逻辑在理想的情况下是否满足预期的功能,如果提供测试的数据越真实,则越能接近实际的情形,这就具有极高的参考价值。在把模块设计完后就进行输入,然后在对其编译综合,产生的报告
文件及网表文件可提供给仿真时使用,这里我们使用的仿真软件是Model Technology 公司的 Modelsim6.2b。本文只介绍几个重点模块的仿真验证,并将在下面分析仿真的结果。
1.收发器 UTMI 的仿真
UTMI 模块的主要功能是完成总线上的事件检测,对它的仿真也是考虑事件检测这部分的。图 5-1 所仿真的是 USB2.0 设备控制器总线复位过程。它仿真的过程是:主要是告诉主机连接的是全速设备还是高速设备,因为 USB2.0 协议有规定,在总线上最初接到的控制器都被设置成全速设备,如果该控制器是高速的,那么就要通过一系列的握手规定总线复位时告知主机此时连接的控制器是高速的,在得到主机的确认
后,总线上的控制器才转变为高速设备。

【1】USB(通用串行总线)2.0 是由 Compaq、HP、Intel、Microsoft、Lucent、Philips 和 NEC 制定的一种计算机外设连接规范,于 2000 年 4 月 27 日公布。用 USB2.0 接口规范取代 PC 机现存在的外围接口,使其外设的连接具有单一化、热插拔等特点。USB2.0 协议将设备之间的数据传输速度增加到 480Mbps,这一传输速度基本能满足绝大部分 PC 外围设备的要求,这也就是说更高效的外部设备能被用户使用,如原来由于速率限制而不适用 USB 的大容量硬盘、高品质摄像头、高分辨率扫描仪等设备。可以这样认为,USB 的发展是计算机技术的重大变革。