外设接口通信底层设计也是FPGA广泛应用的领域,常用的外设接口按照通信速度由慢到快排列又有:串口、USB2.0、千兆网口、USB3.0、PCIE、万兆SFP光口等,在这一章节里我们来实现USB2.0和千兆网口的底层时序逻辑,当然对USB3.0、PCIE、万兆SFP光口等一些高速接口也会持续更新学习教程,希望朋友们通过这一章节的学习和实践对常用外设接口的时序逻辑设计有更深刻地理解!
USB2.0可以说是一种用途广泛的接口,它在日常工作中也十分常见,当然USB2.0本身也有自己的协议层和驱动层,典型地如STM32F103系列带有USBTMC协议层硬核直接初始化引脚配置即可使用,但如果SOC芯片内部不带有相关的硬核,那么就需要用户手工实现底层,毫无疑问工作量是非常巨大的。
对于FPGA和一些不带USB2.0硬核的SOC芯片来说,有两种常用的芯片即CY7C68013和FT232HL可以实现USB.20协议,如图1所示是豌豆开发板Artix7上USB2.0电路,在这里选择了经典的FT232HL芯片,FPGA直接连到芯片相关引脚,再对FT232HL芯片进行操作即可实现USB2.0通信。
图1 豌豆开发板Artix7上FT232HL电路
需要说明的FT232HL芯片本身需要初始化一些数据才能正常工作,笔者猜测其芯片本身不带有ROM,所以需要外扩EEPROM进行初始化数据掉电存储,如图2所示是FT232HL外挂的EEPROM电路图,FT芯片公司也推出了一个上位机可以初始化并烧写外挂EERPOM,其安装包为FT_Prog_v3.0.56.245 Installer.exe。
图2 FT232HL外扩的EEPROM电路
打开FT_Prog_v3.0.56.245 Installer.exe安装包,按照提示一路Next即可,如图3所示是安装FT公司的FT_Prog配置软件的安装截图,我们通过这个官方上位机软件,就可以实现对板载FT232HL初始化配置,因为FT232HL这款芯片本身也有很多种用途,如图4所示是FT232HL的芯片手册截图,大家可以看到该芯片提供了FIFO、SPI、I2C、JTAG等接口于一身的单芯片解决方案,所以这些不同用途需要做不同地初始化配置。
图3 安装FT公司的FT_Prog配置软件
图4 FT232HL功能的说明
FT232HL在出厂的时候,默认是UART模式,配置同步FIFO模式,需要通过官方提供的配置软件FT_Prog进行配置,整个配置过程也很简单,如图5到7所示,为了方便大家操作,笔者把相关的配置都逐一截图下来,配置完成后即可在PC的设备管理器中查看到FT232HL设备如图8所示。
图5 FT_Prog下查找FT232HL设备号
图6 FT_Prog下对FT232HL进行245 FIFO配置
图7 FT_Prog下对FT232HL的外挂EEPROM进行烧写
图8 PC设备管理器查看FT232HL设备
如图9所示是FT232HL芯片在FT245 FIFO模式下的引脚定义,其中ADBUS[7:0]即为输入输出总线,对于FPGA端来说CLKOUT、RXF#、TXE#均为输入引脚,其他的RD#、WR#、SIWU#、OE#均为输出引脚,我们对照芯片手册来看下这些引脚的功能,先大致有个了解,再对照芯片手册的读写逻辑进行代码还原,实际上正如模式名所述,在这种模式下对于FPGA端也如同控制FIFO一样,即可完成对USB2.0的读写操作。
1. CLKOUT:FT232HL输出的60Mhz标准时钟,且所有的信号都把该时钟作为参考时钟进行同步;
2. RXF#:当其为高电平时,表示不能从FIFO中读取数据。当为低电平时,表示FIFO中有数据可读,FPGA端则需要把RD#拉低,在RXF#和RD#均为低电平时候通过ADBUS总线读取数据,但芯片手册仍指出:FPGA端在进行读操作时,需要在置RD#为低之前至少提前一个时钟周期拉低OE#;
3. RD#:FPGA端置RD#为低,表示当FIFO中有数据可读时,向FIFO中读取数据;
4. TXE#:当其为高电平时,表示不能从FIFO中写入数据。当为低电平时,表示可以向FIFO中写入,FPGA端则需要把WR #拉低,在TXE#和WR #均为低电平时候通过ADBUS总线写入数据;
5. WR#:FPGA端置WR #为低,表示向FIFO中写入数据;
6. OE#:驱动FT232HL芯片在读操作时输出数据,需要在置RD#为低之前至少提前一个时钟周期拉低OE#;
7. SIWU#:芯片手册指出当其为低电平时可唤醒USB主设备,默认为高电平,在不用的时候可以直接拉至VCCIO上;
8. ADBUS:8位的输入输出总线。
图9 FT2323HL芯片在FT245 FIFO模式下的引脚定义
如图10所示是FT2323HL芯片在FT245 FIFO模式下的读写时序,大家可以看到在读时序中,FT232H端会将RXF#拉低,表示此时可以读取 FIFO 里的数据,FPGA端则将OE#先拉低,过至少一个时钟周期,再将RD#拉低,在CLKOUT上升沿采集数据即可;在写时序中,FT232H端将TXE#拉低,表示现在可写入,FPGA端则将WR#拉低,在CLKOUT上升沿写入数据即可。整个读写时序逻辑非常简单明了,显然FT232HL芯片内部已经实现了USB2.0的驱动层和协议层等,FPGA端只需像操作FIFO一样即可完成USB2.0通信。
图10 FT2323HL芯片在FT245 FIFO模式下的时序
在这个例程中我们实现一个基本场景,上位机通过USB2.0接口向豌豆开发板发送数据报文,开发板接收后再向上位机返回一模一样的数据报文,同时在报文的末尾处加入了经过计算后的2字节USB2.0 CRC校验数据。有一个网站提供了各种常见接口CRC校验计算的verilog实现,具体网址是:http://www.easics.com/webtools/crctool,但笔者前段时间访问好像又需要注册账号才可以下载所以比较麻烦,不过好在这些工作已经提前为大家做好了,如表1所示是crc16_calculate模块的信号列表,代码则是通过上述网站直接生成的,笔者只不过重新规范了一下信号名称,如图11所示是模块的具体代码设计。
信号列表 | ||
信号名 | I/O | 位宽 |
clk | I | 1 |
rst_n | I | 1 |
sclr | I | 1 |
din | I | 8 |
din_vld | I | 1 |
crc16_dout | O | 16 |
表1 crc16_calculate模块信号列表
在这个模块中,有输入信号sclr作为复位信号,所以FPGA每次计算校验完一包完整的CRC数据后拉高一个时钟周期的sclr即可再次校验下一包数据,din和din_vld是需要校验报文的字节输入数据和输入数据指示信号,而crc16_dout则是计算校准后的输出数据,即CRC校验后的结果。
图11 USB2.0 CRC计算模块的代码设计
如表2所示是usb_driver模块信号列表,在这里模块里我们只需要完成前面所分析的FT2323HL芯片在FT245 FIFO模式下的读写时序即可,如图5-12所示是USB2.0驱动模块的代码设计,类似地因为要把数据和CRC校验发送到USB2.0上位机,所以模块中需要有FIFO缓存从USB2.0接到的数据,在写入FIFO的过程中也代入CRC校验模块计算后2字节的校验和,最后在数据写入完成后,即开始读取数据并在报文末尾添加CRC打包发送给USB2.0上位机。
信号列表 | ||
信号名 | I/O | 位宽 |
clk_120m | I | 1 |
usb_clkout | I | 1 |
rst_n | I | 1 |
usb_rxf | I | 1 |
usb_txe | I | 1 |
usb_crcdata | I | 16 |
crcin | O | 8 |
crcin_vld | O | 1 |
crc_sclr | O | 1 |
usb_oe | O | 1 |
usb_rd | O | 1 |
usb_wr | O | 1 |
usb_siwu | O | 1 |
usb_data | I/O | 8 |
表2 usb_driver模块信号列表
图12 USB2.0驱动模块的代码设计
如图13所示是 USB2.0接收并回复CRC16位校验顶层文件的例化,这里只是把CRC计算模块和USB2.0驱动模块相关信号例化到一起即可,因为USB的clk_out时钟是60Mhz,这里为了更加方便地在ILA下观察各个波形,所以用PLL分频了120Mhz时钟给ILA IP核。
图13 USB2.0接收并回复CRC16位校验顶层文件的例化
在成功安装配置好FT232HL芯片的工作模式后,大家打开USB2.0的上位机,输入0123456789即5个字节的数据,点击发送按键,如图14所示即可看到开发板返回01 23 45 67 89 17 F8,打开CRC Calculator插件选择CRC-16/USB模式,如图15所示,可以看到两者的计算结果想同,但这里需要注意的是CRC Calculator插件计算任何模式下的CRC都没有进行高低字节的替换,而实际项目工程中都存在CRC高低字节替换的步骤。
图14 USB2.0上位机的数据收发实验现象截图
图15 CRC Calculator插件计算CRC-16/USB的检验结果