(轉)USB小白學習之路(8)FX2LP cy7c68013——Slave FIFO 與FPGA通信
此博客轉自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通信