你也許會有疑問,明明有這么多通信方式和數據傳輸(SPI、I2C、UART、以太網)為什么偏偏使用USB呢?
原因有很多,如下:
1. 高速數據傳輸能力
高帶寬 :USB接口提供了較高的數據傳輸速率,尤其是隨著USB版本的升級(如USB 3.0及更高版本),其理論速度可達5 Gbps甚至更高。這對于需要高速數據傳輸的應用(如視頻處理、實時數據采集等)尤為重要。
低延遲 :相比一些其他接口(如UART),USB的延遲更低,能夠滿足實時性要求較高的場景。
2. 通用性和兼容性
廣泛的硬件支持 :幾乎所有現代計算機和嵌入式系統都配備了USB接口,這意味著使用USB進行通信可以輕松實現跨平臺支持,無需額外的硬件適配。
標準化接口 :USB是一種標準化的接口,遵循統一的協議和規范。這不僅簡化了開發過程,還確保了不同設備之間的互操作性。
3. 開發便利性
豐富的工具支持 :大多數FPGA開發工具(如Xilinx Vivado、Altera Quartus等)都提供了對USB接口的支持,簡化了設計和驗證過程。
成熟的驅動和庫資源 :大量的現成驅動程序和庫資源可以輕松集成到項目中,減少了軟件開發的工作量。
4. 靈活的通信模式
全雙工通信 :USB支持全雙工通信模式,允許同時進行數據的上傳和下載,提高了通信效率。
多種數據傳輸類型 :USB支持控制傳輸、批量傳輸、中斷傳輸和同步傳輸等多種數據傳輸類型,能夠適應不同應用場景的需求。
成本效益
低成本解決方案 :相比于一些高端接口(如PCIe),USB的成本較低,適合預算有限的項目。
減少外部組件需求 :由于USB的標準化和廣泛支持,可以減少對外部組件的需求,從而降低整體硬件成本。
也正是因為如此,usb廣泛應用于數據的采集和處理、視頻和音頻傳輸、嵌入式系統開發等。
而我們今天即將要學習的,就是FPGA的USB傳輸,以FX2芯片為例
FX2
USB是一種通用的數據傳輸協議和接口標準,定義了設備與主機(如電腦)之間的通信規則(如協議、電氣特性、數據傳輸模式等);FX系列芯片(FX2, FX3)是Cypress(現英飛凌)推出的USB控制芯片,用于實現高速USB設備的功能。說的再簡單,直白一點:USB是協議標準,FX芯片是實現這一標準的硬件載體
FX芯片可以
自動處理USB復雜協議,無需開發者手動實現,
支持高速傳輸(FX2:支持USB2.0高速傳輸, 480Mbps; FX3則為 5Gbps)
提供靈活的接口(GPIF,Slave FIFO)方便直接連接外設,
內置微控制器,可以通過固件配置USB功能
FX2控制器內部結構圖如下
FX2可以通過兩種方式到FPGA,一個是(通用可編程接口)GPIF模式和從設備FIFO模式
GPIF:FX2是總線的主控者,用戶自定義時序,靈活但開發復雜
Slave FIFO: FX2是被動的FIFO從設備,外部主控直接控制,簡單但靈活性受限

在實際項目中,Slave FIFO模式更常用(尤其是FPGA做為主控的場景),而GPIF模式需要更精確控制總線的特殊需求
回環測試
介紹
我們此處就以簡單的回環測試為例,實現FPGA的Usb數據傳輸。

所謂回環測試,就是說由 PC 發送數據到 FX2 芯片的 OUT 端點 2,然后再由主機將端點 2 中的數據讀出,拷貝到IN 端點 6。使用 FPGA 設計 SlaveFIFO 讀取和寫入接口邏輯,將端點 2 中的數據讀出,然后寫入端點 6 中,再由電腦上位機從端點 6 中將數據讀回,從而實現數據的回環。
代碼
module FiFo #(
Depth = 512,
Width = 16
)
(
input fifo_clk,
input rst_n,
input write_busy,
input read_busy,
input fifo_flush,
input [Width-1:0]din,
output reg fifo_full,
output reg fifo_empty,
output reg [Width-1:0] dout
);
localparam ADDR_Width =$clog2(Depth);
//計數多加一位,防止溢出
reg [ADDR_Width:0] write_occupancy;
reg [ADDR_Width:0] read_occupancy;
wire [ADDR_Width:0] next_write_occupancy;
wire [ADDR_Width:0] next_read_occupancy;
//fifo 地址索引
wire [ADDR_Width-1:0] next_write_ptr;
reg [ADDR_Width-1:0] write_ptr;
wire [ADDR_Width-1:0] next_read_ptr;
reg [ADDR_Width-1:0] read_ptr;
reg [Width-1:0] data_array[Depth-1:0];
wire write_enable;
wire read_enable;
// 寫使能和讀使能邏輯
assign write_enable = !write_busy && !fifo_full;
assign read_enable = !read_busy && !fifo_empty;
// 下一個指針和計數器計算
assign next_write_ptr = (write_enable) ? (write_ptr + 1) : write_ptr;
assign next_read_ptr = (read_enable) ? (read_ptr + 1) : read_ptr;
assign next_write_occupancy = fifo_flush ? 10'd0 : (write_enable ? (write_occupancy + 1) : write_occupancy);
assign next_read_occupancy = fifo_flush ? 10'd0 : (read_enable ? (read_occupancy + 1) : read_occupancy);
// 滿/空狀態判斷(基于下一個計數器值)
wire [ADDR_Width:0] next_occupancy_diff = next_write_occupancy - next_read_occupancy;
wire next_fifo_full = (next_occupancy_diff >= Depth);
wire next_fifo_empty = (next_occupancy_diff == 0);
//更新指針
always @(posedge fifo_clk or negedge rst_n)begin
if(!rst_n)begin
write_ptr<=0;
read_ptr<=0;
end else if(fifo_flush)begin
write_ptr<=0;
read_ptr<=0;
end else begin
write_ptr<=next_write_ptr;
read_ptr<=next_read_ptr;
end//else
end//always
// 更行空/滿信號
always @(posedge fifo_clk or negedge rst_n)begin
if(!rst_n)begin
fifo_full<=0;
fifo_empty<=1;
end else if (fifo_flush)begin
fifo_full<=0;
fifo_empty<=1;
end else begin
fifo_full<=next_fifo_full;
fifo_empty<=next_fifo_empty;
end
end//always
// 讀/寫計數
always @(posedge fifo_clk or negedge rst_n)begin
if(!rst_n)begin
write_occupancy<=0;
read_occupancy<=0;
end else if(fifo_flush)begin
write_occupancy<=0;
read_occupancy<=0;
end else begin
write_occupancy<=next_write_occupancy;
read_occupancy<=next_read_occupancy;
end//else
end//always
//輸出數據
always @(posedge fifo_clk or negedge rst_n)begin
if(!rst_n)dout<=0;
else if(fifo_flush) dout<=0;
else dout<=data_array[read_ptr];
end//always
//數據寫入存儲陣列
always @(posedge fifo_clk)begin
if(write_enable)
data_array[write_ptr]<=din;?
end
// 溢出警告
always @(posedge fifo_clk) begin
if (fifo_full && write_busy) begin
$display("ERROR: %m: Fifo overflow at time %t", $time);
$finish;
end
end // always
// 下溢警告
always @(posedge fifo_clk) begin
if (fifo_empty && read_busy) begin
$display("ERROR: %m: Fifo underflow at time %t", $time);
$finish;
end
end // always
// synthesis translate_on
endmodule
FX2_SF
module FX2_SF(
input clk,
input reset_n,
inout [15:0] fx2_fdata, // 雙向數據總線
output [1:0] fx2_faddr, // FIFO地址選擇
output fx2_slrd, // 讀使能(低有效)
output fx2_slwr, // 寫使能(低有效)
output fx2_sloe, // 輸出使能(低有效)
input ep6_full_flag, // EP6滿標志(可寫)
input ep2_empty_flag, // EP2空標志(可讀)
input fx2_ifclk, // 接口時鐘(60MHz)
output fx2_pkt_end, // 包結束脈沖
output fx2_clear, // 復位信號
output fx2_slcs // 片選(常低)
);
//------------------------ 參數優化 ------------------------//
localparam [1:0]
LOOPBACK_IDLE = 2'd0,
LOOPBACK_READ = 2'd1,
LOOPBACK_WAIT_ep6_full = 2'd2,
LOOPBACK_WRITE = 2'd3;
localparam [1:0]
FIFO_ADDR_READ = 2'b00, // EP2
FIFO_ADDR_WRITE = 2'b10; // EP6
//------------------------ 信號聲明 ------------------------//
reg [1:0] current_state, next_state;
// FIFO控制信號
wire fifo_wr_en;
wire fifo_rd_en;
reg [15:0] fifo_din;
wire [15:0] fifo_dout;
// FX2接口信號
reg slrd_n;
reg slwr_n;
reg sloe_n;
reg [1:0] faddr_n;
reg pkt_end_n;
//------------------------ 接口分配 ------------------------//
assign fx2_slwr = slwr_n;
assign fx2_slrd = slrd_n;
assign fx2_sloe = sloe_n;
assign fx2_faddr = faddr_n;
assign fx2_pkt_end= pkt_end_n;
assign fx2_slcs = 1'b0; // 常使能
assign fx2_clear = 1'b0; // 未使用
// 三態總線控制
assign fx2_fdata = (slwr_n == 1'b0) ? fifo_dout : 16'hzzzz;
//------------------------ 狀態機 ------------------------//
always @(posedge fx2_ifclk or negedge reset_n) begin
if(!reset_n) current_state <= LOOPBACK_IDLE;
else current_state <= next_state;
end
always @(*) begin
next_state = current_state;
case(current_state)
LOOPBACK_IDLE: //ep2為空, 上位機可傳輸數據
if(ep2_empty_flag) next_state = LOOPBACK_READ;
LOOPBACK_READ:
if(!ep2_empty_flag) next_state = LOOPBACK_WAIT_ep6_full;
LOOPBACK_WAIT_ep6_full:
if(ep6_full_flag) next_state = LOOPBACK_WRITE;
LOOPBACK_WRITE: begin
if(!ep6_full_flag || fifo_empty)
next_state = LOOPBACK_IDLE;
end
default: next_state = LOOPBACK_IDLE;
endcase
end
//------------------------ 控制信號生成 ------------------------//
always @(*) begin
// 默認值
slrd_n = 1'b1;
sloe_n = 1'b1;
slwr_n = 1'b1;
faddr_n = FIFO_ADDR_READ;
pkt_end_n = 1'b1;
case(current_state)
LOOPBACK_READ: begin
faddr_n = FIFO_ADDR_READ;
slrd_n = !ep2_empty_flag; // 有數據時持續讀取
sloe_n = !ep2_empty_flag;
end
LOOPBACK_WRITE: begin
faddr_n = FIFO_ADDR_WRITE;
slwr_n = !(ep6_full_flag && !fifo_empty);
// 在最后一次寫入后生成包結束脈沖
pkt_end_n = (slwr_n == 1'b0) ? 1'b0 : 1'b1;
end
endcase
end
//------------------------ FIFO接口 ------------------------//
assign fifo_wr_en = (current_state == LOOPBACK_READ) && !slrd_n;
assign fifo_rd_en = (current_state == LOOPBACK_WRITE) && !slwr_n;
// 數據輸入寄存器
always @(posedge fx2_ifclk) begin
if(fifo_wr_en)
fifo_din <= fx2_fdata;
end
FiFo #(
.Depth(512),
.Width(16)
) u_fifo (
.fifo_clk (fx2_ifclk),
.rst_n (reset_n),
.write_busy (1'b0), // 外部無寫阻塞
.read_busy (1'b0), // 外部無讀阻塞
.fifo_flush (1'b0), // 禁用自動flush
.din (fifo_din),
.fifo_full (fifo_full),
.fifo_empty (fifo_empty),
.dout (fifo_dout)
);
wire clk_96m;//生成96M時鐘用于ILA采樣
pll pll_inst(
.clk_out1(clk_96m),
.clk_in1(clk)
);
//------------------------ 調試模塊注釋 ------------------------//
ila_0 ila_0_inst(
.clk(clk_96m), // input wire clk
.probe0(fx2_fdata), // input wire [15:0] probe0
.probe1(fx2_faddr), // input wire [1:0] probe1
.probe2(ep2_empty_flag), // input wire [0:0] probe2
.probe3(ep6_full_flag), // input wire [0:0] probe3
.probe4(fx2_sloe), // input wire [0:0] probe4
.probe5(fx2_slwr), // input wire [0:0] probe5
.probe6(fx2_slrd), // input wire [0:0] probe6
.probe7(fifo_empty), // input wire [0:0] probe7
.probe8(fifo_full), // input wire [0:0] probe8
.probe9(fifo_flush) // input wire [0:0] probe9
);
endmodule
-
FPGA
+關注
關注
1660文章
22408瀏覽量
636217 -
usb
+關注
關注
60文章
8438瀏覽量
284438 -
數據傳輸
+關注
關注
9文章
2201瀏覽量
67579
原文標題:FPGA之Usb數據傳輸
文章出處:【微信號:gh_9d70b445f494,微信公眾號:FPGA設計論壇】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
基于FPGA和USB數據傳輸電路的設計
基于FPGA的高速LVDS數據傳輸
求助 ,關于STM32的USB數據傳輸問題
基于FPGA+USB3.0接口的高速數據傳輸系統設計
FPGA spartan 3系列,數據傳輸接口有可以匹配的藍牙模塊么?
如何使用FPGA器件和USB通訊實現高速數據傳輸顯示系統的設計
基于USB接口的無線數據傳輸系統設計
基于FPGA和USB的高速數據傳輸、記錄及顯示系統
基于DSP的USB數據傳輸系統設計
基于USB2.0的紅外數據傳輸系統的設計與實現
USB2.0+FPGA實現多路數據傳輸系統
如何使用FPGA器件和USB通訊實現高速數據傳輸顯示系統的設計
基于FPGA的USB數據傳輸
評論