2007年06月18日

製作とavrdude改造..そしてチューニング

SERJTAG FT245RL USBパラレル変換モジュール版 を製作し、動作の確認を行った。確認には avrdude に対応させて、AVR へのプログラミングを行って確認している。だいたいの機能は確認できたはずだが、8bit 単位でない転送など確認できていない機能もある。

製作編


ほぼ、前回の記事の回路図通り、違う点は 2 つで、PWREN# を無接続にしたのと、電圧調整用ダイオードのうち 2連になっているところを 1 つにした。

例によって、SW-55 に入れるつもりで作ったのだが ... (作ってから)モジュールが高すぎて、入らないことがわかった。IC ソケットを使わないようにしないと、13mm (20mm - 上 2mm/下 5mm) に収まらないので注意。

ケーブルは、カモン USB-05を切って作った。


シールドも使うと コネクタ付きの線が 5 本になるので、JTAG/AVR ISP に使える。コネクタが 1pin 単位なので、いろんな PIN 配置に対応できて便利。しかも安い。千石で通販しているし、店頭でも売っている。PC関係のパーツ屋でも扱っていると思うが、千石だと 263円と安い。
ちなみに、3.3V 出力を外に出している。全部で 50 mA しか流せないが、AVR プログラミング用には十分。

avrdude 改造

作ったからには、AVR のプログラミングもできるようにしたい。テストも兼ねて、avrdude を改造することにした。

avr910.c と usbasp.c の2つをにらみながら serjtag.h と serjtag.c を作った。シリアルの制御と初期化でのコマンド発行は、 avr910.c をベースにして、chip_erase の処理は、usbasp.c をベースにしたうえで、他の処理も参考にした。avrdude は、基本的に cmd を使って いろんな処理をしてくれるので、paged_write と paged_load に注力すればよく、作るのは楽だった。( paged_write/paged_load を作らなくても動く。ただし、汎用の cmd() を使うのですごく遅い。) 。ただ、paged_write と paged_load は、FLASH だけではなく、EEPROM にも対応しなければならない。EEPROM までまじめに作るのは面倒なので、avr.c の共通ルーチンをベースにした。

新しいプログラマを組み込むには、Makefile.in を修正するのはもちろんだが、それ以外に config_gram.y , lexer.l , avrdude.conf.in にも修正が必要だった。

テストとデバッグ

動かすまでは大変ではあったが、ざっくり省略。1つだけ教訓がある。

それは、ぎりぎりの SCK クロックで動かすなということ。途中でコマンドが化けて FUSE BIT を書き換えてしまうかも知れない。

avrdude は良くできていて、最後に FUSE BIT をチェックしてくれて、FUSE BIT が(意図に反して)書き換わってしまったら、元に戻すか聞いてくれる。メッセージをよく読まないでアボートしてしまうと、高電圧プログラミングでないと戻せない状態になってしまう場合がある。(ターゲットに ATtiny44 を使っていたのだが、アボートしてしまい、書き込みできない状態にしてしまった。2 つダメにして、そういうことかと後で気が付いた。)

簡単にダメにしてしまったのは、もうひとつ原因がある。CPU クロックを 1/8 にする設定がデフォルトだが、これだと 1MHz で、ISP 書き込みのクロックは、1/4 の 250kHz を超えないようにしなければならない。 1/8 にするのを DISABLE にすれば、2MHz まで OKで、高速化しない限りなかなかその周波数にまではいかない。

ちなみに、HSV で元に戻すボードとプログラムはあるので、ダメにした ATtiny44 は元に戻せるはずだが、ちょっと面倒。

チューニング

paged_write と paged_load を作らないバージョンは、4072 バイトの書き込みに、66.54 秒、ベリファイに 63.13 秒もかかった。1バイトの書き込みに 4バイトの送信と受信をするので、(転送量はともかく)受信の遅延のために時間がかかるのだ。(計算すると遅延は、15 ms ぐらい)

さて、paged_write と paged_load を すなおなコードで作ってみた。書き込み時間は、1.72 秒、ベリファイ時間は、4.66 秒になった。SERJTAG では、SPI の結果を(デバイスが)送信しないようにできるため 1ページ分は受信が必要なく送信を連続してできる。なので、書き込みは結構速い。しかし、ベリファイが予想以上に遅い。

そこで、paged_load については、
AVR-CDCの性能(2)で書いたように ソフトウェアパイプライニングを使ったチューニングをすることにした。

ちょっと長いが、ポイントとなるコードを載せて説明しようと思う。


static struct serjtag_request {
int addr;
int bytes;
int n;
struct serjtag_request *next;
} *req_head,*req_tail,*req_pool;

static void put_request(int addr, int bytes, int n)
{
struct serjtag_request *p;
if (req_pool) {
p = req_pool;
req_pool = p->next;
} else {
p = malloc(sizeof(struct serjtag_request));
if (!p) {
fprintf(stderr, "can't alloc memory\n");
exit(1);
}
}
memset(p, 0, sizeof(struct serjtag_request));
p->addr = addr;
p->bytes = bytes;
p->n = n;
if (req_tail) {
req_tail->next = p;
req_tail = p;
} else {
req_head = req_tail = p;
}
}

static int do_request(PROGRAMMER * pgm, AVRMEM *m)
{
struct serjtag_request *p;
int addr, bytes, j, n;
char buf[128];

if (!req_head) return 0;
p = req_head;
req_head = p->next;
if (!req_head) req_tail = req_head;

addr = p->addr;
bytes = p->bytes;
n = p->n;
memset(p, 0, sizeof(struct serjtag_request));
p->next = req_pool;
req_pool = p;

serjtag_recv_j(pgm, buf, bytes + 3, 0);
for (j=0; j<n; j++) {
m->buf[addr++] = buf[3 + 4*j + 3];
}
return 1;
}


受信のリクエストを出したら、put_request() を使って、受信処理(のパラメータ)を登録(キューイング)する。で、do_request() は、キューから1つ取り出して、受信処理を行う。

put_request()を出したその後ですぐ do_request()を call するならば、普通の処理と変わらない。コードで書くならこう。

for (i=0; i< LOOP_COUNT; i++) {
:
put_request(...);
do_request(...);
}

そこから、最初の N 回は、put_request()を出しておくが、do_request() を call しないようにする。そして、最後に do_request() が 1 を返す間 call してキューイングされた分を刈り取る。

for (i=0; i< LOOP_COUNT; i++) {
:
put_request(...);
if (i >= N) do_request(...);
}
while (do_request(...))
;

こうするわけだ。これで送信と受信が N ずれる。

N を 0 から増やしていくと .. ベリファイ時間は次のようになった。

   N
0 4.66 秒
1 2.79 秒
2 1.93 秒
3 1.50 秒
4 1.22 秒
5
6 0.94 秒
7 0.87 秒
8 0.48 秒
9 0.28 秒
10 0.27 秒
11
12 0.27 秒
13
14 0.27 秒


こうすることで、4.66 秒が、最終的に、0.27 秒まで高速化できたのだ。1バイト書くのに 32bit の送信と受信をしている。JTAG 的には 片側 480 Kbps (帯域的には、960kbps) が出ていることになる。FT245R の BitBangMode の想定性能の 2 倍ぐらい?(8Mbps / 16 / 2 = 250 Kbps ) が実効性能として出ているし、目標とした性能(500kbps 〜 1Mbps) のレンジにかなり近い。性能的には満足だ。

ちなみに 480kbps 出たとして、玄箱の FLASH を書き換えるとすればどうなるか ...
480000 / (507 * 3) = 315 (byte/sec) 。... 64KB 書き換えるのに 209 秒 、 4MB なら 3.7 時間。
JTAG Cable としても、使える範囲に入ってきていると思う。


ベリファイはこれだけ速くなるが、書き込みの高速化は難しい。1ページ書き込み毎に delay を保証しないといけない。write を直接出すのではなく、バッファリングすることで、1.72 秒が、1.28 秒にまで短縮したが、それ以上は無理そうだ。

なお、これらのテストは、Linux (2.4.31) で行った。avrdude のパラメータは、

avrdude -pt44 -c serjtag -P /dev/ttyUSB0 -b 3000000 \
-B 4000000 -U flash:w:usb910j44.hex

としている。-b は、ボーレートの指定。あまり関係なさそうだが、avrdude も改造して、できるだけ大きくした。-B は、SCK のクロック値。4Mhz 以上に設定すると、(プロトコル上) 一切の遅延をしないようになる。(といっても、テストのために、serjtag のプログラム側で nop() などで遅延して、2MHz 以上にしないようにしている。serjtag は USI を使っていて、本当は 4Mhz。)ちなみに、-B を指定しないと、250 kHz 以下になり、8Mhz RC クロックの 1/8 の設定でも問題ないようにしている。

ちなみに、usb910j44.hex は、USB910版。ATtiny44 の typeB の回路ベース。FLASH が足りないので、 AVR910 プロトコルは サポートしていない。すでに USB910 と言えないが、それはさておき、USB910版は、書き込み 7.00 秒・ベリファイ 7.19 秒だった。詳しくは次回に書く予定。


以上のプログラムは、serjtag-0.2.tar.gzに置いた。avrdude-5.3.1 へのパッチも同梱している。
posted by すz at 23:13| Comment(0) | TrackBack(0) | SERJTAG
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント: [必須入力]

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
この記事へのトラックバックURL
http://blog.sakura.ne.jp/tb/30760401
※ブログオーナーが承認したトラックバックのみ表示されます。

この記事へのトラックバック