背景信息
icestick 板載 USB 接口芯片 FT2232H 的端口 A 和端口 B 均與 FPGA ice40hx1k 相連。其中,端口 A 處于 MPSSE 模式,用于讀寫 SPI Flash 以更新 FPGA 的 bitfile,而 B 口默認(rèn)處于 ASYNC Serial 模式,當(dāng)作串口使用。
端口 B 都只有一部分引腳連到 FPGA,無法支持 245 FIFO 或者 245 FIFO SYNC 模式以實(shí)現(xiàn)高速數(shù)據(jù)傳輸。而在 ASYNC Serial 模式時(shí),其支持最大 12Mbaud 即最高 1.14MBps 的數(shù)據(jù)傳輸。
筆者發(fā)現(xiàn) FT2232H 還支持一種稱為 Fast Opto-Isolated Serial Interface 的模式。在 FTDI 文檔和軟件中,這一模式也被稱為 Fast Serial Interface 模式或者 OPTO Isolate 模式。因?yàn)橐肓?a href="http://m.makelele.cn/tags/時(shí)鐘/" target="_blank">時(shí)鐘引腳,這一模式可以在使用較少引腳的情況實(shí)現(xiàn)比 ASYNC Serial 模式更高帶寬的數(shù)據(jù)傳輸。
讀者可以通過此文了解 OPTO Isolate 模式如何使用并按照說明可以實(shí)現(xiàn)最高 2.57MBps 的數(shù)據(jù)傳輸。
準(zhǔn)備工作
你需要具備以下條件:
一塊 icestick 開發(fā)板
ice40 FPGA 開發(fā)工具,開源工具或者 iceCube2
FT Prog 程序及 D2XX 驅(qū)動(dòng)
FT2232H Datasheet
同時(shí),筆者使用以下軟件實(shí)現(xiàn) Windows 端測試程序:
zadig 軟件
libusb 庫及開發(fā)環(huán)境
準(zhǔn)備妥當(dāng)后,我們先嘗試修改 FT2232H 芯片端口 B 的模式。
修改模式
首先,我們需要使用 FTDI 公司的 FT Prog 程序來修改端口 B 的模式。而 FT Prog 程序則需要驅(qū)動(dòng)程序 D2XX 驅(qū)動(dòng)。
打開設(shè)備管理器,插入 icestick 后,如果 D2XX 設(shè)備驅(qū)動(dòng)程序配置正常,在通用總線控制器下會(huì)出現(xiàn) USB Serial Converter A 和 USB Serial Converter B 設(shè)備,如下圖所示。

打開 FT Prog 程序,主菜單上點(diǎn)擊 DEVICES 然后點(diǎn)擊 Scan and Parse 子菜單。如果一切正常,讀者應(yīng)該可以看到以下界面:

選中設(shè)備,找到 Hardware Specific 下 Port B 的 Hardware 項(xiàng),選擇 OPTO Isolate 項(xiàng),然后在主菜單上點(diǎn)擊 DEVICES 然后點(diǎn)擊 Program 子菜單。

點(diǎn)擊 Program 按鈕就可以將修改后的配置選項(xiàng)寫入 FT2232H 的 EEROM 中。
燒寫完畢后可以重新拔插 icestick,打開 FT Prog 再次查看設(shè)備的 Port B 的屬性是否已經(jīng)修改成 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 中我們可以找到:

由于本文側(cè)重于 FPGA 到 FT2232H 的數(shù)據(jù)傳輸,我們可以暫時(shí)忽略用于 FT2232H 到 FPGA 方向數(shù)據(jù)傳輸?shù)?FSDO 引腳。
在章節(jié) 4.8.2 Incoming Fast Serial Data 中 Figure 4.15 Fast Opto-Isolated Serial Interface Input Data 我們可以看到:

有此時(shí)序圖我們可以看出:
空閑狀態(tài)下 FSCTS 和 FSDI 應(yīng)為高電平
FSCLK 作為數(shù)據(jù)傳輸?shù)膮⒖紩r(shí)鐘,F(xiàn)T2232H 應(yīng)在 FSCLK 的上升沿采數(shù)據(jù)
FSCTS 為高電平時(shí),F(xiàn)PGA 可以進(jìn)行數(shù)據(jù)傳輸
一次傳輸?shù)臄?shù)據(jù)由一個(gè)由 0 表示的起始位、LSB 優(yōu)先的 8 位數(shù)據(jù)和一個(gè) DEST 位組成
在 DEST 位發(fā)送后,F(xiàn)SCTS 仍然會(huì)保持一段時(shí)間的低電平
然后我們在章節(jié) 4.8 Fast Opto-Isolated Serial Interface Mode Description 的 Figure 4.13 Fast Opto-Isolated Serial Interface Signal Waveforms 看到具體時(shí)序:

以及在同一章節(jié)的 Table 4.6 Fast Opto-Isolated Serial Interface Signal Timings 看到具體時(shí)序:

根據(jù)這些,我們可以得到:
FSCLK 的最小周期是 20ns,即最大頻率是 50MHz
FSDI 的建立時(shí)間最小為 10ns,保持時(shí)間最小為 5 ns
這樣我們可以根據(jù)這些參數(shù)進(jìn)行 FPGA 接口設(shè)計(jì)了。
在實(shí)現(xiàn)接口電路之前,讀者需要檢查具體用到的 FPGA 的性能。如果 IO 反轉(zhuǎn)性能不能達(dá)到 50MHz,那么 IO 就成為瓶頸;如果 IO 性能滿足要求,但是接口電路頻率不能超過 100MHz 或者在支持支持雙沿輸出和輸入的情況下超過 50MHz,接口電路就會(huì)成為瓶頸。
通過查看 ice40hx1k 的文檔,我們可以大致確定 ice40hx1k 的普通 IO 反轉(zhuǎn)可以做到 50MHz,而且,在此 FPGA 上實(shí)現(xiàn)一個(gè)運(yùn)行在近 100MHz 的電路并不十分困難。
如果我們使用 100MHz 作為內(nèi)部時(shí)鐘,那么數(shù)據(jù)傳輸時(shí)序圖會(huì)變成:

需要說明的是
我們使用 100MHz 使用來產(chǎn)生一個(gè) 50MHz 的 FSCLK 對應(yīng) IO 的反轉(zhuǎn)
我們在 FSCLK 的下降沿變更數(shù)據(jù),這樣保證 FSDI 的建立時(shí)間和保持時(shí)間都是 10ns
我們會(huì)產(chǎn)生一個(gè)持續(xù)反轉(zhuǎn)的 FSCLK,而不會(huì)在不傳輸數(shù)據(jù)的時(shí)候暫停 FSCLK
通過觀察時(shí)序圖,計(jì)數(shù)狀態(tài)機(jī)來實(shí)現(xiàn)此電路較為簡單。同時(shí)對于慢速接口電路,valid-ready 信號(hào)也是不能缺少的。加入這些信息后,數(shù)據(jù)傳輸時(shí)序圖會(huì)變成:

有了這樣的時(shí)序圖,我們可以開始實(shí)現(xiàn)具體的電路了。
接口電路實(shí)現(xiàn)
首先,輸入信號(hào) FSCTS 需要經(jīng)過跨時(shí)鐘域處理。我們可以將 i_fscts 連接到 2 個(gè)級(jí)聯(lián)的 DFF 上來進(jìn)行處理,從而得到同步的信號(hào) 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 電路本質(zhì)是將并行的數(shù)據(jù)進(jìn)行串行數(shù)據(jù),我們還需要一個(gè)移位寄存器和對應(yīng)的控制信號(hào):
//
//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;
因?yàn)閿?shù)據(jù)的發(fā)送需要兩個(gè)必備條件,我們需要一個(gè) bit 來確保默認(rèn)情況 FSDI 的數(shù)據(jù)為高電平。這樣,加上起始位和 DEST 位后,我們共需要 11 位移位寄存器。
同時(shí),數(shù)據(jù)發(fā)送時(shí) LSB 優(yōu)先的,我們的 FSDI 自然而然的會(huì)連接到移位寄存器的最低位。
復(fù)位時(shí),移位寄存器全部填充為 1;復(fù)位解除后,如果需要加載數(shù)據(jù)時(shí),即 w_data_load 為有效時(shí),那么將表示 DEST 位的 i_channel、8 位數(shù)據(jù) i_data 、表示起始位的 0 和默認(rèn)電平 1 加載到寄存器中;如果遇到 w_data_tick 有效時(shí),那么就將移位寄存器進(jìn)行右移,最高位填充 1。
然后,因?yàn)閿?shù)據(jù)發(fā)送的兩個(gè)條件并不是同時(shí)發(fā)生,我們需要一個(gè)寄存器來表示 r_data 是否已經(jīng)填充。
// //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èn)的情況下,r_data_filled 為 0 表示 r_data 是沒有填充的;如果沒有填充過且輸入數(shù)據(jù)有效,那么就將 r_data_filled 設(shè)置為 1,表示已經(jīng)填充;如果已經(jīng)填充,且表示數(shù)據(jù)已經(jīng)完全被發(fā)送出去,即 w_data_done 為 1 時(shí)將 r_data_filled 設(shè)置為 0。
接著,我們需要實(shí)現(xiàn)一個(gè)計(jì)數(shù)狀態(tài)機(jī)來控制 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;
計(jì)數(shù)狀態(tài)機(jī)的實(shí)現(xiàn)并不復(fù)雜。默認(rèn)情況下,計(jì)數(shù)器為 0 表示接口處于空閑狀態(tài);在處于空閑狀態(tài)下,如果 r_data 已經(jīng)被填充,F(xiàn)SCTS 信號(hào)為高,在保證與時(shí)鐘同步的情況下,計(jì)數(shù)器變成 1,然后每個(gè) w_status_tick 有效時(shí)加一,知道計(jì)到最大狀態(tài) 10 之后又變?yōu)?0,等待 w_status_start 再次變?yōu)?1。
最后,有了上述電路,那么輸出信號(hào)處理就較為簡單。
// //outputsignals // //r_dataisreadywhenr_data_filledis0 assigno_ready=~r_data_filled; assigno_fsdi=r_data[0];
對于 o_ready 信號(hào),只要數(shù)據(jù)發(fā)送完畢就可以進(jìn)行填充;而 FSDI 信號(hào)直接取 r_data 的最低位。
為了測試這一接口模塊,我們還需要設(shè)計(jì)另外一個(gè)控制模塊來產(chǎn)生數(shù)據(jù)并驅(qū)動(dòng)此接口模塊。筆者實(shí)現(xiàn)了一個(gè)控制模塊,支持周期發(fā)送和最大帶寬發(fā)送兩種模式選擇。限于篇幅,此處不再贅述其實(shí)現(xiàn)細(xì)節(jié)。
控制模塊的代碼、接口模塊的代碼、cocotb 仿真代碼及 icestick 完整的工程可以在 icestick-oifs 庫中 gateware 目錄 oifs-tx 子目錄下找到。
需要注意的是,由于 icestick 板載晶振頻率 12MHz,使用 PLL 倍頻出最大符合規(guī)范的時(shí)鐘頻率為 99MHz,所以,實(shí)際的 FSCLK 的反轉(zhuǎn)頻率是 49.5MHz,而非設(shè)計(jì)時(shí)的 50MHz。
FPGA 部分實(shí)現(xiàn)完畢后,我們還需要實(shí)現(xiàn) USB Host 側(cè)的軟件來接收數(shù)據(jù)。
USB Host 側(cè)軟件
為了實(shí)現(xiàn)跨平臺(tái)的代碼,筆者使用 libusb 庫進(jìn)行 USB Host 側(cè)的代碼。
在 Windows 上,讀者需要使用 zadig 軟件將端口 B 的 D2XX 驅(qū)動(dòng)替換成 libusb 的驅(qū)動(dòng)。如下圖所示:

同時(shí),筆者在 msys2 環(huán)境下安裝 mingw-w64-x86_64-libftdi 和必要的開發(fā)工具,用來構(gòu)建 USB Host 側(cè)的程序。
筆者編寫了兩個(gè)程序,一個(gè)程序用來讀取數(shù)據(jù)并計(jì)算性能,名為 oifs-rxperf,另外一個(gè)程序用來將數(shù)據(jù)打印到控制臺(tái),名為 oifs-rxdump。
USB Host 側(cè)代碼可以在 icestick-oifs 庫中 software 目錄下找到。這些代碼可以不用修改或者稍加修改運(yùn)行在 Linux 平臺(tái)上。
測試結(jié)果
筆者在 Windows 上測試的結(jié)果如下:

我們可以看到最高的傳輸速率可以達(dá)到 2.57MBps。筆者在 Ubuntu 20.04 和 Ubuntu 22.04 中分別進(jìn)行了測試,測試結(jié)果與 Windows 平臺(tái)上得到的結(jié)果一致。
在接口邏輯仿真環(huán)境中,我們假設(shè)了 FSCTS 信號(hào)總高,但是實(shí)際情況并非如此:

通過邏輯分析儀抓到信號(hào)的波形來看,F(xiàn)SCTS 在 DEST 位傳輸完畢后保持 140ns 的低電平,那么一次傳輸需要大概 364ns 到 384ns,則極限帶寬則約為 2.61MBps。
總結(jié)
按照本文的說明及相應(yīng)的代碼,讀者應(yīng)該可以在 icestick 上實(shí)現(xiàn)從 FPGA 到 USB Host最高 2.57MBps 的數(shù)據(jù)傳輸,從而將 icestick 變成一個(gè) USB 數(shù)據(jù)采集板。
審核編輯:劉清
-
FPGA
+關(guān)注
關(guān)注
1660文章
22412瀏覽量
636379 -
usb
+關(guān)注
關(guān)注
60文章
8440瀏覽量
284547 -
fifo
+關(guān)注
關(guān)注
3文章
407瀏覽量
45752 -
FT2232H
+關(guān)注
關(guān)注
1文章
4瀏覽量
10095
原文標(biāo)題:如何將 FPGA 變成 USB 數(shù)據(jù)采集板
文章出處:【微信號(hào):Open_FPGA,微信公眾號(hào):OpenFPGA】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評(píng)論請先 登錄
基于FPGA的高速LVDS數(shù)據(jù)傳輸
求助 ,關(guān)于STM32的USB數(shù)據(jù)傳輸問題
基于FPGA+USB3.0接口的高速數(shù)據(jù)傳輸系統(tǒng)設(shè)計(jì)
汽車行駛記錄儀的數(shù)據(jù)傳輸設(shè)計(jì)
如何實(shí)現(xiàn)ISO數(shù)據(jù)傳輸
USB數(shù)據(jù)傳輸接口電路設(shè)計(jì)
如何實(shí)現(xiàn)FPGA和PC之間的數(shù)據(jù)傳輸?
基于USB接口的無線數(shù)據(jù)傳輸系統(tǒng)設(shè)計(jì)
基于FPGA和USB的高速數(shù)據(jù)傳輸、記錄及顯示系統(tǒng)
基于DSP的USB數(shù)據(jù)傳輸系統(tǒng)設(shè)計(jì)
基于USB2.0的紅外數(shù)據(jù)傳輸系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)
USB2.0+FPGA實(shí)現(xiàn)多路數(shù)據(jù)傳輸系統(tǒng)
基于EDMA實(shí)現(xiàn)TMS320C64X與FPGA的數(shù)據(jù)傳輸
在icestick板子上實(shí)現(xiàn)從FPGA到USB Host的數(shù)據(jù)傳輸
評(píng)論