« 次期JTAGバウンダリスキャンツール | トップページ | Cosmo-Zを無理やり18bit化してみた »

2015.08.22

複数の特電Spartan-6ボードを開く64bit版DLL

あるお客様から

「64bit版アプリから、複数の特電Spartan-6ボードを同時に使用したい。」

というご依頼をいただきました。

複数の特電Spartan-6ボードを開くためのドライバとDLLは、必要とされるお客様に32bit版で提供してきたのですが、どうしても64bit版が必要とのことでした。

WOW64があるから32bit版のDLLでできるのではないかと思っていたのですが、MFCを使うアプリではだめなのですね。きっと。

そこで、「複数のボードを同時に開くDLL」を作ろいとしたのですが、VisualC++でのDLLの作り方を忘れていたため、いろいろとはまりました。

まずは、DLLの作り方を備忘録として書いておきます。

DLLで関数をexportするには、関数の宣言の前に__declspec(dllexport)を付けるか、その関数の名前をDEFファイルに書いておきます。私は__declspec(dllexport)のほうが好きです。

descspecを使う場合は、

__declspec(dllexport) int WINAPI hoge();

のようにして関数を宣言します。

descspecを使わない(DEFファイル)の場合は、

int WINAPI hoge();

のようにします。

WINAPIは、DLLからエクスポートする関数にはこれを付けます。引数が右から順にスタックに詰められるそうです。

DEFファイルを使ってエクスポートする関数を列挙する場合、「DEFファイル」は、

LIBRARY     "tkusb"

EXPORTS
    USBGetMaxInstance            @1
    USBGetBoardInfo              @2
    USBSetBoardUserId            @3
    USBGetDriverVersion          @4
    USBGetFirmwareVersion        @5
    USBReadEEPROM                @6
    USBWriteEEPROM               @7
・・・

のように書きます。@数字は、序数といってDLLの中に入っている関数を示す数字です。

自分の過去のプログラムを見ていて、以下のような書き方をする場合もありました。

LIBRARY     "tkusb"

EXPORTS
  USBGetMaxInstance@0     = USBGetMaxInstance     @1
  USBGetBoardInfo@4       = USBGetBoardInfo       @2
  USBSetBoardUserId@4     = USBSetBoardUserId     @3
  USBGetDriverVersion@0   = USBGetDriverVersion   @4
  USBGetFirmwareVersion@0 = USBGetFirmwareVersion @5
  USBReadEEPROM@12        = USBReadEEPROM         @6
  USBWriteEEPROM@12       = USBWriteEEPROM        @7
・・・

「関数名@数字 = 関数名 @数字」という形になっていますが、これはBorlandC++で作ったDLLをVisualC++で使うためのインポートライブラリを生成するための書き方です。@数字は、その関数の引数の総バイト数を表すようです。この形式のDEFファイルの書き方でVisualC++でビルドすると、USBGetMaxInstance@0という関数名の関数として扱われてしまうようで、リンクできません。

まぁ、この形式のDEFファイルを作るには人間が引数を数えなければいけないから、ミスも入るでしょう。DLLはVisualC++で作るべきだと思います。

さて、これでDLLを作る準備ができたわけですが、VisualStudop2010 Expressで64bit版のDLLを作る方法は、過去の記事「Visual Studio Expressで64bit版DLLを作成してみる」

https://nahitafu.cocolog-nifty.com/nahitafu/2014/04/visual-studio-e.html

に書いてありました。

過去の記事に書いてあった方法でビルドはできました。しかし、実行すると不正な処理して止まってしまいます。

どうやら、その原因はCyAPIをOpenしていることが原因でした。

64bit版のCyAPIのバージョンが古いためか、

CCyUSBDevice hCyApi= new CCyUSBDevice();
delete hCyApi;

だけで不正な処理をして止まってしまうようです。結局、cyusb.sysとcyapi.dllを使わずに、ezusb.sysベースのデバイスドライバを使うようにしたところ、止まらずに起動できるようになりました。

自分の過去の日記を読んでみると、

「Spartan-6ボードのWindows7 64bit対応
https://nahitafu.cocolog-nifty.com/nahitafu/2011/02/21/index.html

に書いていたのですが、2011年ごろに一時期EZ-USB FX2LPをCyAPIでアクセスしようとして開発していたけれども、速度の問題などで、結局、古いezusb.sysを64bit版でコンパイルすることにしたようでした。

マルチボード対応のDLLを使ったアプリは、

#include <stdio.h>

#include "tkusb.h" int main() { TKUSB_HANDLE h = USBOpenExByID(0); printf("Handle = %x\n",h); if(!h) return 0; USBSetSmajModeEx(h,0); // Smajモードを解除し、通常動作モードへ unsigned char buffer[256]; for(int i=0;i<256;i++) buffer[i] = i; USBWriteDataEx(h,buffer,256,1); // BRAMに256バイト書き込み memset(buffer,0,256); USBReadDataEx(h,buffer,256,1); // BRAMから256バイト読み出し for(int i=0;i<256;i++) { printf("%x ",buffer[i]); } USBCloseEx(h); return 0; }

という感じになります。最初のUSBOpenExByIDという関数の引数を変えると、USBにつながった複数のSpartan-6ボードを開けるという仕組みです。

もちろん、PCにつながっている特電Spartan-6ボードの総数を調べる関数もあり、ボード上のEEPROMに書かれた小さなデータを読み出す機能もあるので、複数のボードを区別して開くこともできるというわけです。

もう数日テストしてみて、問題がなければリリースしたいと思います。

|

« 次期JTAGバウンダリスキャンツール | トップページ | Cosmo-Zを無理やり18bit化してみた »

コメント

コメントを書く



(ウェブ上には掲載しません)




« 次期JTAGバウンダリスキャンツール | トップページ | Cosmo-Zを無理やり18bit化してみた »