Terasic DE0ボードでのUSB通信①
Terasic社が販売しているFPGAボード・DE0にはUSBコネクタが搭載されていますが, 通信方法について具体的に書かれている資料は英語資料含めても限りなく少ないため中々実装することができませんでした.
しかし,rerm.info JavaでJTAG通信 にてJavaを使って通信する方法が掲載されており, これを元に,と思い立ち今日に至ります.
この記事ではまずUSB通信のテストを行います. 今後の実装の都合上,C#を用いてコーディングしました.
1.USB通信テスト
今回はまずUSB通信の第一歩としてPCから命令を送信し,FPGA特有のコードであるIDCODE*1の受信を試みます.
2.ソースコード
Visual Studioを起動し,Visual C#で新しいコンソールアプリケーションを作成後,以下をコピー・ペーストしてください.
using System; using System.Collections.Generic; using System.Runtime.InteropServices; namespace ConsoleApplication1 { class Program { const string DLL_PATH = "ftd2xx.dll"; [DllImport(DLL_PATH)] unsafe private static extern UInt32 FT_Open( Int16 DeviceNumber, UInt32* ftHandle ); [DllImport(DLL_PATH)] private static extern UInt32 FT_Close( UInt32 ftHandle ); [DllImport(DLL_PATH)] unsafe private static extern UInt32 FT_Write( UInt32 ftHandle, [MarshalAs(UnmanagedType.LPArray)] short[] bdata, UInt32 BufferSize, UInt32* BytesWriten ); [DllImport(DLL_PATH)] unsafe private static extern UInt32 FT_Read( UInt32 lngHandle, [MarshalAs(UnmanagedType.LPArray)] byte[] bdata, UInt32 lngBufferSize, UInt32* lngBytesReturned ); static unsafe void Main( string[] args ) { const short L = 0x2D2C; const short H = (short)(L | 0x1010); const short TMS = (short)(L | 0x0202); const short TMS_H = (short)(TMS | H); const short WR = 0x81; const short RD = 0xC0; const short OFF = 0x0D0C; uint size; UInt32 ftHandle; List<short> memory = new List<short>(); if (FT_Open(0, &ftHandle) != 0) { Console.WriteLine("Don't connect."); Console.ReadLine(); return; } Console.WriteLine("Connection!"); // MoveIdle memory = new List<short> { TMS, TMS, TMS, TMS, TMS, L }; FT_Write(ftHandle, memory.ToArray(), (UInt32)memory.Count << 1, &size); // MoveShiftir memory = new List<short> { TMS, TMS, L, L }; FT_Write(ftHandle, memory.ToArray(), (UInt32)memory.Count << 1, &size); // WriteShiftir memory = new List<short> { (short)((0x06 << 8) | WR), L }; FT_Write(ftHandle, memory.ToArray(), (UInt32)memory.Count << 1, &size); // MoveShiftirToShiftdr memory = new List<short> { TMS, TMS, TMS, L, L }; FT_Write(ftHandle, memory.ToArray(), (UInt32)memory.Count << 1, &size); // ReadShiftdr int rx = new int(); byte[] rxData = new byte[4]; memory = new List<short> { (short)((0 << 8) | (RD | 4)), TMS_H, TMS, TMS, L, L }; FT_Write(ftHandle, memory.ToArray(), (UInt32)memory.Count << 1, &size); for (int i = 0; i < 4; i++) { FT_Read(ftHandle, rxData, 1, &size); rx += rxData[0] << (i * 8); } Console.WriteLine("Device IDCODE is " + rx); memory = new List<short> { TMS_H, TMS, OFF }; FT_Write(ftHandle, memory.ToArray(), (UInt32)memory.Count << 1, &size); FT_Close(ftHandle); Console.WriteLine("JTAG Close..."); Console.ReadKey(); } } }
3.注意事項
- プラットフォームターゲットに"x86"を指定
System.BadImageFormatExceptionエラーが発生する場合があります.設定自体はプロパティのビルドから変更します. - アンセーフコードの許可
ftd2xx.dllを使う関係でunsafeを使用しました.この設定も上と同じくビルドから変更します. - 生成された.exeファイルと同じディレクトリにftd2xx.dllを配置
FTDI社WebサイトのDrivers,D2XX Driversからドライバをダウンロードすると中に入っています. - QuartusⅡを入手しておく
USB Blaster認識の都合上必要だと思います(※未検証).フリーのWeb Editionを入手してみてください.
4.実行結果
DE0に搭載しているFPGA,CycloneⅢ EP3C16のIDCODEは0000 0010 0000 1111 0010 0000 1101 1101*2であり,10進では34545885になります. また,DE0の電源スイッチ下、POWER-LED右側のLOADとシルクがあるLEDが一瞬点灯することを確認できるかと思います. これらより,JTAG通信を用いてIDCODEの読み出しに成功したことがわかります.
5.備考
他のTerasic社製ボードの場合,Terasic DE0-Nano(CycloneⅣ EP4CE22)だと34549981が,DE1(CycloneⅡ EP2C20)だと34287837が出力されます.
unsafeを使わないやり方を考えていますが,未熟ゆえ良い方法が思いつきません...... もしうまいやり方をご存知でしたら教えてください.
参考文献
rerm.info JavaでJTAG通信
ioioのホームページ FT245RL用DLLの使い方
坂巻佳寿美.JTAGテストの基礎と応用.CQ出版,2003
(11/18追記)続き
kazu1995.hatenablog.jp
*1:製造メーカや部品番号などが含まれる32bit長のコードのこと
*2:Altera Cyclone III Device Handbook, Volume 1 『Chapter 12. IEEE 1149.1 (JTAG) Boundary-Scan Testing for the Cyclone III Device Family』 p.12-2より