DIY编程器网

 找回密码
 注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 954|回复: 0
打印 上一主题 下一主题

[待整理] 利用FPGA实现外设通信接口之: 典型实例-USB 2.0接口的设计与实现

[复制链接]
跳转到指定楼层
楼主
发表于 2014-10-12 16:31:17 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
        10.7  典型实例17:USB 2.0接口的设计与实现

        10.7.1  实例的内容及目标

         
        1.实例的主要内容

        本节旨在设计实现了FPGA通过FX2 USB 2.0接口芯片与PC机进行高速数据通信,分为读数据、写数据和读写数据3部分内容。帮助读者进一步了解USB接口芯片的工作原理和设计方法。
         
        2.实例目标

        通过本实例,读者应达到如下目标。
        ·  了解FX2 CY7C68013芯片的工作原理和Slave FIFO模式时序。
        ·  了解FX2的固件设计以及USB驱动程序设计。
        ·  熟练掌握状态机的使用。
        ·  实现FPGA与PC机之间的USB接口通信。
         
        10.7.2  USB接口通信实战步骤

        首先创建工程并为工程添加文件,如图10.30所示。
         
        然后编译工程并下载至硬件,如图10.31所示。
                

        图10.30  创建工程并添加文件       图10.31  编译工程并下载

         

        接下来可以加载固件了,固件程序的载入有两种方式。
        (1)通过芯片的I2C总线连接外部的EEPROM,固件代码事先通过烧写器写入EEPROM中,USB设备上电运行时,通过I2C总线将EEPROM中固件代码载入。EZ-USB支持外部EEPROM通过总线来下载固件,这种方式使开发者可以从外围硬件来下载8051程序代码,但是不利于在设备开发阶段使用。
         
        (2)使用该芯片特有软配置功能,将固件程序存储在计算机中,当该设备接入USB电缆时,由于EZ-USB具有重新枚举的能力,所以在初始化枚举以后,用户只需要通过Cypress公司提供的开发软件USB Control Panel中Download项,就可以将固件载入到控制芯片中。该方法完全是软操作,不需要额外的硬件设备,方便程序的修改调试。
         
        使用USB Control Panel进行固件程序下载的界面如图10.32所示。
       

        图10.32  USB Control Panel界面

         
        单击“Download…”按钮,选择“slavefifo.hex”。下载固件成功以后显示如图10.33信息。
       

        图10.33  下载固件程序

         
        其中,通过单击“GetPipes”按钮可以查看通道信息。
         
        现在固件程序后,即可进行USB通信测试。
         
        根据不同的程序,选择相应的测试软件,测试USB接口的传输速度。如图10.34所示是Red Logic工作室提供的基于红色飓风II的USB测试软件。
       

        图10.34  USB测试软件

         
        10.7.3  USB接口通信实例结果

        实现FPGA与PC机之间的USB通信,并且在PC机的超级终端上面测试USB的读写速度,如图10.35和图10.36所示。关于EZ-USB的详细内容,可参见工程文件夹中提供的相关文档。
       

        图10.35  USB测试结果

       

        图10.36  USB测试结果

         

        10.7.4  FPGA代码的设计实现

        本程序功能是配合CY68013的Slave FIFO接口时序。它完成接收从主机下传的60KB数据,写入板上SRAM里,然后从板上SRAM中读出,再上传至主机。整个传输过程通过CY68013的Slave FIFO来交互。
         
        整个程序由一个状态机构成,包括以下状态:
         
        Parameter IDLE='H0,
                       READ_EVENT='H1,
                       POINT_TO_OUT_FIFO='H2,
                       DATA_READY='H3,
                       READ_INTERVAL='H4,
                       READ='H5,
                       READ_END='H6,
                       WRITE_EVENT='H7,
                       POINT_TO_IN_FIFO='H8,
                       WRITE_READY='H9,
                       WRITE='HA,
                       WRITE_END='HB;
         
        每个状态的作用描述如下。
        ·  IDLE:整个操作过程(包括读SLAVE FIFO和写SLAVE FIFO)的入口。对相关的寄存器进行初始化,然后转入READ_EVENT状态,开始读SLAVE FIFO操作。
         
        ·  READ_EVENT:把u_addr[1:0]置为’b00,指向输出FIFO(对应端点6),然后转入POINT_TO_OUT_FIFO状态。
         
        ·  POINT_TO_OUT_FIFO:判断u_flagc是否为高(u_flagc为高指示输出FIFO为空,即输出FIFO中有数据),如果为高,则启动读过程,把u_sloe置为低,转入DATA_READY状态,第一个16位数据出现在总线上;否则说明输出FIFO中无数据,等待。
         
        ·  DATA_READY:判断u_flagc是否为高,如果为高,把u_slrd拉低,继续读取下16位数据。同时为把上一16位数据写入SRAM做准备(主要是SRAM的三态总线),同时转入READ状态,否则转入POINT_TO_OUT_FIFO,等待下一次读取过程。
         
        ·  READ:把上一16位数据写入SRAM,同时把u_slrd拉高,当前16位数据读取结束。判断是否是60KB数据,如果不是,则转入DATA_READY状态,继续读操作;否则转入READ_END状态,读操作结束。
         
        ·  READ_END:把相关寄存器置为初始态,转入WRITE_EVENT状态,开始写操作。
         
        ·  POINT_TO_IN_FIFO:为从SRAM中读取数据作准备,转入WRITE_READY状态。
         
        ·  WRITE_READY:判断u_flagb是否为高(u_flagb为高指示输入FIFO非满),如果为高,则启动写过程,从SRAM中读取数据并送到SLAVE FIFO总线上,把u_lswr置为低,转入WRITE状态;否则说明输入FIFO已满,等待。
         
        ·  WRITE:把u_slwr置为高,当前数据写入SLAVE FIFO。判断是否是60KB数据,如果不是,则转入WRITE_READY状态,继续写操作;否则转入WRITE_END状态,写操作结束。
         
         
        ·  WRITE_END:把相关寄存器置为初始态,转入IDLE状态,开始下一个60KB的读写操作。
        状态机的源代码如下:
         
        case(STATE)
             IDLE:
                  begin
                  //添加RESET状态
                  data_wr<='h0;                // USB接口信号初始化
                  u_slwr<='b1;
                  u_slrd<='b1;
                  u_sloe<='b1;
                  u_addr0<='b1;
                  u_addr1<='b1;
                  oe<='b0;
             
                  sram_d_i<='h0;               // SRAM的控制信号初始化
                  sram_a<='h3ffff;
                  sram_re<='b1;
                  sram_wr<='b1;
                  wr_flag<='b0;
                  
                  STATE<=READ_EVENT;
                  end
             READ_EVENT:
                  begin
                  wr_flag<='b1;               // 设定读写标志
                  u_addr0<='b0;               // 指定端点FIFO
                  u_addr1<='b0;
                  STATE<=POINT_TO_OUT_FIFO;
                  end
             POINT_TO_OUT_FIFO:
                  begin
                  if(u_flagc)                 //  如果flagc高,FIFO不空,开始读数据
                       begin
                       u_sloe<='b0;          // 开始从FX2的端点FIFO读数据
                       u_slrd<='b1;
                       STATE<=DATA_READY;
                       end
                  else
                      begin               // 如果flagc为低,FIFO为空,等待FIFO有数据
                      u_sloe<='b1;      // 停止从FX2的端点FIFO读数据
                      u_slrd<='b1;
                      STATE<=POINT_TO_OUT_FIFO;
                      end
                  end
             DATA_READY:
                  begin
                  if(u_flagc)             // 如果flagc为高,继续读取下一个数据
                      begin
                      u_slrd<='b0;      
                      sram_a<=sram_a+1;  // 把上一个读取的数据写入SRAM
                      sram_d_i<=data;
                      sram_wr<='b0;
                      sram_re<='b1;
                      STATE<=READ;        // 完成数据写入后,进入读数据状态
                      end
                  else
                      begin
                      u_slrd<='b1;        // 如果FIFO空,回到等待状态
                      u_sloe<='b1;
                      STATE<=POINT_TO_OUT_FIFO;
                      end
                  end
             READ:
                  Begin              
                  u_slrd<='b1;            // 完成上一个数据的SRAM写周期
                  sram_re<='b1;
                  sram_wr<='b1;
                  
                  if(sram_a!=ADDR_FULL)   // 如果SRAM地址没有到最大值,继续读操作
                      STATE<=DATA_READY;
                  else
                      STATE<=READ_END;  // 如果SRAM地址到达最大值,结束读操作
                  end
             READ_END:
                  begin
                  u_slrd<='b1;           // 回到初始状态,准备写操作
                  u_sloe<='b1;
                  u_addr0<='b0;
                  u_addr1<='b0;
                  sram_a<='h3ffff;
                  STATE<=WRITE_EVENT;
                  end
             WRITE_EVENT:
                  begin
                  u_addr0<='b0;         // 指定写数据的端点FIFO
                  u_addr1<='b1;
                  oe<='b1;
                  wr_flag<='b0;
                  STATE<=POINT_TO_IN_FIFO;
                  end
             POINT_TO_IN_FIFO:
                  begin
                  sram_a<=sram_a+1;   // 从SRAM中读取一个数据
                  sram_re<='b0;
                  sram_wr<='b1;
                  STATE<=WRITE_READY;
                  end
             WRITE_READY:
                  begin
                  if(u_flagb)
                      begin              // 如果FIFO不满,开始写数据到FX2的FIFO
                      data_wr<=sram_d;
                      u_slwr<='b0;
                      u_slrd<='b1;
                      STATE<=WRITE;
                      end
                  else
                      begin      
                      u_slwr<='b1;        // 如果FIFO已满,等待
                      u_slrd<='b1;
                      STATE<=WRITE_READY;
                      end
                  end
             WRITE:
                  begin
                  u_slwr<='b1;            
                  u_slrd<='b1;
                  if(sram_a!=ADDR_FULL)
                      begin
                      sram_a<=sram_a+1;  // 如果SRAM地址没有达到最大值,继续从SRAM读数据
                      sram_wr<='b1;
                      sram_re<='b0;
                      STATE<=WRITE_READY;
                      end
                  else
                      begin
                      sram_a<='h3ffff; // 如果SRAM地址达到最大值,复位SRAM地址,进入写结束
                      sram_wr<='b1;
                      sram_re<='b1;
                      STATE<=WRITE_END;
                      end
                  end
             WRITE_END:
                  begin
                  wr_flag='b0;          // 结束写FX2 FIFO状态,回到初始的IDLE状态
                  sram_a<='h3ffff;
                  u_addr0<='b1;
                  u_addr1<='b1;
                  STATE<=IDLE;
                  end
             default:
                  STATE<=IDLE;
             endcase
         
        10.7.5  小结

        本节对利用USB接口芯片FX2来完成FPGA和PC机的高速数据传输做了介绍,并通过编译下载在红色飓风的开发板上实现了预定功能。
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|文字版|手机版|DIY编程器网 ( 桂ICP备14005565号-1 )

GMT+8, 2025-8-2 21:04 , 耗时 0.106144 秒, 21 个查询请求 , Gzip 开启.

各位嘉宾言论仅代表个人观点,非属DIY编程器网立场。

桂公网安备 45031202000115号

DIY编程器群(超员):41210778 DIY编程器

DIY编程器群1(满员):3044634 DIY编程器1

diy编程器群2:551025008 diy编程器群2

QQ:28000622;Email:libyoufer@sina.com

本站由桂林市临桂区技兴电子商务经营部独家赞助。旨在技术交流,请自觉遵守国家法律法规,一旦发现将做封号删号处理。

快速回复 返回顶部 返回列表