今天給大俠帶來基于FPGA的USB2.0設(shè)計(jì),附源碼,獲取源碼,請(qǐng)?jiān)凇癋PGA技術(shù)江湖”公眾號(hào)內(nèi)回復(fù)“ USB2.0設(shè)計(jì)源碼”,可獲取源碼文件。話不多說,上貨。
2019年9月4日,USB-IF終于正式公布USB 4規(guī)范。它引入了Intel此前捐獻(xiàn)給USB推廣組織的Thunderbolt雷電協(xié)議規(guī)范,雙鏈路運(yùn)行(Two-lane),傳輸帶寬因此提升,與雷電3持平,都是40Gbps。需要注意的是,你想要體驗(yàn)最高傳輸速度,就必須使用經(jīng)過認(rèn)證的全新數(shù)據(jù)線。USB4保留了良好的兼容性,可向下兼容USB 3.2/3.1/3.0、雷電3。除此之外,USB4將只有USB Type-C一種接口,并支持多種數(shù)據(jù)、顯示協(xié)議,包括DisplayPort,可以一起充分利用高速帶寬,也支持USB PD供電。
比較遺憾的是,USB4的發(fā)布時(shí)間暫未公布。值得注意的是,此次發(fā)布的USB4是規(guī)范,而并非USB4.0。在此之前,USB Implementers Forum(USB-IF)計(jì)劃取消USB 3.0/3.1命名,統(tǒng)一劃歸為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)。
以上就是關(guān)于USB標(biāo)準(zhǔn)以及命名的訊息,而今天我們要做設(shè)計(jì)的是USB2.0,USB2.0的設(shè)備是按照2.0的電源標(biāo)準(zhǔn)設(shè)計(jì)的,設(shè)備所需的電流小于500mA,而USB3.0接口可以提供更大的電流,所以用在USB3.0接口是安全的,這就是標(biāo)準(zhǔn)向下兼容的道理。反之,USB3.0的設(shè)備,是否能夠在USB2.0接口使用,就要查看設(shè)備的說明書。通常的電源都是電壓源,設(shè)備與電源的電壓必須相等,而電源的輸出電流要大于設(shè)備的電流,即電源功率要大于設(shè)備功率。
現(xiàn)在大部分USB設(shè)備(比如USB接口的鼠標(biāo)、鍵盤、閃存、U盤等等)都是采用了USB通用驅(qū)動(dòng),而你的系統(tǒng)有USB通用驅(qū)動(dòng)的話(比如XP就內(nèi)建了USB通用驅(qū)動(dòng))就能用。而有些USB設(shè)備是需要特殊驅(qū)動(dòng)的,比如某些手機(jī),連接到電腦的USB口,是需要安裝驅(qū)動(dòng)才能使用的。下面我們一起動(dòng)手做一做,了解一下如何設(shè)計(jì)。
設(shè)計(jì)原理
USB(Universal Serial Bus2.0,通用串行總線)是一種應(yīng)用在計(jì)算機(jī)領(lǐng)域的新型接口技術(shù)。USB接口具有傳輸速度更快,支持熱插拔以及連接多個(gè)設(shè)備的特點(diǎn)。目前已經(jīng)在各類外部設(shè)備中廣泛的被采用。USB接口有三種:USB1.1,USB2.0和USB3.2。理論上USB1.1的傳輸速度可以達(dá)到12Mbps,而USB2.0則可以達(dá)到速度480Mbps,并且可以向下兼容USB1.1。
本次設(shè)計(jì)我們選擇一款開發(fā)設(shè)備,一塊廉價(jià)的開發(fā)板,其中的USB芯片是Cypress的FX2LP系列中的CY7C68013A代,詳細(xì)的介紹大家可以去Cypress的官網(wǎng)查詢。下面簡述一下設(shè)計(jì)思路。
FX2的設(shè)計(jì)架構(gòu)如下圖,內(nèi)嵌480MBit/s的收發(fā)器,鎖相環(huán)PLL,串行接口引擎SIE——集成了整個(gè)USB 2.0協(xié)議的物理層。為適應(yīng)USB 2.0的480MBit/s的速率,F(xiàn)IFO端點(diǎn)可配置成2,3,4個(gè)緩沖區(qū)。配置用的是“軟配置”——USB固件可由USB總線下載,片上不需集成ROM。擁有四個(gè)FIFO接口,可工作在內(nèi)部或外部時(shí)鐘下。端點(diǎn)和FIFO接口的應(yīng)用使外部邏輯和USB總線可高速連接。
基于FX2LP的USB開發(fā),包括三部分:固件程序、驅(qū)動(dòng)、上位機(jī)軟件。 固件程序我們?cè)趉iil中寫出來,然后配置到我們的芯片中,固件的開發(fā)對(duì)于FPGA工程師來說是不用寫的,是其他工程師配置好芯片后我們直接拿來使用,其主要的配置過程如下圖。
先上電復(fù)位,然后初始化寄存器變量,然后調(diào)用配置函數(shù),打開中斷后,判斷是否接受到了配置包,如果接收到了就調(diào)用TD_POLL()函數(shù),這個(gè)是函數(shù)是不停的執(zhí)行掃描端點(diǎn)等。然后判斷芯片是否掛起,如果掛起就叫醒芯片,如果沒有就一直調(diào)用TD_POLL函數(shù),這樣就完成所需要的配置。
這里的項(xiàng)目設(shè)計(jì)要求是要把FX2配置成從FIFO的模式, 配置為單片機(jī)工作時(shí)鐘24M,端點(diǎn)2輸出,字節(jié)1024,端點(diǎn)6輸入,字節(jié)1024,信號(hào)全設(shè)置為低電平有效等。模塊驅(qū)動(dòng)時(shí)鐘配置成內(nèi)部輸出時(shí)鐘,也就是讓FX2給項(xiàng)目設(shè)計(jì)當(dāng)作時(shí)鐘源,輸出一個(gè)最大的配置時(shí)鐘48M的時(shí)鐘。FX2的數(shù)據(jù)存儲(chǔ)區(qū)叫端點(diǎn),有512、1024字節(jié)兩個(gè)存儲(chǔ)大小之分。
從FIFO說明
當(dāng)有一個(gè)與FX2芯片相連的外部邏輯只需要利用FX2做為一個(gè)USB 2.0接口而實(shí)現(xiàn)與主機(jī)的高速通訊,而它本身又能夠提供滿足Slave FIFO要求的傳輸時(shí)序,可以做為Slave FIFO主控制器時(shí),即可考慮用此傳輸方式。?
Slave FIFO傳輸?shù)氖疽鈭D如下:?
在這種方式下,F(xiàn)X2內(nèi)嵌的8051固件的功能只是配置Slave FIFO相關(guān)的寄存器以及控制FX2何時(shí)工作在Slave FIFO模式下。一旦8051固件將相關(guān)的寄存器配置完畢,且使自身工作在Slave FIFO模式下后,外部邏輯(如FPGA)即可按照Slave FIFO的傳輸時(shí)序,高速與主機(jī)進(jìn)行通訊,而在通訊過程中不需要8051固件的參與。
FX2系列的有3種封裝方式,我們我的開發(fā)板用的是56引腳的封裝方式的電路圖,其電路圖如下所示:
端口介紹
IFCLK:FX2輸出的時(shí)鐘,可做為通訊的同步時(shí)鐘。
SLCS:FIFO的片選信號(hào),外部邏輯控制,當(dāng)SLCS輸出高時(shí),不可進(jìn)行數(shù)據(jù)傳輸。
SLOE:FIFO輸出使能,外部邏輯控制,當(dāng)SLOE無效時(shí),數(shù)據(jù)線不輸出有效數(shù)據(jù)。
SLRD:FIFO讀信號(hào),外部邏輯控制,同步讀時(shí),F(xiàn)IFO指針在SLRD有效時(shí)的每個(gè)IFCLK的上升沿遞增。
SLWR:FIFO寫信號(hào),外部邏輯控制,同步寫時(shí),在SLWR有效時(shí)的每個(gè)IFCLK的上升沿時(shí)數(shù)據(jù)被寫入,F(xiàn)IFO指針遞增。
FD[15:0]:數(shù)據(jù)線。
FIFOADR[1:0]:選擇四個(gè)FIFO端點(diǎn)的地址線,外部邏輯控制。
FLAG A,B,C端點(diǎn)的空滿標(biāo)志位。
開發(fā)驅(qū)動(dòng)大家可以在網(wǎng)上找,然后根據(jù)自己系統(tǒng)裝上合適的驅(qū)動(dòng)。上位機(jī)軟件用的是官方的開發(fā)工具,只有如下的安裝包,然后安裝第一個(gè)和第二個(gè)就好了。
設(shè)計(jì)代碼
總模塊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; //端點(diǎn)2標(biāo)志信號(hào) input pi_usb_flagc; //端點(diǎn)6標(biāo)志信號(hào) inout [15:0] pio_usb_data; //輸入輸出端口 output reg po_usb_oe_n; //讀標(biāo)志信號(hào) output reg po_usb_rd_n; //寫使能 output reg po_usb_wr_n; //讀使能 output reg [1:0] po_usb_address; //端點(diǎn)地址選擇 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; //讀數(shù)據(jù),可以一直釋放數(shù)據(jù)總線的控制權(quán) 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; //地址指向端點(diǎn)2 state <= 2; end 2 : if(!pi_usb_flagb) //判斷端點(diǎn)2已經(jīng)滿 begin po_usb_rd_n <= 0; state <= 3; po_usb_oe_n <= 0; end else state <= 2; 3 : begin if(count < 512 - 1) //接收1024字節(jié)的數(shù)據(jù) 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; //端點(diǎn)2標(biāo)志信號(hào) input pi_usb_flagc; //端點(diǎn)6標(biāo)志信號(hào) inout [15:0] pio_usb_data; //輸入輸出端口 output reg po_usb_oe_n; //讀標(biāo)志信號(hào) output reg po_usb_wr_n; //寫使能 output reg po_usb_rd_n; //讀使能 output reg [1:0] po_usb_address; //端點(diǎn)地址選擇 reg [15:0] temp_data; reg [2:0] state; //在狀態(tài)的3,拿回?cái)?shù)據(jù)總線控制全,給寫入數(shù)據(jù) 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; //地址指向端點(diǎn)6 state <= 2; end 2 : if(!pi_usb_flagc) //判斷端點(diǎn)6已經(jīng)空 begin po_usb_wr_n <= 0; state <= 3; end else state <= 2; 3 : if(temp_data < 512 - 1) //發(fā)送1024字節(jié)的數(shù)據(jù) 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
延時(shí)模塊?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
上位機(jī)測試
安裝好驅(qū)動(dòng)和下載的上位機(jī)軟件,然后在下面的界面中,點(diǎn)擊”LGEEPROM”按鈕,下載我們寫好的的.IIC固件。
然后在下面的頁面中會(huì)出現(xiàn)先選擇other endpt xfers選項(xiàng)中會(huì)出現(xiàn)4個(gè)端點(diǎn),然后選擇寫入的端點(diǎn)或者讀的端點(diǎn)執(zhí)行讀寫操作。
寫的端點(diǎn)是6端點(diǎn),選擇這個(gè)端點(diǎn),寫入端點(diǎn)是1024個(gè)字節(jié),這里設(shè)置的是512字節(jié),也就是寫入2次就可以寫滿了,如下圖,和我們編寫的代碼中寫入數(shù)據(jù)值是一樣的。
讀操作也就是要讀端點(diǎn)2,我們先要給端點(diǎn)一個(gè)數(shù),然后才能讀我們的端點(diǎn),我們寫入圖中顯示的數(shù),因?yàn)槲覀冊(cè)O(shè)計(jì)的是讀出的數(shù),如果第三個(gè)數(shù)位33ff ,就讓我們的燈亮,值得一說的是,我們上位機(jī)顯示的時(shí)候是把低位顯示到了前面,高位顯示到了后面,我們一個(gè)包是1024字節(jié),后面的數(shù)自動(dòng)補(bǔ)零,讀出數(shù)據(jù)后可以看到我們的led燈亮,驗(yàn)證出我們的設(shè)計(jì)正確。
以上就是我們的基于FPGA的usb2.0設(shè)計(jì)了,希望能給各位大俠起到參考學(xué)習(xí)作用,此次設(shè)計(jì)到此結(jié)束,有緣再見,告辭。
審核編輯:黃飛
?
評(píng)論
查看更多