背景信息
icestick 板載 USB 接口芯片 FT2232H 的端口 A 和端口 B 均與 FPGA ice40hx1k 相連。其中,端口 A 處于 MPSSE 模式,用于讀寫 SPI Flash 以更新 FPGA 的 bitfile,而 B 口默認處于 ASYNC Serial 模式,當作串口使用。
端口 B 都只有一部分引腳連到 FPGA,無法支持 245 FIFO 或者 245 FIFO SYNC 模式以實現(xiàn)高速數(shù)據(jù)傳輸。而在 ASYNC Serial 模式時,其支持最大 12Mbaud 即最高 1.14MBps 的數(shù)據(jù)傳輸。
筆者發(fā)現(xiàn) FT2232H 還支持一種稱為 Fast Opto-Isolated Serial Interface 的模式。在 FTDI 文檔和軟件中,這一模式也被稱為 Fast Serial Interface 模式或者 OPTO Isolate 模式。因為引入了時鐘引腳,這一模式可以在使用較少引腳的情況實現(xiàn)比 ASYNC Serial 模式更高帶寬的數(shù)據(jù)傳輸。
讀者可以通過此文了解 OPTO Isolate 模式如何使用并按照說明可以實現(xiàn)最高 2.57MBps 的數(shù)據(jù)傳輸。
準備工作
你需要具備以下條件:
一塊 icestick 開發(fā)板
ice40 FPGA 開發(fā)工具,開源工具或者 iceCube2
FT Prog 程序及 D2XX 驅動
FT2232H Datasheet
同時,筆者使用以下軟件實現(xiàn) Windows 端測試程序:
zadig 軟件
libusb 庫及開發(fā)環(huán)境
準備妥當后,我們先嘗試修改 FT2232H 芯片端口 B 的模式。
修改模式
首先,我們需要使用 FTDI 公司的 FT Prog 程序來修改端口 B 的模式。而 FT Prog 程序則需要驅動程序 D2XX 驅動。
打開設備管理器,插入 icestick 后,如果 D2XX 設備驅動程序配置正常,在通用總線控制器下會出現(xiàn) USB Serial Converter A 和 USB Serial Converter B 設備,如下圖所示。
打開 FT Prog 程序,主菜單上點擊 DEVICES 然后點擊 Scan and Parse 子菜單。如果一切正常,讀者應該可以看到以下界面:
選中設備,找到 Hardware Specific 下 Port B 的 Hardware 項,選擇 OPTO Isolate 項,然后在主菜單上點擊 DEVICES 然后點擊 Program 子菜單。
點擊 Program 按鈕就可以將修改后的配置選項寫入 FT2232H 的 EEROM 中。
燒寫完畢后可以重新拔插 icestick,打開 FT Prog 再次查看設備的 Port B 的屬性是否已經修改成 OPTO Isolate。
修改成功后,我們看一下 OPTO Isolate 模式下接口的規(guī)格。
OPTO Isolate 模式
在 FT2232H Datasheet 章節(jié) 3.1.4.6 FT2232H Pins used as a Fast Serial Interface 的 Table 3.10 中我們可以找到:
由于本文側重于 FPGA 到 FT2232H 的數(shù)據(jù)傳輸,我們可以暫時忽略用于 FT2232H 到 FPGA 方向數(shù)據(jù)傳輸?shù)?FSDO 引腳。
在章節(jié) 4.8.2 Incoming Fast Serial Data 中 Figure 4.15 Fast Opto-Isolated Serial Interface Input Data 我們可以看到:
有此時序圖我們可以看出:
空閑狀態(tài)下 FSCTS 和 FSDI 應為高電平
FSCLK 作為數(shù)據(jù)傳輸?shù)膮⒖紩r鐘,F(xiàn)T2232H 應在 FSCLK 的上升沿采數(shù)據(jù)
FSCTS 為高電平時,F(xiàn)PGA 可以進行數(shù)據(jù)傳輸
一次傳輸?shù)臄?shù)據(jù)由一個由 0 表示的起始位、LSB 優(yōu)先的 8 位數(shù)據(jù)和一個 DEST 位組成
在 DEST 位發(fā)送后,F(xiàn)SCTS 仍然會保持一段時間的低電平
然后我們在章節(jié) 4.8 Fast Opto-Isolated Serial Interface Mode Description 的 Figure 4.13 Fast Opto-Isolated Serial Interface Signal Waveforms 看到具體時序:
以及在同一章節(jié)的 Table 4.6 Fast Opto-Isolated Serial Interface Signal Timings 看到具體時序:
根據(jù)這些,我們可以得到:
FSCLK 的最小周期是 20ns,即最大頻率是 50MHz
FSDI 的建立時間最小為 10ns,保持時間最小為 5 ns
這樣我們可以根據(jù)這些參數(shù)進行 FPGA 接口設計了。
接口電路設計
在實現(xiàn)接口電路之前,讀者需要檢查具體用到的 FPGA 的性能。如果 IO 反轉性能不能達到 50MHz,那么 IO 就成為瓶頸;如果 IO 性能滿足要求,但是接口電路頻率不能超過 100MHz 或者在支持支持雙沿輸出和輸入的情況下超過 50MHz,接口電路就會成為瓶頸。
通過查看 ice40hx1k 的文檔,我們可以大致確定 ice40hx1k 的普通 IO 反轉可以做到 50MHz,而且,在此 FPGA 上實現(xiàn)一個運行在近 100MHz 的電路并不十分困難。
如果我們使用 100MHz 作為內部時鐘,那么數(shù)據(jù)傳輸時序圖會變成:
需要說明的是
我們使用 100MHz 使用來產生一個 50MHz 的 FSCLK 對應 IO 的反轉
我們在 FSCLK 的下降沿變更數(shù)據(jù),這樣保證 FSDI 的建立時間和保持時間都是 10ns
我們會產生一個持續(xù)反轉的 FSCLK,而不會在不傳輸數(shù)據(jù)的時候暫停 FSCLK
通過觀察時序圖,計數(shù)狀態(tài)機來實現(xiàn)此電路較為簡單。同時對于慢速接口電路,valid-ready 信號也是不能缺少的。加入這些信息后,數(shù)據(jù)傳輸時序圖會變成:
有了這樣的時序圖,我們可以開始實現(xiàn)具體的電路了。
接口電路實現(xiàn)
首先,輸入信號 FSCTS 需要經過跨時鐘域處理。我們可以將 i_fscts 連接到 2 個級聯(lián)的 DFF 上來進行處理,從而得到同步的信號 w_fscts。
// //CDCsignals // localparamDFF_W=2; wirew_fscts; reg[DFF_W-1:0]r_fscts_sync; always@(posedgei_clk) r_fscts_sync<=?{r_fscts_sync[DFF_W?-?2?:?0],?i_fscts}; ????assign?w_fscts?=?r_fscts_sync[DFF_W?-?1];
其次,F(xiàn)ast Opto-Isolated Serial Interface 電路本質是將并行的數(shù)據(jù)進行串行數(shù)據(jù),我們還需要一個移位寄存器和對應的控制信號:
// //r_data // //r_datakeepsthedatatobetransmitted // localparamTX_DATA_W=DATA_W+3; reg[TX_DATA_W-1:0]r_data; reg[TX_DATA_W-1:0]w_data_next; wirew_data_tick; wirew_data_load; wirew_status_tick; always@(posedgei_clk,posedgei_arst) if(i_arst) r_data<=?{TX_DATA_W{1'b1}}; ????????else ????????????r_data?<=?w_data_next; ????always?@(*)?begin ????????w_data_next?=?r_data; ????????if?(w_data_load) ????????????w_data_next?=?{i_channel,?i_data,?2'b01}; ????????else ????????????if?(w_data_tick) ????????????????w_data_next?=?{1'b1,?r_data[TX_DATA_W?-?1?:?1]}; ????end ????//?w_data_load?indicates?if?r_data?could?be?filled?safely ????assign?w_data_load?=?o_ready?&?i_valid; ????assign?w_data_tick?=?w_status_tick?|?w_status_start;
因為數(shù)據(jù)的發(fā)送需要兩個必備條件,我們需要一個 bit 來確保默認情況 FSDI 的數(shù)據(jù)為高電平。這樣,加上起始位和 DEST 位后,我們共需要 11 位移位寄存器。
同時,數(shù)據(jù)發(fā)送時 LSB 優(yōu)先的,我們的 FSDI 自然而然的會連接到移位寄存器的最低位。
復位時,移位寄存器全部填充為 1;復位解除后,如果需要加載數(shù)據(jù)時,即 w_data_load 為有效時,那么將表示 DEST 位的 i_channel、8 位數(shù)據(jù) i_data 、表示起始位的 0 和默認電平 1 加載到寄存器中;如果遇到 w_data_tick 有效時,那么就將移位寄存器進行右移,最高位填充 1。
然后,因為數(shù)據(jù)發(fā)送的兩個條件并不是同時發(fā)生,我們需要一個寄存器來表示 r_data 是否已經填充。
// //r_data_status // //r_data_statusdecidesthevalid-readysignalsand //ifr_statusFSMstarts // regr_data_filled; regr_data_filled_next; wirew_data_done; wirew_status_done; always@(posedgei_clk,posedgei_arst) if(i_arst) r_data_filled<=?1'b0; ????????else ????????????r_data_filled?<=?r_data_filled_next; ????always?@(*)?begin ????????r_data_filled_next?=?r_data_filled; ????????//?if?the?tx?data?has?been?filled ????????if?(r_data_filled)?begin ????????????//?and?the?data?transmission?has?been?done ????????????if?(w_data_done) ????????????????r_data_filled_next?=?1'b0; ????????end ????????//?or?if?the?tx?data?is?empty ????????else?begin ????????????//?and?upstream?module's?data?is?ready ????????????if?(i_valid) ????????????????r_data_filled_next?=?1'b1; ????????end ????end ????assign?w_data_done?=?w_status_done?&?i_tick;
默認的情況下,r_data_filled 為 0 表示 r_data 是沒有填充的;如果沒有填充過且輸入數(shù)據(jù)有效,那么就將 r_data_filled 設置為 1,表示已經填充;如果已經填充,且表示數(shù)據(jù)已經完全被發(fā)送出去,即 w_data_done 為 1 時將 r_data_filled 設置為 0。
接著,我們需要實現(xiàn)一個計數(shù)狀態(tài)機來控制 r_data 的移位和 r_data_filled 的更新。
// //r_status // //r_statuscontrolsTXFSM // localparamSTATUS_MAX=11; localparamSTATUS_W=$clog2(STATUS_MAX); reg[STATUS_W-1:0]r_status; reg[STATUS_W-1:0]w_status_next; wirew_status_start; wirew_status_idle; assignw_status_idle=(r_status=={STATUS_W{1'b0}}); assignw_status_done=(r_status==(STATUS_MAX[STATUS_W-1:0]-1'b1)); assignw_status_tick=i_tick&~w_status_idle; always@(posedgei_clk,posedgei_arst) if(i_arst) r_status<=?{STATUS_W{1'b0}}; ????????else ????????????r_status?<=?w_status_next; ????always?@(*)?begin ????????w_status_next?=?r_status; ????????if?(w_status_start) ????????????w_status_next?=?{{STATUS_W-1{1'b0}},?1'b1}; ????????else ????????????if?(w_status_tick) ????????????????if?(w_status_done) ????????????????????w_status_next?=?{STATUS_W{1'b0}}; ????????????????else ????????????????????w_status_next?=?r_status?+?1'b1; ????end ????//?FSM?begins?counting?when?FSM?is?idle ????assign?w_status_start?=?w_status_idle?& ????????????????????????????//?r_data?is?filled ????????????????????????????r_data_filled?& ????????????????????????????//?i_fstcs?is?ready?to?receive?data ????????????????????????????w_fscts?& ????????????????????????????//?to?sync?with?o_fsclk?signal ????????????????????????????i_tick;
計數(shù)狀態(tài)機的實現(xiàn)并不復雜。默認情況下,計數(shù)器為 0 表示接口處于空閑狀態(tài);在處于空閑狀態(tài)下,如果 r_data 已經被填充,F(xiàn)SCTS 信號為高,在保證與時鐘同步的情況下,計數(shù)器變成 1,然后每個 w_status_tick 有效時加一,知道計到最大狀態(tài) 10 之后又變?yōu)?0,等待 w_status_start 再次變?yōu)?1。
最后,有了上述電路,那么輸出信號處理就較為簡單。
// //outputsignals // //r_dataisreadywhenr_data_filledis0 assigno_ready=~r_data_filled; assigno_fsdi=r_data[0];
對于 o_ready 信號,只要數(shù)據(jù)發(fā)送完畢就可以進行填充;而 FSDI 信號直接取 r_data 的最低位。
為了測試這一接口模塊,我們還需要設計另外一個控制模塊來產生數(shù)據(jù)并驅動此接口模塊。筆者實現(xiàn)了一個控制模塊,支持周期發(fā)送和最大帶寬發(fā)送兩種模式選擇。限于篇幅,此處不再贅述其實現(xiàn)細節(jié)。
控制模塊的代碼、接口模塊的代碼、cocotb 仿真代碼及 icestick 完整的工程可以在 icestick-oifs 庫中 gateware 目錄 oifs-tx 子目錄下找到。
需要注意的是,由于 icestick 板載晶振頻率 12MHz,使用 PLL 倍頻出最大符合規(guī)范的時鐘頻率為 99MHz,所以,實際的 FSCLK 的反轉頻率是 49.5MHz,而非設計時的 50MHz。
FPGA 部分實現(xiàn)完畢后,我們還需要實現(xiàn) USB Host 側的軟件來接收數(shù)據(jù)。
USB Host 側軟件
為了實現(xiàn)跨平臺的代碼,筆者使用 libusb 庫進行 USB Host 側的代碼。
在 Windows 上,讀者需要使用 zadig 軟件將端口 B 的 D2XX 驅動替換成 libusb 的驅動。如下圖所示:
同時,筆者在 msys2 環(huán)境下安裝 mingw-w64-x86_64-libftdi 和必要的開發(fā)工具,用來構建 USB Host 側的程序。
筆者編寫了兩個程序,一個程序用來讀取數(shù)據(jù)并計算性能,名為 oifs-rxperf,另外一個程序用來將數(shù)據(jù)打印到控制臺,名為 oifs-rxdump。
USB Host 側代碼可以在 icestick-oifs 庫中 software 目錄下找到。這些代碼可以不用修改或者稍加修改運行在 Linux 平臺上。
測試結果
筆者在 Windows 上測試的結果如下:
我們可以看到最高的傳輸速率可以達到 2.57MBps。筆者在 Ubuntu 20.04 和 Ubuntu 22.04 中分別進行了測試,測試結果與 Windows 平臺上得到的結果一致。
在接口邏輯仿真環(huán)境中,我們假設了 FSCTS 信號總高,但是實際情況并非如此:
通過邏輯分析儀抓到信號的波形來看,F(xiàn)SCTS 在 DEST 位傳輸完畢后保持 140ns 的低電平,那么一次傳輸需要大概 364ns 到 384ns,則極限帶寬則約為 2.61MBps。
總結
按照本文的說明及相應的代碼,讀者應該可以在 icestick 上實現(xiàn)從 FPGA 到 USB Host最高 2.57MBps 的數(shù)據(jù)傳輸,從而將 icestick 變成一個 USB 數(shù)據(jù)采集板。
審核編輯:劉清
-
FPGA
+關注
關注
1625文章
21620瀏覽量
601231 -
usb
+關注
關注
60文章
7876瀏覽量
263692 -
fifo
+關注
關注
3文章
386瀏覽量
43492 -
FT2232H
+關注
關注
1文章
4瀏覽量
9872
原文標題:如何將 FPGA 變成 USB 數(shù)據(jù)采集板
文章出處:【微信號:Open_FPGA,微信公眾號:OpenFPGA】歡迎添加關注!文章轉載請注明出處。
發(fā)布評論請先 登錄
相關推薦
評論