1. 程式人生 > >(轉)USB小白學習之路(8)FX2LP cy7c68013——Slave FIFO 與FPGA通信

(轉)USB小白學習之路(8)FX2LP cy7c68013——Slave FIFO 與FPGA通信

讀取 批量傳輸 clock 數據接收 select 緩沖 targe operation 暫停

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

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。這兩個模式分別為通用可編程接口( GPIF)模式和從設備 FIFO模式。

2.1 硬件連接

技術分享圖片

引腳名稱說明
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固件
技術分享圖片
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;            // FLAGA - 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;            // FLAGA - 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(如果采用中斷,那就修改中斷函數)兩個函數即可,大大縮短了開發時間。

(轉)USB小白學習之路(8)FX2LP cy7c68013——Slave FIFO 與FPGA通信