?
10.7??典型實例17:USB?2.0接口的設計與實現
10.7.1??實例的內容及目標
1.實例的主要內容
本節(jié)旨在設計實現了FPGA通過FX2?USB?2.0接口芯片與PC機進行高速數據通信,分為讀數據、寫數據和讀寫數據3部分內容。幫助讀者進一步了解USB接口芯片的工作原理和設計方法。
2.實例目標
通過本實例,讀者應達到如下目標。
·??了解FX2?CY7C68013芯片的工作原理和Slave?FIFO模式時序。
·??熟練掌握狀態(tài)機的使用。
·??實現FPGA與PC機之間的USB接口通信。
10.7.2??USB接口通信實戰(zhàn)步驟
首先創(chuàng)建工程并為工程添加文件,如圖10.30所示。
然后編譯工程并下載至硬件,如圖10.31所示。
圖10.30??創(chuàng)建工程并添加文件?????? 圖10.31??編譯工程并下載
?
接下來可以加載固件了,固件程序的載入有兩種方式。
(1)通過芯片的I2C總線連接外部的EEPROM,固件代碼事先通過燒寫器寫入EEPROM中,USB設備上電運行時,通過I2C總線將EEPROM中固件代碼載入。EZ-USB支持外部EEPROM通過總線來下載固件,這種方式使開發(fā)者可以從外圍硬件來下載8051程序代碼,但是不利于在設備開發(fā)階段使用。
(2)使用該芯片特有軟配置功能,將固件程序存儲在計算機中,當該設備接入USB電纜時,由于EZ-USB具有重新枚舉的能力,所以在初始化枚舉以后,用戶只需要通過Cypress公司提供的開發(fā)軟件USB?Control?Panel中Download項,就可以將固件載入到控制芯片中。該方法完全是軟操作,不需要額外的硬件設備,方便程序的修改調試。
使用USB?Control?Panel進行固件程序下載的界面如圖10.32所示。
圖10.32??USB?Control?Panel界面
單擊“Download…”按鈕,選擇“slavefifo.hex”。下載固件成功以后顯示如圖10.33信息。
圖10.33??下載固件程序
其中,通過單擊“GetPipes”按鈕可以查看通道信息。
現在固件程序后,即可進行USB通信測試。
根據不同的程序,選擇相應的測試軟件,測試USB接口的傳輸速度。如圖10.34所示是Red?Logic工作室提供的基于紅色颶風II的USB測試軟件。
圖10.34??USB測試軟件
?
10.7.3??USB接口通信實例結果
實現FPGA與PC機之間的USB通信,并且在PC機的超級終端上面測試USB的讀寫速度,如圖10.35和圖10.36所示。關于EZ-USB的詳細內容,可參見工程文件夾中提供的相關文檔。
圖10.35??USB測試結果
圖10.36??USB測試結果
?
10.7.4??FPGA代碼的設計實現
本程序功能是配合CY68013的Slave?FIFO接口時序。它完成接收從主機下傳的60KB數據,寫入板上SRAM里,然后從板上SRAM中讀出,再上傳至主機。整個傳輸過程通過CY68013的Slave?FIFO來交互。
整個程序由一個狀態(tài)機構成,包括以下狀態(tài):
Parameter?IDLE='H0,
???????????????READ_EVENT='H1,
???????????????POINT_TO_OUT_FIFO='H2,
???????????????DATA_READY='H3,
???????????????READ_INTERVAL='H4,
???????????????READ='H5,
???????????????READ_END='H6,
???????????????WRITE_EVENT='H7,
???????????????POINT_TO_IN_FIFO='H8,
???????????????WRITE_READY='H9,
???????????????WRITE='HA,
???????????????WRITE_END='HB;
每個狀態(tài)的作用描述如下。
·??IDLE:整個操作過程(包括讀SLAVE?FIFO和寫SLAVE?FIFO)的入口。對相關的寄存器進行初始化,然后轉入READ_EVENT狀態(tài),開始讀SLAVE?FIFO操作。
·??READ_EVENT:把u_addr[1:0]置為’b00,指向輸出FIFO(對應端點6),然后轉入POINT_TO_OUT_FIFO狀態(tài)。
·??POINT_TO_OUT_FIFO:判斷u_flagc是否為高(u_flagc為高指示輸出FIFO為空,即輸出FIFO中有數據),如果為高,則啟動讀過程,把u_sloe置為低,轉入DATA_READY狀態(tài),第一個16位數據出現在總線上;否則說明輸出FIFO中無數據,等待。
·??DATA_READY:判斷u_flagc是否為高,如果為高,把u_slrd拉低,繼續(xù)讀取下16位數據。同時為把上一16位數據寫入SRAM做準備(主要是SRAM的三態(tài)總線),同時轉入READ狀態(tài),否則轉入POINT_TO_OUT_FIFO,等待下一次讀取過程。
·??READ:把上一16位數據寫入SRAM,同時把u_slrd拉高,當前16位數據讀取結束。判斷是否是60KB數據,如果不是,則轉入DATA_READY狀態(tài),繼續(xù)讀操作;否則轉入READ_END狀態(tài),讀操作結束。
·??READ_END:把相關寄存器置為初始態(tài),轉入WRITE_EVENT狀態(tài),開始寫操作。
·??POINT_TO_IN_FIFO:為從SRAM中讀取數據作準備,轉入WRITE_READY狀態(tài)。
·??WRITE_READY:判斷u_flagb是否為高(u_flagb為高指示輸入FIFO非滿),如果為高,則啟動寫過程,從SRAM中讀取數據并送到SLAVE?FIFO總線上,把u_lswr置為低,轉入WRITE狀態(tài);否則說明輸入FIFO已滿,等待。
·??WRITE:把u_slwr置為高,當前數據寫入SLAVE?FIFO。判斷是否是60KB數據,如果不是,則轉入WRITE_READY狀態(tài),繼續(xù)寫操作;否則轉入WRITE_END狀態(tài),寫操作結束。
?
·??WRITE_END:把相關寄存器置為初始態(tài),轉入IDLE狀態(tài),開始下一個60KB的讀寫操作。
狀態(tài)機的源代碼如下:
case(STATE)
?????IDLE:
??????????begin
??????????//添加RESET狀態(tài)
??????????data_wr<='h0;??????????????? //?USB接口信號初始化
??????????u_slwr<='b1;
??????????u_slrd<='b1;
??????????u_sloe<='b1;
??????????u_addr0<='b1;
??????????u_addr1<='b1;
??????????oe<='b0;
?????
??????????sram_d_i<='h0;?????????????? //?SRAM的控制信號初始化
??????????sram_a<='h3ffff;
??????????sram_re<='b1;
??????????sram_wr<='b1;
??????????wr_flag<='b0;
??????????
??????????STATE<=READ_EVENT;
??????????end
?????READ_EVENT:
??????????begin
??????????wr_flag<='b1;?????????????? //?設定讀寫標志
??????????u_addr0<='b0;?????????????? //?指定端點FIFO
??????????u_addr1<='b0;
??????????STATE<=POINT_TO_OUT_FIFO;
??????????end
?????POINT_TO_OUT_FIFO:
??????????begin
??????????if(u_flagc)???????????????? //??如果flagc高,FIFO不空,開始讀數據
???????????????begin
???????????????u_sloe<='b0;????????? //?開始從FX2的端點FIFO讀數據
???????????????u_slrd<='b1;
???????????????STATE<=DATA_READY;
???????????????end
??????????else
??????????????begin????????? ???? //?如果flagc為低,FIFO為空,等待FIFO有數據
??????????????u_sloe<='b1;????? //?停止從FX2的端點FIFO讀數據
??????????????u_slrd<='b1;
??????????????STATE<=POINT_TO_OUT_FIFO;
??????????????end
??????????end
?????DATA_READY:
??????????begin
??????????if(u_flagc)???????????? //?如果flagc為高,繼續(xù)讀取下一個數據
??????????????begin
??????????????u_slrd<='b0;???????
??????????????sram_a<=sram_a+1;? //?把上一個讀取的數據寫入SRAM
??????????????sram_d_i<=data;
??????????????sram_wr<='b0;
??????????????sram_re<='b1;
??????????????STATE<=READ;??????? //?完成數據寫入后,進入讀數據狀態(tài)
??????????????end
??????????else
??????????????begin
??????????????u_slrd<='b1;??????? //?如果FIFO空,回到等待狀態(tài)
??????????????u_sloe<='b1;
??????????????STATE<=POINT_TO_OUT_FIFO;
??????????????end
??????????end
?????READ:
??????????Begin??????????????
??????????u_slrd<='b1;??????????? //?完成上一個數據的SRAM寫周期
??????????sram_re<='b1;
??????????sram_wr<='b1;
??????????
??????????if(sram_a!=ADDR_FULL)?? //?如果SRAM地址沒有到最大值,繼續(xù)讀操作
??????????????STATE<=DATA_READY;
??????????else
??????????????STATE<=READ_END;? //?如果SRAM地址到達最大值,結束讀操作
??????????end
?????READ_END:
??????????begin
??????????u_slrd<='b1;?????????? //?回到初始狀態(tài),準備寫操作
??????????u_sloe<='b1;
??????????u_addr0<='b0;
??????????u_addr1<='b0;
??????????sram_a<='h3ffff;
??????????STATE<=WRITE_EVENT;
??????????end
?????WRITE_EVENT:
??????????begin
??????????u_addr0<='b0;???????? //?指定寫數據的端點FIFO
??????????u_addr1<='b1;
??????????oe<='b1;
??????????wr_flag<='b0;
??????????STATE<=POINT_TO_IN_FIFO;
??????????end
?????POINT_TO_IN_FIFO:
??????????begin
??????????sram_a<=sram_a+1;?? //?從SRAM中讀取一個數據
??????????sram_re<='b0;
??????????sram_wr<='b1;
??????????STATE<=WRITE_READY;
??????????end
?????WRITE_READY:
??????????begin
??????????if(u_flagb)?
??????????????begin????????????? //?如果FIFO不滿,開始寫數據到FX2的FIFO
??????????????data_wr<=sram_d;
??????????????u_slwr<='b0;
??????????????u_slrd<='b1;
??????????????STATE<=WRITE;
??????????????end
??????????else
??????????????begin???????
??????????????u_slwr<='b1;??????? //?如果FIFO已滿,等待
??????????????u_slrd<='b1;
??????????????STATE<=WRITE_READY;
??????????????end
??????????end
?????WRITE:
??????????begin
??????????u_slwr<='b1;????????????
??????????u_slrd<='b1;
??????????if(sram_a!=ADDR_FULL)
??????????????begin
??????????????sram_a<=sram_a+1;? //?如果SRAM地址沒有達到最大值,繼續(xù)從SRAM讀數據
??????????????sram_wr<='b1;
??????????????sram_re<='b0;
??????????????STATE<=WRITE_READY;
??????????????end
??????????else
??????????????begin
??????????????sram_a<='h3ffff;?//?如果SRAM地址達到最大值,復位SRAM地址,進入寫結束
??????????????sram_wr<='b1;
??????????????sram_re<='b1;
??????????????STATE<=WRITE_END;
??????????????end
??????????end
?????WRITE_END:
??????????begin
??????????wr_flag='b0;????????? //?結束寫FX2?FIFO狀態(tài),回到初始的IDLE狀態(tài)
??????????sram_a<='h3ffff;
??????????u_addr0<='b1;
??????????u_addr1<='b1;
??????????STATE<=IDLE;
??????????end
?????default:
??????????STATE<=IDLE;
?????endcase
10.7.5??小結
本節(jié)對利用USB接口芯片FX2來完成FPGA和PC機的高速數據傳輸做了介紹,并通過編譯下載在紅色颶風的開發(fā)板上實現了預定功能。