スポンサーサイト

.-- -- スポンサー広告 comment(-) trackback(-)
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

FT245プロジェクト中断

.22 2011 FT245-CPLDwriter comment(0) trackback(0)
libftdiを使ってsvfを再生してFPGAをコンフィグするためにいろいろやっていて、まだ未完成ですが、RUNTESTコマンドに対応したところで速度を測ってみました。

結論。libftdiは遅いっぽい。
FTDIのD2XXライブラリを使ったライタがWindows上で走るのでそれと比較してみましたがとにかく遅い。
一応自分のアプリケーションの階層でバッファを作ってftdi_write_data関数を呼ぶ回数は最小限にとどめているのですが、それでも実用に耐える速度ではなかったのでlibftdiを使って作るのは諦めました。
そこでD2XXのライブラリをUbuntuで使えるようにするためにいろいろ調べています。

前にも書いたようにコンパイルまでは通るのですが、実際に実行するとFT_Openが失敗します。
lsusbではFTDIのチップがusbバス上に見えているのですが、D2XXのライブラリ関数からは見えていないようです。

昨日からかなり調べましたが、どうもD2XXは/proc/bus/usbがあることを前提に動いているようなので、今時のUbuntuでは使えないのではないかという気がしています。
今後も調べますが、調べ物にまとまった時間を使うのは勿体ないので一旦このプロジェクトは中断します。
次はDRAMの飼いならし方でも勉強しますか。

VHDL書き終わるころにD2XXをUbuntuで使う方法が分かっていればいいのだが。。。
スポンサーサイト

FT245でsvf再生

.18 2011 FT245-CPLDwriter comment(0) trackback(0)
またまた謎現象が発生しました。
SYNCBB modeではパラレルポート側のピンの状態を変化させる度にそのときのポートの状態を保存し、ftdi_read_dataを呼んだときにそれらのデータが送られてきます。
したがって10byte書き込めば10byte読み出せるはずです。

しかし、ときどきですがこれがうまくいかないのです。
ftdi_write_data(ftdic, txbuf, 10);
done = 0;
for (i = 0; i < 5; i++) {
	ac = ftdi_read_data(ftdic, rxbuf, 10 - done)
	if (ac < 0)
		error_exit();
	done += ac;
	if (done >= 10)
		break;
}
if (done < 10)
	// 10 byte書き込んだのに10 byte読み出せない!
この現象はftdi_initのあとの最初のftdi_read_dataで発生することが多いですが、初回以外でもたまに起こります。
初回に起こる場合が多いのでとりあえず最初に不要なwrite, readをしてさらにpurge_bufferでbufferを空にしていますが、すっきりしない上、初回以外で起きると対処のしようがないです。
libftdiとかlibusbのwrapperでしかないのでそんなにバグがあるとは思えないんですけどねー。どうなってんだか。

続いてsvfを再生します。
svfの仕様についてはSerial Vector Format Specificationとかでググれば出てきます。

今回は読み出した値が期待した値と違う場合にはその時点で諦めて終了するようにします。
そうするとパケットをひとつにまとめて高速化できます。

svfの一番面倒な点は、超長いパラメータをLSB firstで送るので、ファイルポインタをfseekで戻しながら適切な量を持ってこないといけない点です。
例えば、
SDR 1353856 TDI (...1000行くらい...) SMASK (...1000行くらい...) TDO (...1000行くらい...) MASK (...1000行くらい...);
みたいなのは、最初にキーワードTDI, SMASK, TDO, MASKのファイルポインタのオフセット値を記憶して、値の末尾の方からある程度の量をfreadでとってくるようにします。
# パラメータが短ければ普通に一回でfreadして末尾から読むだけでいいのですが、今回はmallocが保証しているサイズを越えているのでこんな面倒なことをしているのです。

XC9572用に吐かれたsvfは全てのコマンドが一行に収まっていて楽なのですがSPARTAN3用に吐かれたsvfは上のようなコマンドがあり、これに対応しないとFPGAライターが作れないのです。

  1. コマンドからキーワードの位置のオフセットを取得する
  2. 読み出した値を下から送出
  3. オフセット値を実際に送ったところまで戻す

間に改行文字とかいろいろ入ること考えてざっとこんな感じに書けばいいのかなー

初めにTDI()の閉じ括弧のオフセット値をtdi_ofs, TDO()の閉じ括弧のオフセット値をtdo_ofsとして記憶します。
BUF_SZ = 4096;

while (len) {
	proc_size = min{len, BUF_SZ};

	fseek(fp, tdi_ofs - proc_size, SEEK_SET);
	fread(fp, tdi_buf, proc_size);
	fseek(fp, tdo_ofs - proc_size, SEEK_SET);
	fread(fp, tdo_buf, proc_size);

	for (i = 0, j = 0; i < proc_size && j < proc_size;) {
		tmp = (ishex(tdo_buf[proc_size - j]) << 1) | ishex(tdi_buf[proc_size - i]);
		if (tmp == 3) {
			send...
			ac_proc++;
			i++;
			j++;
		} else {
			if (!(tmp & (1 << 0)))
				i++;
			if (!(tmp & (1 << 1)))
				j++;
		}
	}
	tdi_ofs -= i;
	tdo_ofs -= j;
	len -= ac_proc;
}

FT245でバウンダリスキャン

.14 2011 FT245-CPLDwriter comment(0) trackback(0)
また変な罠を踏みました。
前回紹介したlibftdi_write_dataですが、どういうわけかsizeに384(= 512 - 128)より大きい数字を指定するとusb bulk write failedと出て落ちます。
FT245のRX FIFOは128byteなのでこれは関係なさそうです。
全く意味が分からないのですが、そういうもののようです。


これはしかたがないので「そういうもの」と割り切って次に進みます。

いよいよバウンダリスキャン。といっても先秋の復習です。先秋はAVRでCPLDをバウンダリスキャンしてID読み出しやらSAMPLEコマンド発行やらをやりましたが、今回はFT245RLをPCから叩いてCPLDをバウンダリスキャンしてみます。PCからサクッと弄れるので前より簡単です。

以下、FT245のパラレル出力のうち下位4bitがそれぞれ(TDO, TCK, TMS, TDI)に接続されているものとします。TDIはBoundaryScanのデイジーチェーンの入力で、TDOは最終出力です。
つまりFT245から見るとTDOだけ入力、他は出力です。

バウンダリスキャンは、TEST_LOGIC/RESETのステートに行くとIR(instruction register)がID読み出し(IDCODE命令)にセットされるので、そのままSHIFT_DRステートに行けばIDが出てきます。
IDCODEは32bitで、(Version(4bit), PartNumber(15bit), ManufactureID(11bit), 1(fixed, 1bit))となっているようです。

では、複数のデバイスでデイジーチェーンを構成している場合、全てのデバイスのIDを調べるにはどうすればいいのかを考えてみます。

デフォルトではIRはIDCODEが選択されています。したがってDRには32bitのIDが入っています。
ただし、IDCODEを持たないデバイスもあり、その場合BYPASSコマンドが実行されます。
BYPASSコマンドでは、内部の1bitのbypass registerが使われますが、その初期値は0です。
一方、さきほどIDCODEのフォーマットを示しましたが、最下位bitは1固定です。

そこで入力としてIDCODEとして使われない値を入れ、その値が出力されればデイジーチェーンを一巡したといえます。
IDCODEとして使われない値として、0000 1111111 1というのがよく使われるようです。
JDECはManufactureIDに下位7bitが全て1のIDを割り当てないことに由来します。

まとめると、
1. SHIFT_DRに遷移
2. TDIから000011111111をlsb firstで流し込む
3. 読み出した値が1なら続く31bitはIDCODE。ただしその次の10bitを見て入力したパターンならそこで終了。読み出した値が0ならバイパス。

これで簡単にデイジーチェーン上のデバイスの個数が分かります。
これについては
バウンダリスキャン入門がわかりやすいです。

あとはこれを実装するだけですが、TMSとTDIのタイミングが微妙に分かりにくいです。
バウンダリスキャン講座で詳しく解説されています。

ただ、SHIFTDRの2clk目から入れるというのはどうもしっくりこないのでもう少し合理的な考え方を示します。
デバイス側でデータが取り込まれるのはTCKの立ち上がり時です。
したがってホスト側はTCKの立ち下がり時にTMS, TDIを変化させます。
そうするとホスト側にとってはTCKを立ち下げるタイミングでSTATEが変化すると考えた方が制御がわかりやすくなります。
↓ホスト側のSTATE


STATE      IDLE|SEL|CAP|  SHIFTDR

TMS          ̄ ̄ ̄\___________________

TCK         _/ ̄\_/ ̄\_/ ̄\_/ ̄\_/ ̄\_/ ̄

TDI         ___________〔D0〕〔D1〕〔D2〕

TDO         _____________〔D0〕〔D1〕〔D2

bufferpos               0 1 2 3 4 5

# monospaceって日本語文字:半角英数字の幅の比が2:1とは限らないんですね。めんどくせー

下のbufferposってのはSYNCBBモードで重要なものです。
SYNCBBではwriteするとその時点でのpinの状態をスキャンしてreadをかけるとその値が出てきます。
したがって上の場合では、出力として
txbuffer[0] = D0(TDI)
txbuffer[1] = TCK | D0(TDI)
txbuffer[2] = D1(TDI)
txbuffer[3] = TCK | D1(TDI)
みたいにすると、rxbuffer[2]以降の偶数番の入力だけを使えばいいということがわかります。

libftdiを使ってみる

.13 2011 FT245-CPLDwriter comment(0) trackback(0)
fwriteは内部でバッファリングしていて、そのバッファが一杯になると実際の書き込みが行われます。
したがって
for (i = 0; i < 1000; i++)
	fwrite(fp, buf + i, 1);

でも
fwrite(fp, buf, 2000);

でも速度にほとんど差はでないはず。
# fcloseするまでfwriteが実行されなくて焦ったという経験は一度くらいあるはずです。

しかし、ftdi_write_dataの方はそうはなっていないようで、
for (i = 0; i < 1000; i++)
	ftdi_write_data(&ftdic, buf + i, 1);

ftdi_write_data(&ftdic, buf, 1000);

では圧倒的な速度の差がありました。基板上にLEDをつけているので、実際にポートにアクセスしている時間が違うのが分かります。timeコマンドの結果でも100倍くらいの速度差が出ました。
ftdi_writeに関しては内部バッファの容量を制御するコマンドがありますが、それはftdi_writeで書き込まれたサイズが内部バッファのサイズを越えた場合にのみ機能するもので、そうでない限り複数に分けて呼ばれたものを一回のパケットにまとめるという処理は行われないようです。
内部バッファが一杯になるまでIO処理が行われないというのはいろいろとまずいのでこれはこれでいいと思いますが、もう少し頑張れば、「buffer not emptyかつftdi_write_dataが呼ばれた」ときくらいパケットを一つにまとめることもできるんじゃないの?という気はします。

続いて読み出しです。ここで結構苦戦しました。
ポートの状態を常にスキャンして送られても、そのデータがどの時点のものなのか分からないので扱いに困ります。
そこでいろいろ調べたところ、FT245RLのデータシートでSYNCBBというモードがあることを知りました。
通常のBitBangモードでは普通のパラレルポートと同じようにデータが送られてくるのですが、データシートによると
The FT245R supports synchronous bit bang mode. This mode differs from asynchronous bit bang mode in that the interface pins are only read when the device is written to. ということでこれは便利です。
このモードを使うには、ftdi_set_bitmode(&ftdic, 0x07, BITMODE_SYNCBB)とかすればいいです。

# ちなみにBitBangModeの場合、チップ上のWR, RDなどの入力は無視されます。これはBitBangではポートへの書き込み、読み出しのタイミングがこれらの入力とは関係なくボーレートによって決まるためです。

これで読み出しができます。
とりあえずFT245RLをlibftdiで叩くやり方が大体分かったのでBoundaryScanをやる前に一回ここで切ります。

UbuntuでFTDIのチップを使う

.11 2011 FT245-CPLDwriter comment(0) trackback(0)
先秋の続きです。CPU実験が終わり、X純正のFPGAライターとかも返却してしまったので今FPGAで何かやろうと思ったらまずはライターが欲すぃくなります。OSもUbuntuに乗り換えたので今日は環境を整えるところからです。

1. FTDI社のホームページからDrivers/D2XXと進みます。そこから適切なドライバを落として解凍し、READMEの通りにします。これで使えるようになりました。
2. 使い方:gccのオプションに少々追加するものがあります。コンパイル時にftdiのライブラリをリンクする必要があるので、
% gcc -lftd2xx main.c
のようにします。

続いて、以前に紹介したcpld_progが実際に動くことを確認します。
% sudo prog_cpld main.svf
Can't open USB device.
というエラーが出ます。最初のFT_Openのところですでに躓いてしまっているようです。
# しかもsudoつけないとセグフォるっていう。エラーが起きたら何やってもいいってことはねーだろ。

さんざん試行錯誤したのち、こいつはダメだということでFTDIのライブラリを消しました。
代わりに入れたのがオープンソースのlibftdi。
libftdi-devとかlibftdi1とか入れればいい感じ。
使い方:gccのオプションに-lftdiをつけてリンクすればいいようです。

さて、prog_cpldはFTDI純正ドライバの関数を使っているのでそこを書き換えないといけないのですが、他にもbitファイル由来のsvfファイルが書き込めなかったりするのでこの際もう一回boundary scanのプロトコルを復習して全部書き直してしまおうと思います。というわけで続きは明日。

そういえば今日は地震で大変でしたね。M8.8だとか。うちは6階なので結構揺れました。僕の部屋はもともと地震が起きた後のような感じの散らかりっぷりなので地震が起きてもこれ以上崩れるものもなく、大して被害はありませんでした。ただ、結局ガスが出なくて風呂に入れなかったのがちょっと不便でした。まぁ火事とかなくてよかったよ。ほんと。

外はボロいブロック塀がいくつか落下していたりしていましたが、その程度で済んだようです。
地震の時、地面に垂直に立っているものがあると何となく安心してしまいますが、ブロック塀は本当に危険です。

今回は家にいたのでよかったのですが、今回の地震でケータイの必要性を感じたので近いうちに契約しようと思います。
# 以前高一くらいのときに地震で帰宅途中に電車が止まったときはそこから家まで12km走りましたけど。

◎  ω   ◎ < 早く僕と契約してよ!

各社からこんな声が聞こえてきそうですが、この際スマフォにしてしまうのも悪くないかなーとか色々考えてます。
ケータイあれば遠征の時、写真撮りながらつぶやいたりとかできて面白そうですし。
 HOME 
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。