基于FPGA的USB2.0读写控制
项目简介
我们前面已经写过了USB3.0的FPGA实现,所用到的芯片是FX600Q芯片,这次我们讲解USB2.0的FPGA代码的编写。我们用到的芯片是Cypress厂家的Cy7C68013A,该款芯片在市场上的应用率极广,我们这里不涉及USB的具体协议,也不涉及固件的写法,因为前者已经封装进了USB芯片,后者Cypress厂家给出了例程。与USB3.0一样,我们能将USB芯片看成一个FIFO进行书写。
本次实验所用到的软硬件环境如下:
FPGA开发板:锆石A4plus开发板
软件环境:quartus II 13.1
上位机软件:Cypress官方提供(会放进群里面,有需要的进群下载)
CY7C68013A芯片介绍
我们从开发板的硬件电路中找到关于该款USB芯片的介绍:
从上图可以看出,芯片中含有一个8051的核。该电路在开发板上的连线如下:
其实USB芯片在下载官方的固件之后,我们可以把他等价成一个FIFO,如下图:
当然我们也可以对USB的固件进行编程,然后对数据进行一定的处理,但不在本次实验内容中。
接下来,我们将对上面的引脚做一些简单的说明,当然想具体了解的可以查阅技术手册:
USB_CLKOUT:USB芯片输出时钟引脚,本程序中不使用,不多关注
IFCLK:slave fifo的同步时钟信号,在USB工作在slave模式下,FIFO的同步信号,也是本次实验中使用的时钟引号。
FLAGA:slave FIFO是否可编程的标志信号,在我们的程序中也使用不到。
FLAGB:FIFO的满信号
FLAGC:FIFO的空信号
SLCS:USB芯片的片选信号,低电平使能
SLWR:USB芯片等价FIFO的写信号,低电平有效
SLRD:USB芯片等价FIFO的读信号,低电平有效
SLOE:USB芯片输出的使能信号,该信号为低电平时,USB芯片作为输出,高电平作为输入。
FIFOADR:该款USB芯片相当于4个FIFO,该信号控制着哪一个FIFO被选择,4个FIFO的编号是2,4,6,8分别对应00,01,10,11。具体哪个FIFO被选择是由固件所确定的,在上位机软件上可以查看。
该款USB芯片的驱动与固件程序由于CSDN无法上传文件,我们放在了群里面,需要的同学进群自己下载即可:
其中1是芯片的驱动,2是Cypress官方的配套软件与固件。
CY7C68013A芯片读写时序控制
这里我们从技术手册中找到芯片的读写时序,这里以同步读写为例:
由于这里时序特别简单,我们便不再画出具体的时序图,直接由上面的时序图进行写代码,相信大家从代码中很容易就可以读懂时序。
CY7C68013A芯片读写代码
USB2.0写代码:
`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author : zhangningning
// Email : [email protected]
// Website :
// Module Name : usb_write.v
// Create Time : 2020-02-19 12:53:38
// Editor : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date By Version Change Description
// -----------------------------------------------------------------------
// XXXX zhangningning 1.0 Original
//
// *********************************************************************************
module usb_write(
//System Interfaces
input rst_n ,
//USB Interfaces
input usb_ifclk ,
input usb_full ,
output wire usb_slcs ,
output wire usb_slwr ,
output wire usb_slrd ,
output wire usb_sloe ,
output wire [ 1:0] usb_fifoadr ,
output reg [15:0] usb_data
);
//========================================================================================\
//**************Define Parameter and Internal Signals**********************************
//========================================================================================/
reg usb_slwr_r ;
//========================================================================================\
//************** Main Code **********************************
//========================================================================================/
assign usb_slcs = 1'b0;
assign usb_slwr = ~((usb_full == 1'b1) && (usb_slwr_r == 1'b0));
assign usb_slrd = 1'b1;
assign usb_sloe = 1'b1;
assign usb_fifoadr = 2'b10;
always @(posedge usb_ifclk or negedge rst_n)
if(rst_n == 1'b0)
usb_slwr_r <= 1'b1;
else if(usb_full == 1'b1)
usb_slwr_r <= 1'b0;
else
usb_slwr_r <= 1'b1;
always @(posedge usb_ifclk or negedge rst_n)
if(rst_n == 1'b0)
usb_data <= 16'd0;
else if(usb_slwr == 1'b0)
usb_data <= usb_data + 1'b1;
else
usb_data <= usb_data;
endmodule
USB2.0读代码:
`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author : zhangningning
// Email : [email protected]
// Website :
// Module Name : usb_read.v
// Create Time : 2020-02-19 13:50:12
// Editor : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date By Version Change Description
// -----------------------------------------------------------------------
// XXXX zhangningning 1.0 Original
//
// *********************************************************************************
module usb_read(
//System Interfaces
input rst_n ,
//USB Interfaces
input usb_ifclk ,
input usb_empty ,
output wire usb_slcs ,
output wire usb_slwr ,
output wire usb_slrd ,
output wire usb_sloe ,
output wire [ 1:0] usb_fifoadr ,
input [15:0] usb_data ,
//Communication Interfaces
output reg data_en ,
output reg [15:0] data
);
//========================================================================================\
//**************Define Parameter and Internal Signals**********************************
//========================================================================================/
reg usb_slrd_r ;
//========================================================================================\
//************** Main Code **********************************
//========================================================================================/
assign usb_slcs = 1'b0;
assign usb_slrd = ~((usb_empty == 1'b1) && (usb_slrd_r == 1'b0));
assign usb_sloe = 1'b0;
assign usb_slwr = 1'b1;
assign usb_fifoadr = 2'b00;
always @(posedge usb_ifclk or negedge rst_n)
if(rst_n == 1'b0)
usb_slrd_r <= 1'b1;
else if(usb_empty == 1'b1)
usb_slrd_r <= 1'b0;
else
usb_slrd_r <= 1'b1;
always @(posedge usb_ifclk or negedge rst_n)
if(rst_n == 1'b0)
data_en <= 1'b0;
else if(usb_slrd == 1'b0)
data_en <= 1'b1;
else
data_en <= 1'b0;
always @(posedge usb_ifclk)
data <= usb_data;
endmodule
从上面可以看出控制一个USB2.0的芯片其实就是相当于控制一个FIFO。
USB2.0的测试结果
我们在quartus II中分别下载上面两个程序到开发板中,观察上位机软件的现象。
对于USB写模块,我们在上位机CyConsole看到如下现象,证明了我们程序的正确性:
在验证USB读模块的正确性的时候,我们在上位机软件中发送如下数据:
然后利用Signaltap进行抓取数据验证FPGA接受到数据的正确性,抓到图的数据如下:
将Signaltap中抓取到的数据与CyConsole发送的数据对比,我们可以验证读模块的正确性。
结束语
对文章有什么看法或者需要更近一步交流的同学,可以加入下面的群: