基于FPGA的USB2.0控制器设计_接口电路论文
关键词:usb vhdl fpga
在视频存储和图像宽带领域中,经常遇到实时高速数据传输的要求。2000年4月,由intel、microsoft、nec、compaq、lucent、phillips等公司共同制订的usb2.0(universal serial bus)传输协议,其速度远远超过了目前使用ieee1394接口进行视频传输的400mbps,达到了480mbps;而且具有即插即用的pnp(plug and play)、可进行菊花链式的级联(通过usb hub进行外围扩展)、可串连多达127个usb设备等优点。应用该协议可支持实时语音、音频和视频数据的传输。
本文针对高速数据传输需求,根据usb2.0的协议规范,利用vhdl语言实现符合该协议的功能控制器,在视频压解系统中使数据在pc与外设之间高速传输。如图1所示由视频a/d采集的原始视频数据,在philips公司生产的tm1300专用视频处理器中压缩后,通过usb控制器送至pc机。pc机的整个通过usb控制器传输到tm1300,解压后发送至视频d/a。
1 控制器结构原理
usb2.0控制器结构框图如图2所示。控制器主要由两个部分组成,其一为与外设的接口,另一个是内部协议层逻辑pl(protocol layer)。内部存储器仲裁器实现对内部dma和外部总线对存储器访问之间的仲裁。pl则实现usb的数据i/o和控制。
接口有三种:一种是与微控制器之间的功能接口;一种是与单口同步静态存储器(ssram)之间的接口;另外一种是与层之间的接口。这里符合utmi(usb transceiver macrocell interface)规范定义。
2 控制器实现
控制器接口的信号框图如图3所示。存储器采用标准的单口sram,其信号接口由32位数据线sram_data、15位地址线sram_addr及读写信号(sram_we和sram_rd)组成,系统所需sram的容量为2 15×32bit=128kb。
而与微控制器之间的接口信号包括32位数据线data、18位地址线addr以及dma请求和响应信号(dma_req和dma_ack)。由于要支持到128kb,需要17位地址线,另外还需要一根地址线来选通ssram和usb控制器内部的寄存器,总共需要18根地址线addr[17:0]。定义如下:
usb_rf_sel <= !addr[17];
usb_mem_sel <=addr[17];
第18位地址addr[17]为高时选择缓冲存储器,否则选择内部寄存器。地址addr[16:2]直接用于存储器ssram的地址。
2.1 utmi接口
utmi接口信号包括:与发送数据相关的信号(txvalid、txready等),与接收数据相关的信号(rxactive、rxvalid、rxerror等)以及16位双向数据线。
在层,该控制器需要一个外部的usb收发器(transceiver),本文采用的是philips公司的isp1501芯片。该芯片用作usb2.0的模拟前端,从usb电缆来的差分信号进行反转不归零码(nrzi)解码和位解填充转换成16位并行数据;反之,16位并行数据通过一个差分驱动电路经过串行化、位填充和nrzi编码输出到usb电缆上。isp1501通过管脚mode0和mode1决定收发器的工作模式,共有4种工作模式:mode[1:0]为“00”时,收发器处于断开状态;为“01”时处于全速(full speed)模式(此时usb带宽为12mb/s);为“10”时是高速(high speed)模式(此时usb最大带宽是480mb/s);为“11”时是hs chirp模式。
utmi接口通过译码mode[1:0]来控制isp1501在hs和fs之间转变。
if mode_hs='1'then
mode<='10'
elsif mode_hs='0'then
mode<='01'
end if;
2.2 协议层
控制器的核心逻辑位于pl(protocl layer)模块,负责管理所有usb数据i/o和控制通信,其结构如图4所示。
dma和存储器接口提供随机存储器访问和dma操作。该模块使pl和外部微控制器采用dma方式访问ssram。当外部总线有访问sram的请求时,且pl没有请求访问存储器,控制逻辑如下:req、ack分别对应外部总线和存储器之间的请求和响应信号,din、addr和we分别是外部总线给出的数据、地址和写信号,mreq是内部dma向存储器发送的请求信号,mdin、maddr和mwe分别是内部dma给出的数据、地址和写信号。
sel <=(req or ack_r) and(not mreq);
if sel='1' then
sram_out<=din;
sram_adr<=addr;
sram_we<=req and we;
else
sram_out<=mdin;
sram_adr<=maddr;
sram_we <=mwe;
end if;
由控制逻辑可看出,内部dma操作的优先级比外部总线高。
协议引擎(protocol engine)处理所有标准的usb握手信号和控制通信。分组组装器组装分组并送入输出fifo,先组装分组头,插入适当的pid(分组标识)和校验和,然后加入数据域。分组拆装器先解码出pid和序列号以及校验和,再从8位pid取低4位(或高4位取反)得到pid[3:0],通过usb2.0协议的pid类型定义译码出pid名,判断是token分组(out、in、sof和setup)还是data分组(data0、data1、data2和mdata)。
pid_token<=pid_out or pid_in or pid_sof or pid_setup;
pid_data <=pid_data or pid_data1 or pid_data2 or pid_mdata;
如果是token分组(格式定义如图5所示),则将后续的16bit数据分别放入两个8bit临时token寄存器token0和token1,然后取出分组中的7位地址、4位端点号及5位crc校验码。
token_fadr<=token0[6:0];
token_endp<=token1[2:0] & token0[7];
token_crc5<=token1[7:3];
对于特殊的token须进行特殊的处理,本文实现的控制器只对sof这一特殊token进行操作,解出pid后的11位帧号及5位crc5校验码。
frame_no<=token1[2:0] & token0;
token_crc5<=token1[7:3];
检验校验码是否出错,如果出错等待下一个token,否则将地址、端点号和帧号等放入相应寄存器。token类型如果是in,则执行组装分组并发送寄分组;如果是out则拆卸接收到的数据分组。对于其他不支持的token则视为错误处理:pid_error<=pid_ack or pid_nack or pid_stall or pid_nyet or pid_pre or pid_err or pid_split or pid_ping;如果出错则不进行token的解码,而等待下一个token的到来。
如果是data分组,则紧接着pid的是最大载荷为1024字节的数据和16位crc16校验码。对数据的处理先写入端点寄存器,然后通过dma操作写入ssram。下面详细介绍端点寄存器和dma操作
2.3 端点操作
数据的传输实际上通过端点(endpoint)进行,控制器通过写端点的寄存器来配置端点,该控制器最多可有16个端点,每个端点有相应的4个寄存器:epn_csr、epn_int、epn_buf0和epn_buf1(这里n=0、1、2或3),其格式如图6所示。本文使用addr[8:2]7根据地址线来访问这些寄存器,addr[8:4]用来选择端点号,其值(16进制)从4到19分别表epn(n=0...15)。addr[3:2]指定寄存器类型:“00”代表csr(control status register);“01”代表中断寄存器;“10”指向buffer0;“11”代表buffer1。这两个buffer用来作临时数据存储,buffer0和buffer1分别作为专用的输入/输出缓冲器来提高usb的数据吞吐能力。双buffer能够减少微控制器和驱动软件之间的延迟。其中端点的csr寄存器指定端点的工作模式并且向控制器报告指定端点的状态。ep_csr[31:30]必须初始化为“00”(最初使用buffer0),通过读这2位可以知道下次所要处理的缓冲器;为“01”时,指定buffer1。ep_csr[27:26]和ep_csr[25:24]分别指定端点类型和传输类型,其类型编码参见表1。ep_csr[21:18]指定端点号,总共可以有16个端点。ep_csr[15]时dma使能位,为“1”时允许外部dma操作,否则不允许dma操作。
表1 类型编码表
ep_csr[27:26] | 端点类型 | ep_csr[25:24] | 传输类型 |
00 | 控制端点 | 00 | 中断传输 |
01 | in端点 | 01 | 同步传输 |
10 | out端点 | 10 | 块传输 |
11 | 保留 | 11 | 保留 |
当控制器收到中断时,读中断源寄存器(ep_int[6:0])来判断中断源和产生的原因。可自定义中断源,如ep_int定义为该控制器接收到不支持的pid而产生的中断:ep_int<=pid_error。ep_int和ep_int分别表示buffer1和buffer0的满或空的状态位。
ep_buf[31](标记缓冲器是否被使用过)在使用后被控制器置“1”,在清空或重填充该缓冲器后,控制器清除该位。该闰初始化时为“0”。ep_buf[30:17]指定缓冲器能容纳的字节数。ep_buf[16:0]缓冲器的指针,装载存储器sram中数据的地址。
控制端点(endpoint0)比较特殊,由于它既要接收也要发送数据,因此对于控制端点,buffer0用于out缓冲器,buffer1则是in缓冲器。从setup和out分组来的数据,写入buffer0,in分组的数据则是从buffer1中获取。
2.4 dma操作
dma操作允许控制器与功能接口之间数据的透明传输。一旦设置了dma操作,则不需要微控制器的干预。每个端点有一对dma_req和dma_ack信号。当csr寄存器中dma使能信号位(ep_csr[15])被置位时,usb控制器使用dma_req和dma_ack这两个信号来进行dma的流控制。当缓冲区有数据或为空需要填充时发送dma请求信号dma_req,每传输4字节,响应一个dma_ack信号。
由于usb2.0协议定义的事务操作以8bit为单位,因此完成一次32bit的dma操作需要进行4次写8bit。内部dma采用高效的one-hot状态机设计方法,状态转换如图7所示。当需要将接收到的数据存储到sram(rx_dma_en=1)时进入wait_mrd状态,在该状态选中一个临时数据寄存器,并向存储器发送请求信号mreq,从存储器中预取4字节(当接收到的数据少于4字节时,保证有4字节的数据写入存储器)到该寄存器中,然后进入mem_wr状态。当pl的分组拆装器接收到1字节数据时,将该字节写入临时存储器,转入下一状态mem_wr1;当分组拆装器没数据给dma仲裁器时则进入mem_wr2状态,在此状态将临时存储器中的数据写入sram,然后回到idle状态。在操作过程中,使用计数器adr_cb对传输字节数进行计数,通过addr_cb[1:0]的值标识当前传输的是32bit中的哪个字节。计数器sizu_c每接收1字节数值加1。
在需要读取sram中的数据(tx_dma_en=1)时,dma仲裁器由idie状态进入mem_rd1状态,读取4字节数据到发送缓冲区中,然后进入状态mem_rd2,再读4字节进入状态mem_rd3,这8字节轮流使用buffer0和buffer1缓冲区:
在需要读取sram中的数据(tx_dma_en=1)时,dma仲裁器由idle状态进入mem_rd1状态,读取4字节数据到发送缓冲区中,然后进入状态mem_rd2,再读4字节进入状态mem_rd3,这8字节轮流使用buffer0和buffer1缓冲区:
if((not adr_cb) and mack
then buffer0<=sram_data_i;
elsif (adr_cb and mack)
then buffer1<=sram_data_i;
end if;
在mem_rd3状态判断是否还需要读下一个数据,如果需要再进入状态mem_rd2,否则在传输完所有字节后,返回到idle状态。在发送数据过程中,使用14bit计数器sizd_c决定传输字节数,取自ep_buf[30:17],每发送1字节数据,它的值减1。在图7中的各个状态中,由于超时、crc校验错误或得到的数据发生错误时,pe产生的abort信号会使当前状态都回到idle。
文中阐述了usb2.0功能控制器的一种实现方案。
其vhdl语言实现代码,已在xilinx公司的fpga virtex xvv3006fg456中通过了xilinx ise的仿真、综合及布局布线。fpga的规模是32万门,1536个clb(可配置逻辑单元)。该控制模块占用2050个slice(66%),使用了1697个slice触发器(27%)和3047个4输入lut表(49%)。整个fpga的速度可达到56.870mhz,完全满足视频数据的高速传输(对32bit数据操作,达到480mb/s的速度时钟只需15mhz)。该方案实现的控制器便于修改且易于实现,可作为一个功能模块嵌入到soc中,可使不同情况最大限度地灵活设计片上系统。