zoukankan      html  css  js  c++  java
  • USB小白学习之路(8)FX2LP cy7c68013A——Slave FIFO 与FPGA通信(转)

    此博客转自CSDN:http://blog.csdn.net/xx116213/article/details/50535682

    这个博客只对自己理解CY7C68013的配置有一定的帮助,对于配置CY7C68013,使其与FPGA通信,还是官方给的文档AN61345以及附件代码更详细直观。

    1 USB 概述

    USB名称解释 
    USB是通用串行总线(Universal Serial Bus)的缩写。能过在计算机运行过程中随意地接入,并且立刻就能投入工作,那么这样的特性叫做即插即用PnP(Plug and Play)。由于USB是主从模式的结构,设备与设备之间、主机与主机之间不能互连。为了解决这个问题,出现了USB OTG(On the go),它的做法:同一个设备,在不同场合下可以在主机与从机之间切换。

    USB系统组成 
    usb系统的三个组成:Host、HUB和Device。

    • Host:主控器,能读写usb设备的设备。例如插有U盘的电脑,那么PC就是主控器。
    • HUB:扩充USB接口。
    • Device(USB Device):如硬盘、打印机、U盘等。

    USB设备组成 
    每一个USB设备由一个或多个配置来控制其行为,使用多配置原因是对操作系统的支持;一个配置是由接口(Interface)组成;接口则是由管道(Pipe)组成;管道是和USB设备的端点(Endpoint)对应,端点都是输入输出成对的。在固件编程中,USB设备、配置、接口和管道都来描述符来报告其属性。

    一个端点(Endpoint)建立一个管道。管道的端点总是成对出现,即In Endpoint和Out Endpoint。端点0默认为控制管道,其它端点可以配置成数据管道。一个具体的端点,只能工作在一种传输模式下。

    • In Endpoint:由device向Host发送数据的端点。
    • Out Endpoint:由Host向device发送数据的端点。

    USB传输速度 
    USB1.0和USB1.1版本中,只支持1.5Mb/s的低速(low-speed)模式和12Mb/s的全速模式。在USB2.0种,又加入了速度更快(480Mb/s)的高速模式。而USB3.0的最大传输带宽高达5.0Gbps(625MB/s)。

    USB可扩展设备 
    USB1.1规定最多为4层,USB2.0规定最多为6层。理论上,一个USB主控制器最多可接127个设备,这是因为协议规定每个USB设备具有一个7 bit的地址(取值范围0~127),而地址0是保留给未初始化的设备使用。

    USB传输类型 
    虽然USB定义了数据在总线上传输的基本单位是包,但是我们还不能随意地使用包来传输数据,必须按照一定的关系把这些不同的包组织成事务才能传输数据。

    事务通常由两个或者三个包组成:令牌包,数据包和握手包。

    • 令牌包用来启动一个事务,总是由主机发送。
    • 数据包传送数据,可以从主机到设备,也可以从设备到主机,方向由令牌包来制定。
    • 握手包的发送者通常为数据接收者,当数据接收正确后,发送握手包。设备也可以使用NAK握手包来表示数据还未准备好。

    USB协议规定了4种传输类型:批量传输、等时传输(同步传输),中断传输和控制传输。其中,批量传输、等时传输、中断传输每传输一次数据都是一个事务;控制传输包括三个过程,建立过程和状态过程分别是一个事务,数据过程则可能包含多个事务。4种数据传输的相关特性(仅限USB1.1协议)如下表。

    传输模式中断传输Interrupt批量传输Bulk等时传输ISO控制传输Control
    传输速率/Mbps 12(1.5,低速) 12 12 1.5/12
    数据的最大长度/Byte 1~64(1~8,低速) 8/16/32/64 1~1023 1~64(1~8,低速)
    数据周期性 没有 没有
    发送错误重传
    应用设备 鼠标键盘 打印机 语音  
    可得到的最大宽度/Mbps 6.762(0.051低速) 9.728 10.240  

    批量传输使用批量事务传输数据。一个批量事务由三个阶段:令牌包阶段,数据包阶段和握手包阶段。每个阶段都是一个独立的包。批量传输通常用于数据量大,对数据的实时性要求不高的场合。

    USB2.0 数据帧 
    USB2.0和USB1.1规范的最大不同就是数据帧。在USB1.1规范中,USB数据采用每毫秒一个数据帧的方式进行数据传输,在毫秒数据帧的开始,USB主机首先产生帧开始(SOF)数据包,并传输当前数据帧号,后面是传输数据。对于USB2.0规范,为了支持480Mbps高速传输速度,USB2.0提出了微帧的概念,每毫秒数据帧又包含8个微帧。

    USB2.0 端点缓冲区

    传输类型USB1.1数据包大小USB2.0数据包大小
    控制传输 8,16,32,64 64
    批量传输 8,16,32,64 512
    中断传输 1~64 1024
    等时传输 1023 1024

    2 CY7C68013与FPGA

    官方资料AN61345 提供了一个示例项目,用以通过从设备 FIFO 接口将 FX2LP 连接至 FPGA。示例实现中描述的接口为各个应用执行高速度的 USB 连接事项,如数据采集、工业控制和监控以及图像处理。 

    FX2LP-FPGA系统

    可以通过两个不同的模式将 FX2LP 连接至 FPGA。这两个模式分别为通用可编程接口( GPIF)模式和从设备 FIFO模式。

    2.1 硬件连接

    FX2LP-FPGA硬件连接

    引脚名称说明
    SLRD SLRD 引脚应由主设备激活,用以从 FIFO 读取数据。
    SLWR SLWR 引脚应该由主设备激活,以将数据写入到 FIFO 内。
    SLOE 是指 FIFO 输出驱动器的使能信号。
    FIFOADR[1:0] 这些信号用于选择有效的端点。
    FD[15:0] 16 位数据总线
    FLAGA/FLAGB/FLAGC/FLAGD FIFO 使用这些标志来表示各种状态(满、空、可编程)。
    IFCLK 是指与从设备 FIFO 接口同步的时钟。在本应用笔记所提供的设计中,该时钟的频率被配置为 48 MHz,并由连接至 FX2LP 的 FPGA 生成。
    CLKOUT FX2LP 的 CLKOUT 引脚可以提供的时钟频率分别为 12、 24 或 48 MHz

    2.2 固件的实现

    利用Cypress Suite USB提供的资源,在此基础上修改例程。 

    FX2LP固件 
    从设备 FIFO 接口的 FX2LP 固件 

    Fw.c 文件包含 main 函数。它执行了 USB 维持的大部分操作(如进行枚举),并且每当需要自定义时,它将调用应用代码( Slave.c)中特定名称的外部函数。一般情况下,不需要修改 Fw.c 文件。执行各个日常操作的步骤后,该函数将调用 Slave.c 所提供的外部函数,即 TD_init。(前缀TD 表示“任务调度” 。然后,它进入一个无限循环,以通过 CONTROL 端点 0 检查 SETUP 数据包的到来。该循环还会检查 USB 暂停事件,但从设备 FIFO 应用不会使用该循环。每次进入该循环时,该函数都将调用 Slave.c 文件中提供的外部函数 TD_Poll。 TD_Poll 函数用于同步化 FPGA 和 FX2LP 间所传输的数据。开始传输数据时,由于 FIFO 被配置为自动模式,因此该函数不会进行任何操作。

    每个 USB 外设通过它们的 CONTROL 端点接收两个请求类型:枚举和操作。 
    枚举 
    当 与 USB 器 件 连 接 时 , 主 机 PC 将 发 送 多 个GET_DESCRIPTOR 请求以确定器件类型及其要求。这些操作属于枚举过程的一部分。 fw.c 代码截取这些请求,并通过使用 dscr.a51 文件中所存储的数值处理请求。 
    操作 
    需要用户代码时, fw.c 将调用一个带有特定名称前缀为 DR(器件请求)的外部函数(存储在 Slave.c 文件中)。对于从设备 FIFO 这种简单的应用,只会使用一个配置和一个接口。因此, 图 14 中所显示的两对 DR_Set-Get 函数只存储由主机发送的“ Set” 值,并在主机发出“ Get” 请求时对该值进行随路。对于更加复杂的配置,您可以使用这些 DR调用( “ hooks” )更改摄像机的分辨率或将请求路由到两个不同的接口等。 

    固件代码

     1 #pragma NOIV                    // Do not generate interrupt vectors
     2 #include "fx2.h"
     3 #include "fx2regs.h"
     4 #include "fx2sdly.h"            // SYNCDELAY macro
     5 
     6 extern BOOL GotSUD;             // Received setup data flag
     7 extern BOOL Sleep;
     8 extern BOOL Rwuen;
     9 extern BOOL Selfpwr;
    10 
    11 BYTE Configuration;             // Current configuration
    12 BYTE AlternateSetting;          // Alternate settings
    13 
    14 //-----------------------------------------------------------------------------
    15 // Task Dispatcher hooks
    16 //   The following hooks are called by the task dispatcher.
    17 //-----------------------------------------------------------------------------
    18 void TD_Init( void )
    19 { // Called once at startup
    20 
    21   CPUCS = 0x10; // CLKSPD[1:0]=10, for 48MHz operation, output CLKOUT
    22 
    23   PINFLAGSAB = 0x08;            // FLAGA - EP2EF
    24   SYNCDELAY;
    25   PINFLAGSCD = 0x60;            // FLAGD - EP6PF
    26   SYNCDELAY;
    27   PORTACFG |= 0x80;
    28   SYNCDELAY;
    29   IFCONFIG = 0xE3;             // for async? for sync?
    30   SYNCDELAY;
    31   CPUCS |= 0x02;
    32 
    33   // EP4 and EP8 are not used in this implementation...
    34   EP2CFG = 0xA0;                //out 512 bytes, 4x, bulk
    35   SYNCDELAY;                    
    36   EP6CFG = 0xE0;                // in 512 bytes, 4x, bulk
    37   SYNCDELAY;              
    38   EP4CFG = 0x02;                //clear valid bit
    39   SYNCDELAY;                     
    40   EP8CFG = 0x02;                //clear valid bit
    41   SYNCDELAY;   
    42 
    43   SYNCDELAY;
    44   FIFORESET = 0x80;             // activate NAK-ALL to avoid race conditions
    45   SYNCDELAY;                    // see TRM section 15.14
    46   FIFORESET = 0x02;             // reset, FIFO 2
    47   SYNCDELAY;                    // 
    48   FIFORESET = 0x04;             // reset, FIFO 4
    49   SYNCDELAY;                    // 
    50   FIFORESET = 0x06;             // reset, FIFO 6
    51   SYNCDELAY;                    // 
    52   FIFORESET = 0x08;             // reset, FIFO 8
    53   SYNCDELAY;                    // 
    54   FIFORESET = 0x00;             // deactivate NAK-ALL
    55 
    56   // handle the case where we were already in AUTO mode...
    57   // ...for example: back to back firmware downloads...
    58   SYNCDELAY;                    // 
    59   EP2FIFOCFG = 0x00;            // AUTOOUT=0, WORDWIDE=0
    60 
    61   // core needs to see AUTOOUT=0 to AUTOOUT=1 switch to arm endp's
    62   SYNCDELAY;                    // 
    63   EP2FIFOCFG = 0x11;            // AUTOOUT=1, WORDWIDE
    64   SYNCDELAY;                    // 
    65   EP6FIFOCFG = 0x0D;            // AUTOIN=1, ZEROLENIN=1, WORDWIDE=1
    66   SYNCDELAY;
    67 }
    68 
    69 void TD_Poll( void )
    70 { // Called repeatedly while the device is idle
    71 
    72   // ...nothing to do... slave fifo's are in AUTO mode...
    73 
    74 }

    TD_Init 
    该函数执行以下操作:

    • 将 8051 时钟频率设置为 48 MHz。
    1   CPUCS = 0x10;
    2   ……
    3   CPUCS |= 0x02;
    • 配置 FIFO 标志输出。 FLAGA 被配置为 EP2 OUTFIFO 的空标志, FLAGD 被配置为 EP6 IN FIFO可编程标志(官方的例程:配置为EP6 IN FIFO 的满标志)。
    1   PINFLAGSAB = 0x08;            // FLAGA - EP2EF
    2   SYNCDELAY;
    3   PINFLAGSCD = 0x60;            // FLAGD - EP6PF
    4   SYNCDELAY;
    • 对从设备 FIFO 接口进行配置,使之使用 48 MHz 大小的内部时钟。
    1 IFCONFIG = 0xE3;
    • 将 EP2 配置为 BULK-OUT 端点,并将 EP6 配置为BULK-IN 端点。该两个端点均为四倍缓冲,并使用512 字节的 FIFO。由于本设计中没有使用 EP4 和 EP8,所以它们均被取消激活。
    1   EP2CFG = 0xA0;                //out 512 bytes, 4x, bulk
    2   SYNCDELAY;                    
    3   EP6CFG = 0xE0;                // in 512 bytes, 4x, bulk
    4   SYNCDELAY;              
    5   EP4CFG = 0x02;                //clear valid bit
    6   SYNCDELAY;                     
    7   EP8CFG = 0x02;                //clear valid bit
    8   SYNCDELAY;
    • 复位 FIFO。
     1   FIFORESET = 0x80;             // activate NAK-ALL to avoid race conditions
     2   SYNCDELAY;                    // see TRM section 15.14
     3   FIFORESET = 0x02;             // reset, FIFO 2
     4   SYNCDELAY;                    // 
     5   FIFORESET = 0x04;             // reset, FIFO 4
     6   SYNCDELAY;                    // 
     7   FIFORESET = 0x06;             // reset, FIFO 6
     8   SYNCDELAY;                    // 
     9   FIFORESET = 0x08;             // reset, FIFO 8
    10   SYNCDELAY;                    // 
    11   FIFORESET = 0x00;             // deactivate NAK-ALL
    12   SYNCDELAY; 
    • 分别将端点 2 FIFO 和端点 6 配置为自动输出模式和自动输入模式,同时使用 16 位接口。
    1   EP2FIFOCFG = 0x00;            // AUTOOUT=0, WORDWIDE=0
    2   // core needs to see AUTOOUT=0 to AUTOOUT=1 switch to arm endp's
    3   SYNCDELAY;                    // 
    4   EP2FIFOCFG = 0x11;            // AUTOOUT=1, WORDWIDE=1
    5   SYNCDELAY;                    // 
    6   EP6FIFOCFG = 0x0D;            // AUTOIN=1, ZEROLENIN=1, WORDWIDE=1
    7   SYNCDELAY;

    TD_Poll 
    在 fw.c 文件的无限循环中调用了 TD_Poll。因为EP2和EP6配置为自动输出和输入模式,所以不必要添加代码进行手动操作。

    2.3 FPGA代码

      1 library IEEE;
      2 use IEEE.STD_LOGIC_1164.ALL;      
      3 use IEEE.STD_LOGIC_ARITH.ALL;     
      4 use IEEE.STD_LOGIC_UNSIGNED.ALL;
      5 
      6 entity fpga_master is
      7   Port (  
      8     fdata : inout  STD_LOGIC_VECTOR(15 downto 0);  --  FIFO data lines.
      9     faddr     : out STD_LOGIC_VECTOR(1 downto 0); --  FIFO select lines
     10     slrd      : out STD_LOGIC;                    -- Read control line
     11     slwr      : out STD_LOGIC;                    -- Write control line
     12     gstate    : out STD_LOGIC_VECTOR(3 downto 0); -- debug lines
     13 
     14 
     15     flagd     : in  STD_LOGIC;                    --EP6 full flag
     16     flaga     : in  STD_LOGIC;                    --EP2 empty flag
     17     clk       : in  STD_LOGIC;                    --Interface Clock
     18     sloe      : out STD_LOGIC                     --Slave Output Enable control 
     19   );
     20 end fpga_master;
     21 
     22 architecture rtl of fpga_master is
     23 
     24 signal faddr_i    : STD_LOGIC_VECTOR(1 downto 0);  
     25 
     26 signal slrd_i     : STD_LOGIC;
     27 signal slwr_i     : STD_LOGIC;
     28 
     29 signal gstate_i : STD_LOGIC_VECTOR(3 downto 0);
     30 
     31 signal MasterState : STD_LOGIC_VECTOR(3 downto 0);   -- Counter to sequence the fifo signals.
     32 
     33 signal sloe_i : STD_LOGIC;
     34 
     35 shared variable cnt : integer range 0 to 9 := 0 ;
     36 
     37 CONSTANT A: STD_LOGIC_VECTOR (3 DownTo 0) := "0000";
     38 CONSTANT B: STD_LOGIC_VECTOR (3 DownTo 0) := "0001";
     39 CONSTANT C: STD_LOGIC_VECTOR (3 DownTo 0) := "0010";
     40 CONSTANT D: STD_LOGIC_VECTOR (3 DownTo 0) := "0011";
     41 CONSTANT E: STD_LOGIC_VECTOR (3 DownTo 0) := "0100";
     42 CONSTANT F: STD_LOGIC_VECTOR (3 DownTo 0) := "0101";
     43 CONSTANT G: STD_LOGIC_VECTOR (3 DownTo 0) := "0110";
     44 CONSTANT H: STD_LOGIC_VECTOR (3 DownTo 0) := "0111";  
     45 begin
     46 
     47     slrd    <= slrd_i;
     48     slwr    <= slwr_i;
     49     faddr <= faddr_i;
     50     gstate<= gstate_i;
     51     sloe    <= sloe_i;
     52 
     53 
     54 process(clk)
     55 
     56 variable fdatawe : natural := 0;
     57 variable fifodatabyte : STD_LOGIC_VECTOR(15 downto 0) := "0000000000000000";  -- Local for now.
     58 
     59 begin
     60     if(rising_edge(clk)) then
     61 
     62         case MasterState(3 downto 0) is
     63 
     64             when A =>  -- IDLE STATE   
     65 
     66                 sloe_i <= '1';                         
     67                 faddr_i <= "10";        
     68                 slrd_i  <= '1';
     69                 slwr_i  <= '1';
     70                 MasterState <= E;
     71                 fdatawe := 0;
     72                 gstate_i <= "0001";
     73 
     74             when E =>   
     75 
     76                 faddr_i <= "10";
     77                 slrd_i  <= '1';
     78                 sloe_i <= '1';
     79                 if (flagd = '1')   then                 -- if Full flag is in a deasserted state 
     80                     slwr_i  <= '0';                         --assert slave write control signal
     81                     fdatawe := 0 ;
     82                     fdata <= fifodatabyte;  
     83                     fifodatabyte := fifodatabyte + '1';   
     84                     MasterState <= E;                       -- stay in state E 
     85                 else
     86                     slwr_i  <= '1'; 
     87                     MasterState <= A;                         --when Full flag gets asserted, move to state A 
     88 
     89                 end if;
     90 
     91                 gstate_i <= "0110";  
     92 
     93             when others =>--if an undefined state move to IDLE
     94 
     95                 faddr_i <= "00";
     96 
     97                 slrd_i  <= '1';                         
     98                 sloe_i <= '1';
     99                 slwr_i  <= '1';
    100 
    101                 gstate_i <= "1000";  
    102                 MasterState <= A;
    103         end case;
    104     end if;
    105 end process;
    106 end rtl;

    3 总结

    CYPRESS提供了FX2LP的固件框架,使得固件开发只需修改TD_Init和TD_Poll(如果采用中断,那就修改中断函数)两个函数即可,大大缩短了开发时间。

    真正不羁的灵魂不会真的去计较什么,因为他们的内心深处有着国王般的骄傲。
  • 相关阅读:
    JQuery 学习总结及实例 !! (转载)
    JavaScript 学习笔记
    个人对JS的一些见解
    本博客欢迎交流,文章自由转载,保持署名!
    VSCode:源码编译运行,分析,踩坑
    ant design pro/前端/JS:实现本地运行https
    前端/JS/React/ES6:纯前端实现图片压缩技术
    云服务名词:软件即服务SaaS,怎么这个理解起来这么别扭
    React:effect应该怎么翻译比较合适??
    我给博客加了一个娃娃,一片雪花
  • 原文地址:https://www.cnblogs.com/kybyano/p/8111296.html
Copyright © 2011-2022 走看看