DDR3-AXI-USBのサンプルデザイン
VivadoでUSB3.0からAXIバスを経由してUSB3.0へ読み書きするサンプルデザインを作りました。
このサンプルデザインは次のような機能があります。
- AXI-4を通じたMIG(DDR3メモリの読み書き)
- シンプルなブロックRAMの読み書き
- 640×480サイズの画像を想定したパターンジェネレータ
- アドバンスドLEDチカチカ
- GPIOの状態をUSB3.0に転送
なお、FX3からMIG(DDR3メモリ)への読み書きは、間にAXIインタコネクトを挟んでいるので、ここにユーザ回路を追加すれば、ユーザ回路からDDR3メモリに書き込み、それをUSBでパソコンに吸い上げるといった使い方ができます。
ダウンロード
- サンプルデザインVivadoのプロジェクト (ハードウェアデザイン一式)
- Artix-7 USB3.0 通信サンプルソフト (ソフトウェアデザイン一式)
FX3-AXIコア
このデザインで要になるのは、FX3-AXIコアです。
このコアは、EZ-USB FX3をAXIバスに変換するIPコアで、以下の機能を持ちます。
- USB3.0のBulk In/Outを標準的なAXI-4として出力する
- USB3.0のBulk In/OutをBRAMインタフェースとして出力する
- USB3.0のBulk In/Outを低レベルなローカルバスとして出力する
- Bulk In/Outで読み書き可能なローカルレジスタ(32bit×16本)の提供
ソースコードで提供されているので、VivadoでEdit in IP Packagerを行うとソースの編集ができます。
このコアは USBを使う のページのコアをAXIバス化したものです。こちらのページで紹介したUSB APIがそのまま使えます。
ポートの説明
- usbというポートは、EZ-USB FX3へつながる信号です。Make ExternalでそのままFPGAの外に出してください。
- M_AXIは、Full AXI-4のマスタです。ここにAXI Interconnectをつないで、MIGや、ユーザ回路をつないでください。
- bramは、XILINXのbramインタフェースです。ローカルなBlockRAMをそのままつなげることができます。DDRメモリと比べて高速ですが、容量は最大512kバイト程度が実用的です。
- bulkioは、特電仕様のローカルなバルク転送ポートです。各信号の使い方はこちらのページをご覧ください。
- iregは、ローカルな内蔵レジスタ用ポートです。
- clk100m_iは、元になるクロックです。reset_iは使用していませんが、平常動作時は'0'にしてください。
- m_axi_aclkはMIGから出力されるui_clkを、m_axi_aresetnは、MIGから出力されるsync_rstを反転させたものを入れてください。
AXIと、BRAMと、内蔵レジスタの使い分け(プログラムの作成方法)
当コアを操作するPCのプログラムでは、基本的にはUSBWriteData、USBReadDataという関数を使います
int USBWriteData(unsigned long addr,unsigned char *data,int len,unsigned short flag); int USBReadData(unsigned long addr,unsigned char *data,int len,unsigned short flag);
ここで、flag=0とすると内蔵レジスタ、flag=1とするとBRAM、flag=2とするとAXIバス(DDRメモリ)を読み書きします。
このサンプルデザインでは、flag=6とするとパターンジェネレータからの読み出しになります。
サンプルソフトについて
このサンプルソフトでは、内蔵BRAMや、DDRメモリ、パターンジェネレータへの読み書きができます。
FX3-AXIコアを通じて最大300MB/s超の速度で通信ができます。また、ソースコードも付属しています。
![]() |
![]() |
USB2.0でインタフェース | USB3.0でインタフェース |
内蔵レジスタ
内蔵レジスタは、32bitのシンプルなレジスタが16本集まったものです。
AXI-GPIOよりも手軽に、コントロール/ステータスレジスタが作れます。
VivadoのIPインテグレータでは、バスのバスが作れないので、512ビット幅の信号を作り、32×16のレジスタを詰めて出力しています。
内蔵レジスタへの書き込み
USBWriteData(レジスタ番号,data,4,0)で内蔵レジスタに書き込むと、
ireg_op[(レジスタ番号)×32+31 : (レジスタ番号)×32]
から、書き込まれた値が出てきます。
また、このとき、ireg_updated_op(レジスタ番号)が'1'になります。
内蔵レジスタからの読み出し
USBReadData(レジスタ番号,data,4,0)で、内蔵レジスタから読み出すと、
ireg_ip[(レジスタ番号)×32+31 : (レジスタ番号)×32]
のポートの値がPCから読み出せます。
また、このとき、ireg_captured_op(レジスタ番号)が'1'になります。
ブロックRAM
BRAMは、XILINXのブロックRAM用のポートです。
ここに標準的なブロックRAMを接続すると、USBWriteData(addr,data,len,1)で書き込み、USBReadData(addr,data,len,1)で読み出しができるようになります。
BRAMを使用しない場合は削除してしまって構いません。
BRAMを作るときには、以下のような設定にします。
- モードはStandAloneにする。実用的にするには、BRAMのもう一つのポートから読み書きしなければならないので、Single Port RAMではなくTrue Dualport RAMが良いだろう。
- 読み書きの幅は32bit。深さは任意。このサンプルでは131072になっているが、普通はこんなには必要ないだろう。
Primitive Output RegisterとCore Output Registerのチェックは外すこと。そうしないと、読み出しが1クロック遅れるので、正しいデータが読み出せない。
- このページのオプションは変更不要。
- 全体の確認
パターンジェネレータ
パターンジェネレータは、640×480の大きさの様々なパターンを生成する回路です。
flag[2:0]=6としてUSBReadDataで読み出すとbulkinポートを通じてデータを送られます。
flagの[5:3]がパターンのタイプを決めています。このパターンジェネレータを試すには、サンプルソフトでIN data sourceをPattern generatorにします。
Sequential Number
クロックでカウントアップしていく数字です。途中で飛ぶのは、USBの転送が連続ではないからです。
Horizontal gradation
水平グラデーションを生成します。
Vertical gradation
垂直グラデーションを生成します。
Frame Number
時間とともに明るさが変わります。
GPIO[31:0]、GPIO[63:32]
Artix-7ボードのGPIOの端子の状態をそのままデータバスにしたものです。
[31:0]は主に上側のピンヘッダ、[63:32]は主に下側のピンヘッダの値が読み出されます。
指で触るとノイズで縞模様が見えたりします。
Random Pattern
XorShift回路で作った乱数です。