加入星计划,您可以享受以下权益:

  • 创作内容快速变现
  • 行业影响力扩散
  • 作品版权保护
  • 300W+ 专业用户
  • 1.5W+ 优质创作者
  • 5000+ 长期合作伙伴
立即加入
  • 正文
    • 设计原理
    • 从FIFO说明
    • 端口介绍
    • 设计代码
    • 上位机测试
  • 推荐器件
  • 相关推荐
  • 电子产业图谱
申请入驻 产业图谱

源码系列:基于 FPGA 的 USB2.0 设计

04/25 12:00
5234
阅读需 21 分钟
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

大侠好,欢迎来到FPGA技术江湖,江湖偌大,相见即是缘分。大侠可以关注FPGA技术江湖,在“闯荡江湖”、"行侠仗义"栏里获取其他感兴趣的资源,或者一起煮酒言欢。

今天给大侠带来基于FPGA的USB2.0设计,附源码,获取源码,请在“FPGA技术江湖”公众号内回复“ USB2.0设计源码”,可获取源码文件。话不多说,上货。

2019年9月4日,USB-IF终于正式公布USB 4规范。它引入了Intel此前捐献给USB推广组织的Thunderbolt雷电协议规范,双链路运行(Two-lane),传输带宽因此提升,与雷电3持平,都是40Gbps。需要注意的是,你想要体验最高传输速度,就必须使用经过认证的全新数据线。USB4保留了良好的兼容性,可向下兼容USB 3.2/3.1/3.0、雷电3。除此之外,USB4将只有USB Type-C一种接口,并支持多种数据、显示协议,包括DisplayPort,可以一起充分利用高速带宽,也支持USB PD供电。

比较遗憾的是,USB4的发布时间暂未公布。值得注意的是,此次发布的USB4是规范,而并非USB4.0。在此之前,USB Implementers Forum(USB-IF)计划取消USB 3.0/3.1命名,统一划归为USB 3.2。其中USB 3.0更名USB 3.2 Gen 1(5Gbps),USB 3.1更名USB 3.2 Gen 2(10Gbps),USB 3.2更名为USB 3.2 Gen 2x2(20Gbps)。

以上就是关于USB标准以及命名的讯息,而今天我们要做设计的是USB2.0,USB2.0的设备是按照2.0的电源标准设计的,设备所需的电流小于500mA,而USB3.0接口可以提供更大的电流,所以用在USB3.0接口是安全的,这就是标准向下兼容的道理。反之,USB3.0的设备,是否能够在USB2.0接口使用,就要查看设备的说明书。通常的电源都是电压源,设备与电源的电压必须相等,而电源的输出电流要大于设备的电流,即电源功率要大于设备功率。

现在大部分USB设备(比如USB接口的鼠标、键盘、闪存、U盘等等)都是采用了USB通用驱动,而你的系统有USB通用驱动的话(比如XP就内建了USB通用驱动)就能用。而有些USB设备是需要特殊驱动的,比如某些手机,连接到电脑的USB口,是需要安装驱动才能使用的。下面我们一起动手做一做,了解一下如何设计。

设计原理

USB(Universal Serial Bus2.0,通用串行总线)是一种应用在计算机领域的新型接口技术。USB接口具有传输速度更快,支持热插拔以及连接多个设备的特点。目前已经在各类外部设备中广泛的被采用。USB接口有三种:USB1.1,USB2.0和USB3.2。理论上USB1.1的传输速度可以达到12Mbps,而USB2.0则可以达到速度480Mbps,并且可以向下兼容USB1.1。

本次设计我们选择一款开发设备,一块廉价的开发板,其中的USB芯片是Cypress的FX2LP系列中的CY7C68013A代,详细的介绍大家可以去Cypress的官网查询。下面简述一下设计思路。

FX2的设计架构如下图,内嵌480MBit/s的收发器锁相环PLL,串行接口引擎SIE——集成了整个USB 2.0协议的物理层。为适应USB 2.0的480MBit/s的速率,FIFO端点可配置成2,3,4个缓冲区。配置用的是“软配置”——USB固件可由USB总线下载,片上不需集成ROM。拥有四个FIFO接口,可工作在内部或外部时钟下。端点和FIFO接口的应用使外部逻辑和USB总线可高速连接。

基于FX2LP的USB开发,包括三部分:固件程序、驱动、上位机软件。固件程序我们在kiil中写出来,然后配置到我们的芯片中,固件的开发对于FPGA工程师来说是不用写的,是其他工程师配置好芯片后我们直接拿来使用,其主要的配置过程如下图。

先上电复位,然后初始化寄存器变量,然后调用配置函数,打开中断后,判断是否接受到了配置包,如果接收到了就调用TD_POLL()函数,这个是函数是不停的执行扫描端点等。然后判断芯片是否挂起,如果挂起就叫醒芯片,如果没有就一直调用TD_POLL函数,这样就完成所需要的配置。

这里的项目设计要求是要把FX2配置成从FIFO的模式, 配置为单片机工作时钟24M,端点2输出,字节1024,端点6输入,字节1024,信号全设置为低电平有效等。模块驱动时钟配置成内部输出时钟,也就是让FX2给项目设计当作时钟源,输出一个最大的配置时钟48M的时钟。FX2的数据存储区叫端点,有512、1024字节两个存储大小之分。

从FIFO说明

当有一个与FX2芯片相连的外部逻辑只需要利用FX2做为一个USB 2.0接口而实现与主机的高速通讯,而它本身又能够提供满足Slave FIFO要求的传输时序,可以做为Slave FIFO主控制器时,即可考虑用此传输方式。

Slave FIFO传输的示意图如下:

在这种方式下,FX2内嵌的8051固件的功能只是配置Slave FIFO相关的寄存器以及控制FX2何时工作在Slave FIFO模式下。一旦8051固件将相关的寄存器配置完毕,且使自身工作在Slave FIFO模式下后,外部逻辑(如FPGA)即可按照Slave FIFO的传输时序,高速与主机进行通讯,而在通讯过程中不需要8051固件的参与。

FX2系列的有3种封装方式,我们我的开发板用的是56引脚的封装方式的电路图,其电路图如下所示:

端口介绍

IFCLK:FX2输出的时钟,可做为通讯的同步时钟。

SLCS:FIFO的片选信号,外部逻辑控制,当SLCS输出高时,不可进行数据传输

SLOE:FIFO输出使能,外部逻辑控制,当SLOE无效时,数据线不输出有效数据。

SLRD:FIFO读信号,外部逻辑控制,同步读时,FIFO指针在SLRD有效时的每个IFCLK的上升沿递增。

SLWR:FIFO写信号,外部逻辑控制,同步写时,在SLWR有效时的每个IFCLK的上升沿时数据被写入,FIFO指针递增。

FD[15:0]:数据线。

FIFOADR[1:0]:选择四个FIFO端点的地址线,外部逻辑控制。

FLAG A,B,C端点的空满标志位。

开发驱动大家可以在网上找,然后根据自己系统装上合适的驱动。上位机软件用的是官方的开发工具,只有如下的安装包,然后安装第一个和第二个就好了。

设计代码

总模块usb

module  usb(pi_clk, clk, pi_rst_n, pi_usb_flagb, pi_usb_flagc, pio_usb_data,   po_usb_oe_n, po_usb_wr_n, po_usb_address, po_usb_rd_n, led);
  input clk;  input pi_clk;  input pi_rst_n;  input pi_usb_flagb;            input pi_usb_flagc;            inout [15:0] pio_usb_data;
  output  po_usb_oe_n;            output  po_usb_wr_n;            output  po_usb_rd_n;            output  [1:0] po_usb_address;    output led;  wire po_rst_n;
  delay delay_dut(    .pi_clk(pi_clk),    .pi_rst_n(pi_rst_n),     .po_rst_n(po_rst_n)  );
  usb_wr wr_dut(    .pi_clk(pi_clk),    .pi_rst_n(po_rst_n),    .pi_usb_flagb(pi_usb_flagb),     .pi_usb_flagc(pi_usb_flagc),     .pio_usb_data(pio_usb_data),     .po_usb_oe_n(po_usb_oe_n),     .po_usb_wr_n(po_usb_wr_n),    .po_usb_address(po_usb_address),    .po_usb_rd_n(po_usb_rd_n)  );
  my_pll  my_pll_inst (    .areset ( ~ pi_rst_n ),    .inclk0 ( clk ),    .c0 ( c0_sig ),    .locked ( locked_sig )  );  endmodule

读模块usb_rd:

module usb_rd(pi_clk, pi_rst_n, pi_usb_flagb, pi_usb_flagc, pio_usb_data,   po_usb_oe_n, po_usb_rd_n, po_usb_address, po_usb_wr_n, led);
  input pi_clk;  input pi_rst_n;  input pi_usb_flagb;              //端点2标志信号  input pi_usb_flagc;                    //端点6标志信号  inout [15:0]  pio_usb_data;            //输入输出端口
  output reg po_usb_oe_n;                //读标志信号  output reg po_usb_rd_n;                //写使能  output reg po_usb_wr_n;                //读使能  output reg [1:0] po_usb_address;       //端点地址选择  output reg led;
  reg [15:0] temp_data;  reg [9:0] count;  reg [2:0] state;
  assign pio_usb_data = (state == 10) ? 1 : 16'hzzzz;    //读数据,可以一直释放数据总线的控制权
  always @ (posedge pi_clk or negedge pi_rst_n)    if(!pi_rst_n)      begin        state <= 0;        po_usb_oe_n <= 1;        po_usb_rd_n  <= 1;        count <= 0;        po_usb_wr_n <= 1;        temp_data <= 0;      end    else      case (state)          0  :  state <= 1;
        1  :  begin              po_usb_address <= 2'b00;  //地址指向端点2              state <= 2;                      end
        2  :  if(!pi_usb_flagb)      //判断端点2已经满              begin                po_usb_rd_n  <= 0;                state <= 3;                po_usb_oe_n <= 0;              end            else              state <= 2;
        3  :  begin              if(count < 512 - 1)      //接收1024字节的数据              begin                count <= count + 1'b1;              end            else              begin                count <= 0;                state <= 4;              end            if (count == 2)              begin                temp_data <= pio_usb_data;              end            end
        4  :  begin              po_usb_rd_n  <= 1;              po_usb_oe_n <= 1;              state <= 0;            end
        default:  state <= 0;      endcase
  always @ (*)    if(!pi_rst_n)      led <= 1;    else if (temp_data == 16'h33ff)      led <= 0;
endmodule

写模块 usb_wr:

module usb_wr(pi_clk, pi_rst_n, pi_usb_flagb, pi_usb_flagc, pio_usb_data,   po_usb_oe_n, po_usb_wr_n, po_usb_address, po_usb_rd_n);
  input pi_clk;  input pi_rst_n;  input pi_usb_flagb;            //端点2标志信号  input pi_usb_flagc;            //端点6标志信号  inout [15:0] pio_usb_data;            //输入输出端口
  output reg po_usb_oe_n;          //读标志信号  output reg po_usb_wr_n;          //写使能  output reg po_usb_rd_n;          //读使能  output reg [1:0] po_usb_address;    //端点地址选择
  reg [15:0] temp_data;  reg [2:0] state;
  //在状态的3,拿回数据总线控制全,给写入数据  assign pio_usb_data = (state == 3) ? temp_data : 16'hzzzz;
  always @ (posedge pi_clk or negedge pi_rst_n)    if(!pi_rst_n)      begin        state <= 0;        po_usb_oe_n <= 1;        po_usb_wr_n  <= 1;        temp_data <= 0;        po_usb_rd_n <= 1;      end    else      case (state)          0  :  state <= 1;
        1  :  begin              po_usb_address <= 2'b10;  //地址指向端点6              state <= 2;                      end
        2  :  if(!pi_usb_flagc)      //判断端点6已经空              begin                po_usb_wr_n  <= 0;                state <= 3;              end            else              state <= 2;
        3  :  if(temp_data < 512 - 1)        //发送1024字节的数据              temp_data <= temp_data + 1'b1;            else              begin                temp_data <= 0;                state <= 4;              end
        4  :  begin              po_usb_wr_n  <= 1;              state <= 0;            end
        default:  state <= 0;      endcase
endmodule

延时模块 delay:

module delay(pi_clk, pi_rst_n, po_rst_n);
  input pi_clk;  input pi_rst_n;
  output reg po_rst_n;
  parameter T1ms = 50000;  reg [15:0] count;
  always @ (posedge pi_clk or negedge pi_rst_n)    if(!pi_rst_n)      begin        count <= 0;        po_rst_n <= 0;      end    else      begin        if(count < T1ms - 1)            count <= count + 1;        else          begin            count <= count;            po_rst_n <= 1;          end      end
endmodule

上位机测试

安装好驱动和下载的上位机软件,然后在下面的界面中,点击”LGEEPROM”按钮,下载我们写好的的.IIC固件。

然后在下面的页面中会出现先选择other endpt xfers选项中会出现4个端点,然后选择写入的端点或者读的端点执行读写操作。

写的端点是6端点,选择这个端点,写入端点是1024个字节,这里设置的是512字节,也就是写入2次就可以写满了,如下图,和我们编写的代码中写入数据值是一样的。

读操作也就是要读端点2,我们先要给端点一个数,然后才能读我们的端点,我们写入图中显示的数,因为我们设计的是读出的数,如果第三个数位33ff ,就让我们的灯亮,值得一说的是,我们上位机显示的时候是把低位显示到了前面,高位显示到了后面,我们一个包是1024字节,后面的数自动补零,读出数据后可以看到我们的led灯亮,验证出我们的设计正确。

以上就是我们的基于FPGA的usb2.0设计了,希望能给各位大侠起到参考学习作用,此次设计到此结束,有缘再见,告辞。

推荐器件

更多器件
器件型号 数量 器件厂商 器件描述 数据手册 ECAD模型 风险等级 参考价格 更多信息
EPM240T100C5N 1 Altera Corporation Flash PLD, 7.5ns, 192-Cell, CMOS, PQFP100, 16 X 16 MM, 0.50 MM PITCH, LEAD FREE, TQFP-100

ECAD模型

下载ECAD模型
$18.04 查看
EP4CE40F29C8N 1 Altera Corporation Field Programmable Gate Array, 39600 CLBs, 472.5MHz, 39600-Cell, PBGA780, 29 X 29 MM, 1 MM PITCH, LEAD FREE, FBGA-780
$599.92 查看
EPM1270F256I5N 1 Intel Corporation Flash PLD, 10ns, 980-Cell, CMOS, PBGA256, 17 X 17 MM, 1 MM PITCH, LEAD FREE, FBGA-256
$476.27 查看

相关推荐

电子产业图谱

任何技术的学习就好比一个江湖,对于每一位侠客都需要不断的历练,从初入江湖的小白到归隐山林的隐世高人,需要不断的自我感悟自己修炼,让我们一起仗剑闯FPGA乃至更大的江湖。