2009年12月07日

usb162用USBaspLoader

前記事で mega328p用USBaspLoader が動いたと書いたが、続いて usb162 用のUSBaspLoader を動かそうとしている。

こっちの方を先にやっていた訳だが、ライタとか不安があったので、実際のテストは躊躇していた。mega328p でいろいろやったので、手順的にも不安がなくなった。

ちなみに、AE-UM232R を使った FT232R Bitbang ライタは、今こんな状態。



LED を CBUS 2 に付けてみた。RESET と同期させるつもりだったが、CBUS Bitbng は、Close したら 入力(HI-Z)になってしまうようで、avrdude の実行と同期するだけ。CBUS 以外なら RESET するまで 点灯するはず。

あと、CBUS 4 を 12MHz クロック出力に設定して、ケーブルをつないだ。 mega328p で、水晶に設定したときに役にたった。(XTAL1 に接続すると、ISP が使える) ... が、普段は使わない。ちょっと、ピンをひっかけられるようにしている。

さて、usb162 用のUSBaspLoader だが最初全然動かなくて困った。ビルドの方法とか見直したあと、ヒューズビットを見直したところ、なんとか動き出した。

ヒューズビットは次のようにした。

# Fuse extended byte:
# 0xf6 = 1 1 1 1 0 1 1 0
# | \-+-/
# | +-------BODLEVEL 0..2 (110 = 2.7 V)
# +-----------HWBE (0 = HWB enable )
# Fuse high byte:
# 0xd1 = 1 1 0 1 0 0 0 1<-- BOOTRST (reset vector == 0 but using HWB)
# ^ ^ ^ ^ ^ \+/
# | | | | | +------- BOOTSZ (00 = 4k bytes)
# | | | | + --------- EESAVE (preserve EEPROM over chip erase)
# | | | +-------------- WDTON (if 0: watchdog always on)
# | | +---------------- SPIEN (allow serial programming)
# | +------------------ DWEN (debug wire enable)
# +-------------------- RSTDISBL (reset pin is enabled)
# Fuse low byte:
# 0xff = 1 1 1 1 1 1 1 1
# ^ ^ \ / \--+--/
# | | | +------- CKSEL 3..0 (crystal - lowpower)
# | | +--------------- SUT 1..0 (boottime - 65 ms)
# | +------------------ CKOUT (if 0: Clock output enabled)
# +-------------------- CKDIV8 (if 0: divide by 8)


水晶は、周波数が安定するまで時間がかかるそうなので、もっとも立ち上がりに時間がかかるモードにしてみた。あとは、chip erase で EEPROM をクリアしないようにしたのと、BOD の設定を 3.0V → 2.7V にしたぐらい。1/8 分周は Off -- ライタで書くのに不便なので。
    ついでに書いておく。efuse を 0xfe にして、hfuse を 0xd0 にすると、常に ブートローダが起動する。ブートローダでなんのチェックも入れないと、まずはブートローダを動かして なにかの操作をし、次にアプリケーション起動という手順にできる。デバッグ中などは、こっちのほうが便利なこともある。

いまの状態では、read 系しか動いていない。... が、まぁ デバッグしていけば、まともになっていくだろう。

ちなみに、2KB に収まりそう。DFU ブートローダが 4KB だったので、ちょっと嬉しい。

ところで、最初から書き込まれている DFU ブートローダは、悪くはない。FLASH や EEPROM を読めないようになっているが、いったん chip erase して再度書き込むとFLASH や EEPROM が読めるようになるようだ。たぶんロックビットをチェックして、保護しているのだろう。Linux でも使えるし。あと、ヒューズビットの設定を微妙に変えても問題なく動作するし、水晶が 16MHz でも 8 MHz でも動く。

それでも、USBaspLoader にするのだ。ソースもっていると改造できるし、avrdude で使えるので操作を統一できる。2KB にできたら、それも魅力かも。
    mega328p の USBaspLoader では、2KB にしたとしても 開いたエリア (0x7000 - 0x7800) に書き込むことはできないと書いた。
    その領域は NRWW 領域というもので、書き込んだりすると CPU が停止する。それが、VUSB(ソフトだけの USB) だと都合が悪い。
    usb162 でも、0x3800 - 0x3c00 の領域は NRWW 領域であることは変わらないのだが、usb162 では割り込みを使わなくとも USB の通信が出来る。実際 usb162 用 USBaspLoader は割り込みを使っていない。おそらく NRWW 領域に書き込んでも問題ない。 だから 2KB にした場合、アプリケーションで使える領域を増やすことができる。ついでに書いておくと、本当は、cli/sei も必要なく、プログラムサイズを少々減らすこともできる。
    ただ、増えた 2KB を 機能拡張で使おうと思っている。機能拡張とは、シリアル FLASH からのロード。それはまた別途。

とりあえず、動いたみたい。ものは、usb162-0.2-wk12.tar.gz

サイズは、WinAVR-20090313 でビルドして 1930 バイト。gcc3 だとなぜか 2072 バイトと 大きくなる。

ちなみに、flash への write でブートローダを保護していない。実用で使う場合、ロックビットで保護する必要がある。
-- 保護していないといっても、自己書換えはできない。単に チェックの分節約しているだけ。

    ロックビットの設定は、avrdude では、デフォルト が 0x3f と見える。これを 0x2f にすると、ブートローダ領域が書き込みから保護される。


USBaspLoader にする最も大きな理由を書き忘れていた。

自作ボードの SRT162 は、スライドスイッチで HWB を切り替えるのだが、それと連動して ISP コネクタの RESET の部分が RESET と SS が切り替わる。

どちらにしても、プログラムを書き換えるには、スライドスイッチを PGM 側にしないといけないのだが、そうすると microSD を使う場合、プログラムの書き込みで いちいち microSD を取り外さないといけない。

それがとっても面倒なのだ。面倒だけでなく、コネクタがゆるくなったりする心配もある。

... というわけで、いままで microSD のテストがちっとも進んでいなかったのだ。これでようやく microSD のテストが簡単にできるようになる!。

    補足:
    efuse = 0xfe , hfuse = 0xd0, (+ lock 0x2f)
    とすれば、いちいち avrdude を -E reset オプションで 立ち上げないと アプリケーションが動作しないわけだが、
    microSD の取り外し/取り付け よりはよっぽど良い。
posted by すz at 00:21| Comment(0) | TrackBack(0) | USBasp関係

2009年12月06日

mega328p用USBaspLoader

mega88系ボードの設計の記事の基板を組み立てた。



とりあえずの目的は、avrdude-serjtag のテストと 改造 USBaspLoader の動作確認。

いままでは、ライタのテストでいちいちブレッドボードで組む(面倒)か、SRT162 ボード(壊すのが怖い)を使っていたのだが、これからは気軽にテストできる。

それはおいておいて、USBaspLoader を次のように改造した。


  • 起動の条件を、PD7 が L レベルでかつ、リセットボタンでリセットした時にして、ブートローダから抜ける条件を USBasp のDISCONNECT コマンドを受け取ったとき(のみ)にした。

    オリジナルの動作は、PD7= H で抜けてしまうので、ジャンパとかが必要だったが、これで、タクトスイッチも使えるようになる。

    avrdude-serjtag04e.zip に付属のバイナリ (avrdude.exe) は、-E reset オプションのときだけ DISCONNECT コマンドを 発行するように改造してあって、何回か avrdude を起動する場合便利なようにしている。

  • PC3 を USB D- の 1.5k Ωプルアップに接続して、最初に 切断→接続。最後に切断するようにした。

    USB D- の 1.5k Ωプルアップを VCC に接続すると、PC が 接続を求めてきて、それに反応しないと USB の電源を切られてしまう。

    常に USB 接続をするつもりはないので、プルアップの切断が必要になった。ボードの方もパターンカットして対応した。

  • PB0 に H で点灯するようLED を接続する(ボードでは IDLE LED)と、コマンド実行中点灯。

  • fuse や signature の読み込み、flash の バイト単位の読み込みに対応。(ISP コマンドエミュレーション)

    fuseは、avrdude が最初に読み込み、最後におかしくなっていないか確認するので、一応対応。書き込みはできないし、P/PA 専用。

    signature は、必要ではないが、fuse と一緒に対応。
    (実は、デバイスの定義を実際と違うようにしたとき(後述)ちょっと便利)

    flash の バイト単位の読み込みは、dump で使うらしい。端末モード(-t) を結構使っているので対応。

  • SETISPSCK コマンドに対応。

    bitrate を設定するコマンド。
    warnning がでるのが、なんとなくイヤなので対応。... といっても OK の値を返すだけでなにもしない。

  • usbdrv(VUSB) を vusb-20090822 と差し替え。

    --- なんか 16MHz 時のバグ対応が入っている。


これだけ機能を入れると (WinAVR20090313 では)2KB を超えてしまう。(現在 2252 B) そうすると 必然的に KB のブート領域がある mega328p 専用になる。2kB に収める努力はしているが、なかなか難しい。
--- mega328p 以外使うつもりはないので、まぁいいか。

    ちなみに、2KB 以内に出来ても mega328p では、0x7000 - 0x77ff までの領域は、書き換えられないはず。書き換えようとすると CPU が停止するので、USB の受信ができず困ったことになりそうだ。
    要するに mega328p にはなんの恩恵もない。

ヒューズの設定。
    mega328p

    #---------------------------------------------------------------------
    # Fuse extended byte:
    # 0x05 = 0 0 0 0 0 1 0 1
    # \-+-/
    # +-------BODLEVEL 0..2 (101 = 2.7 V)
    # Fuse high byte:
    # 0xd0 = 1 1 0 1 0 0 0 0<-- BOOTRST (boot reset vector at 0x7000)
    # ^ ^ ^ ^ ^ \+/
    # | | | | | +------- BOOTSZ (00 = 4k bytes)
    # | | | | + --------- EESAVE (preserve EEPROM over chip erase)
    # | | | +-------------- WDTON (if 0: watchdog always on)
    # | | +---------------- SPIEN (allow serial programming)
    # | +------------------ DWEN (debug wire enable)
    # +-------------------- RSTDISBL (reset pin is enabled)
    # Fuse low byte:
    # 0xff = 1 1 1 1 1 1 1 1
    # ^ ^ \ / \--+--/
    # | | | +------- CKSEL 3..0 (crystal - lowpower)
    # | | +--------------- SUT 1..0 (boottime - 65 ms)
    # | +------------------ CKOUT (if 0: Clock output enabled)
    # +-------------------- CKDIV8 (if 0: divide by 8)


    一応推奨。efuse は、00 のままでも良い。lfuse は、起動時間を 出来るだけ遅いもの (65 ms) にしたほうが良さそうと思ったため。

    注) mega328p と mega88(p)/168(p) ではヒューズビットのフォーマットが違う。↑はあくまで、mega328p 用。


さて、これを WinAVR20090313 でビルドしているのだが... -mmcu=atmega328p で動かない。

試しに -mmcu=atmega168 にすると OK 。HEX ファイルを比較しても、ちょっとしか違わないのだが ... とりあえずは mega168 としてビルトしている。

改造したもの一式を USBaspLoader-suz-002.zip に(とりあえず)置いておく。が、ドキュメントが全然ないので注意。

    usbasp 自体も移植するつもりで入れてある。が、コンパイル通しただけのもの。
    ついでに、USBasp の Windows ドライバ一式も。


追記: WinAVR-20060421 (gcc-3.4.5) で ビルドしたところ、2078 バイトになった。なんか惜しいので LED の処理を ちょっと変更して、2048 バイトのバージョンを作成した。動作確認は、mega328p の アドレス 0x7000 のものだが、アドレスを 0x7800 , 0x3800 にずらしたものも ついでに作成した。 mega168p でも動くに違いない。

さらに、ついでに mega88p 用も作成。こちらは動作するかどうかわからない。

ものは、USBaspLoader-suz-003.zip 。ドキュメントが全然ないのでとりあえずというのは変わらない。

ちなみに、必要な回路。赤が オリジナルからの追加分。LED はなくても良いけど出力に使われる。対応しているのは、16MHz の mega328p / 168p のみ。

    あ、ツェナー付けるような回路を書いてるけど、実際は VCC を 3.3V にして、ツェナーなし。本当は、3.3V なら 12MHz が望ましいのだけれども、無理やり 16MHz で動かしているのも注意!。

posted by すz at 18:16| Comment(0) | TrackBack(0) | USBasp関係

2009年11月22日

USBaspLoader 移植メモ

USBaspLoader の移植についての覚書。

だいぶ出来てきたので、ブートローダ関係についてまとめておこうと思う。(USBaspのプロトコルについては前記事でまとめる)

ブートローダの基本動作



ブートローダ領域をサポートしたAVR で、ブートローダを有効にすると、リセットベクタが、ブートローダ領域 に移動する。

USBaspLoader では、PORTD の BIT7 を pull-up した後、チェックして H レベル bit_is_set(PIND,JUMPER_BIT) なら、0 番地にジャンプして アプリケーションを実行するようになっている。また、リセットボタンでリセットしたとき以外 -- bit_is_clear(MCUCSR,EXTRF) のときも アプリケーションを実行する。

ブートローダを実行するときは、set_bit(MCUCR,IVSEL) することで、割り込みベクタ全部をブートローダ領域 に移動する。こういう機能があるおかげで、VUSB のような割り込みを使う機能をブートローダでも使えるわけだ。

bit_is_set(PIND,JUMPER_BIT)の状態になれば、ブートローダを終了して、アプリケーションを実行するようになっている。

bootloaderconfig.h で、BOOTLOADER_CAN_EXIT を 1 にしておくと、USBasp への USBASP_FUNC_DISCONNECT コマンドで ブートローダを終了することはできる。

  • Atmel DFU ブートローダとの違い

    リセットボタンでリセットしたときに、PORTD の BIT7 が Lだったときのみ ブートローダが動作するのは同じ。ただし、DFU ブートローダは、H になったからといって ただちに抜けるわけではない。

    BOOTLOADER_CAN_EXIT を 1 にして ブートローダの実行条件bootLoaderCondition()を 開始用と終了用の 2 つに分ければ Atmel DFU ブートローダに近くなるのかも。ただ、avrdude を 実行するたびに リセットボタンでリセットしないといけないかも。
    -- 実験してみて仕様を決めよう。

  • アプリケーションからのブートローダ実行

    USBaspLoader では、アプリケーションからのブートローダ実行も考慮しているようだ。

    実行すること自体は簡単で ブートローダ領域の先頭アドレスに jump すれば良い。

    ただし、ブートローダの実行条件をクリアしないとリセットと同じになってしまう。

    具体的には、JUMPER をセットした後、

       bit_set(MCUCSR,EXTRF) ;

    して jump 。JUMPER_BIT を 出力にして L レベルにする手もあるが、そうすると今度はブートローダからリセットなしに抜けられなくなる。


ブートローダのビルドについて



ブートローダは、開始アドレスがベクター領域ごとずれる。そういうものをどうやってビルドするかについて いろんなやり方があって、参考にしたものはみんな違う。


  • USBaspLoader の方法

    普通にコンパイルして、リンクのときに 以下のオプションでアドレスを指定。

    -Wl,--section-start=.text=3800
    または、
    -Ttext 0x3800


    hex ファイルは、まったく同じになるようだ。なら昔からある -Ttext 0x3800 で良さそうなものだが、なぜか誰も使っていない。

    AT90USB162 では、--section-start がエラーになる。..と書いたが間違い。ちゃんと使えた。

  • BOOTLOADER_SECTION を使う方法

    ソースコードで関数の宣言のときに例えば、

       void bootloader(uint8_t sync) BOOTLOADER_SECTION
               __attribute__((noreturn));

    という風に BOOTLOADER_SECTION を付ける。関数定義自体にも付ける必要があるようだ。

    リンクでのアドレス指定は次のようにする。

    -Wl,--section-start=.bootloader=3800


    そういうやりかたが出来るというのは分ったのだが、こうしてしまうとライブラリが使えないように思えるし、メリットは良くわからない。


ブートローダ エミュレーション



ブートローダ領域をサポートしない AVR で、ブートローダを作るには、どうすれば良いのだろう?

実用上はともかく、これができるとデバッグするのが楽。なぜなら、本物のブートローダが使えるから。

    www.mikrocontroller.net の "Bootloader" for ATTiny2313に 置いてある ATTiny2313_bootloader が 代表的なもの。ちなみに、上のリンクには、”48-instruction one-wire bootloader for ATTiny13/24/45/85” なんて話題もある。


まず、違うアドレスから実行するようにしないといけない。これは上で説明した。

次にリセットで、ブートローダに制御を渡すように 0 番地に本物のベクタを置かないといけない。

ブートローダ実行で、0 番地にアプリケーションのベクタが書かれた場合、元のデータを変更しないようにして、別のところに置くようにする。READ も対応して透過的にしないと ベリファイでエラーになる。

あと、自分自身を書き換えないように保護する必要もある。

ちなみに、AT90USB162 は割込みを一切使わなくとも USB の処理が出来る。リセットベクタだけ保護すれば良いので大分楽。また、ベクタは、2 Word なので、相対アドレスのRJMPではなく、絶対アドレスの JMP 命令を使う。これも処理が楽になる。

もっとも重要なことを見逃していた。ブートローダー領域でプログラム実行中でないと、SPM 命令でのフラッシュの書き込みが禁止される。アプリケーションから ブートローダー領域への call はできるようなので、いんちきは出来るかもしれない。ただ、そのいんちきをするためには、自作ブートローダーが動作していないといけないので、デバッグにはあまり役立たない。

    ついでに書いておくと、AT90USB162では、後ろの 4KB が ブートローダー領域のサイズにかかわらず NRWW 領域となってて、ここに書き込む場合は、CPU が停止する。AT90USB162はあまり関係ないのだが、3,4 ms 停止するので、応答性が重要な VUSB では問題が出るかも知れない。

    ATmega88p , ATmega88pa のデータシートを見てみたが、88/168 は、NRWW = 最大ブートローダ領域は、2KB 。328 はそれが 4KB になっているようだ。VUSB では 2KB でも厳しいし普通は NRWW = ブートローダ領域と決めてしまえば良いのだろう。

    この問題、解決するかも。↓で記載。



おまけ:gawk で作る 0 番地に置くベクタを作るツール



0 番地のベクタを ビルドしたプログラムから作りたいのだが、どうしたら良いのだろう?

MinGW を前提にすれば gcc も使えるので簡単なのだが..

WinAVR の utils\bin には、いろんな UNIX 系コマンドがある。perl はないが、gawk はあるので、これでなんとかしてみることにした。ちょっと長いがスクリプトだし、参考になる時もあるかも ... ということで載せておく。


BEGIN{
hex[0] = 0; hex[1] = 1; hex[2] = 2; hex[3] = 3;
hex[4] = 4; hex[5] = 5; hex[6] = 6; hex[7] = 7;
hex[8] = 8; hex[9] = 9; hex["A"] = 10; hex["B"] = 11;
hex["C"] = 12; hex["D"] = 13; hex["E"] = 14; hex["F"] = 15;
}
{
sum = 0;
len = hex2dec($1, 2);
sum += len;
x = hex2dec($1, 4);
sum += x;
addr = hex2dec($1, 6);
sum += addr;
addr += x * 256;
rtype = hex2dec($1, 8);
sum += rtype;
for (i=0; i<len; i++) {
data[i] = hex2dec($1, 10+i*2);
sum += data[i];
}
isum = hex2dec($1, 10+len*2);
sum += isum;
sum = sum % 256;
if (sum != 0) {
printf("line %d: ihex format error!\n",NR);
exit(1);
}
if (NR == 1) {
if (data[0] == 12 && data[1] == 9 * 16 + 4) {
addr = 0;
} else {
printf("line %d: data error!\n",NR);
exit(1);
}
}
if (NR == 1 || rtype == 1) {
print_ihex(rtype, addr, data, len);
}
}

function hex2dec(str, i, x) {
x = hex[substr(str,i,1)] * 16 + hex[substr(str,i+1,1)];
return x;
}

function print_ihex(rtype, addr, data, len, sum) {
sum = 0;
printf(":%02X%04X%02X",len, addr, rtype);
sum += len;
sum += addr;
sum += int(addr/256);
sum += rtype;
for (i=0; i<len; i++) {
printf("%02X", data[i]);
sum += data[i];
}
sum = sum % 256;
printf("%02X\r\n", 256 - sum);
return sum;
}


おまけ:DFU ブートローダ 1.05 の サブルーチン



逆アセンブルしたら、SPM を使う関数一式が見つかった。

このアドレスに直接 CALL することで DEBUG できそう。
で、自作するときは、最後の方の固定のアドレスに置いておく。

... というか、最後に JUMP テーブルがあるから、なにか公開された API かも。ただ、gcc 規約ではないので注意。

    gccの規約は、ELM: アセンブラ関数の書き方 (avr-gcc)が分りやすい。引数のレジスタが違うし、r16,r17 を使っているので、ラッパーで push/pop しないといけない。あと、0 にしておく r1 を壊している。0 に再設定しないと。

ところで、rww_set_enable() 相当らしき関数が、よくわからない。11 = 1011b を書いているが、データシートには記載なし。

あと、erase してwrite というのは、何? 先に fill しておいて、atomic にやるということ?

それはともかく、erase と write は、アクセスできるようになったら戻るようになっている。アプリーケーションから使っても問題なさそう。

1FF2 : 940C 1E70 JMP L1E70 ; erase and write
1FF4 : 940C 1E94 JMP L1E94 ; LPM なので略
1FF6 : 940C 1E9C JMP L1E9C ; LPM なので略
1FF8 : 940C 1EA4 JMP L1EA4 ; page_fill(addr, data);
1FFA : 940C 1E75 JMP L1E75 ; page_write(addr);
1FFC : 940C 1E86 JMP L1E86 ; page_erase(addr);
1FFE : 940C 1EAC JMP L1EAC ; lock_bits_set(lock_bits)

;page_write(addr);
1E75 : D03C L1E75: RCALL L1EB2 ; spm_busy_wait();
1E76 : 2FF1 MOV ZH,R17 ;
1E77 : 2FE0 MOV ZL,R16 ;
1E78 : E045 LDI R20,$05 ; WRITE
1E79 : BF47 OUT SPMCSR,R20 ;
1E7A : 95E8 SPM ;
1E7B : D036 RCALL L1EB2 ; spm_busy_wait();
1E7C : D012 RCALL L1E8F ; rww_set_enable();
1E7D : 9508 RET ;

; page_erase(addr);
1E86 : D02B L1E86: RCALL L1EB2 ;spm_busy_wait();
1E87 : 2FF1 MOV ZH,R17 ;
1E88 : 2FE0 MOV ZL,R16 ;
1E89 : E043 LDI R20,$03 ; ERASE
1E8A : BF47 OUT SPMCSR,R20 ;
1E8B : 95E8 SPM ;
1E8C : D025 RCALL L1EB2 ;spm_busy_wait();
1E8D : D001 RCALL L1E8F ;rww_set_enable();
1E8E : 9508 RET ;

;rww_set_enable();
1E8F : D022 L1E8F: RCALL L1EB2 ;spm_busy_wait();
1E90 : E141 LDI R20,$11 ;
1E91 : BF47 OUT SPMCSR,R20 ;
1E92 : 95E8 SPM ;
1E93 : C01E RJMP L1EB2 ;spm_busy_wait();

; page_fill(addr, data);
1EA4 : 2FF3 L1EA4: MOV ZH,R19 ;
1EA5 : 2FE2 MOV ZL,R18 ;
1EA6 : 2E01 MOV R0,R17 ;
1EA7 : 2E10 MOV R1,R16 ;
1EA8 : E041 LDI R20,$01 ; FILL
1EA9 : BF47 OUT SPMCSR,R20 ;
1EAA : 95E8 SPM ;
1EAB : C006 RJMP L1EB2 ;

; lock_bits_set(lock_bits)
1EAC : D005 L1EAC: RCALL L1EB2 ;
1EAD : 2E00 MOV R0,R16 ;
1EAE : E029 LDI R18,$09 ;BLBSET | 1
1EAF : BF27 OUT SPMCSR,R18 ;
1EB0 : 95E8 SPM ;
1EB1 : C000 RJMP L1EB2 ;


; spm_busy_wait();
1EB2 : 2E02 L1EB2: MOV R0,R18 ;
1EB3 : B727 IN R18,SPMCSR ;
1EB4 : FD20 SBRC R18,0 ;SPMEN
1EB5 : CFFC RJMP L1EB2 ;

1EB6 : 2D20 MOV R18,R0 ;
1EB7 : 9508 RET ;

; rww_busy_wait();
1EB8 : 2E02 L1EB8: MOV R0,R18 ;
1EB9 : B727 IN R18,SPMCSR ;
1EBA : FD26 SBRC R18,6 ;RWWSB
1EBB : CFFC RJMP L1EB8 ;

1EBC : 2D20 MOV R18,R0 ;
1EBD : 9508 RET ;
posted by すz at 17:19| Comment(0) | TrackBack(0) | USBasp関係

2009年11月20日

USBasp のプロトコル

USBasp は、USBのコントロール転送を使って通信する。コントロール転送については、とりあえず置いておいて どんなやり取りをしているのかについて、ちょっとまとめておこう。
    参考リンク
  • USBasp オリジナル (USB プログラマ)
  • USBaspLoaderUSBasp プロトコルブートローダ


大雑把に言ってしまうと、通信は 次の2つの やりとりになる。

    1) OUT ( PC → USBasp )

    PC → USBasp [ 制御情報 8バイト ]
    PC → USBasp [ 通信データ 0-200 バイト]

    2) IN ( USBasp → PC )

    PC → USBasp [ 制御情報 8バイト ]
    PC ← USBasp [ 通信データ 0-200 バイト]


8 バイトの制御情報は、USB の制御でも使われる。先頭の1バイトには、種別に関する情報が入っており、USBasp では、ベンダーの種別 を使用している。次の 1 バイトは、コマンド。後の 6 バイトは 基本的に自由に使える。USBasp では、次のようにコマンドを定義している。


    コマンド タイプ 通信データ長 制御情報(2-7)
    1 CONNECT IN 0 - - - - - -
    2 DISCONNECT IN 0 - - - - - -
    3 TRANSMIT IN 4 ISPCMD(4) - -
    4 READFLASH IN 0-200 ADDR(2) - - LEN(2)
    5 ENABLEPROG IN 1 - - - - - -
    6 WRITEFLASH OUT 0-200 ADDR(2) F+P LEN(2)
    7 READEEPROM IN 0-200 ADDR(2) - - LEN(2)
    8 WRITEEEPROM OUT 0-200 ADDR(2) F+P LEN(2)
    9 SETLONGADRESS IN 0 ADDR(4) - -
    10 SETISPSCK IN 1 CLK(1) - - - - -

    F+P: Flags + PageSz

    +-----------+-----------+-----------+-----------+
    | PageSz(H)| | | L|F | PageSz(L) |
    +-----------+-----------+-----------+-----------+
    | |
    | +---- isFirst Block
    +------- isLast Block

    READ/WRITE は、Pagesize 関係なしに 200バイトのブロックサイズに分割してデータを Recv/Send する。
    isFirst Block は、最初の転送であることを示し、isLast Block は 最後の転送であることを示す。
    最後の転送がきれいにページアラインになることは保証されないので、isLast のフラグを見て close 処理をしなくてはならない。
    PageSize は、上位の 4 bit 分が、Flags の 上位に来る。512B とか 256バイト以上の PageSize に対処するための苦肉の策のようだ。



この表でイメージは掴めるのではないかと思う。

これだけなら簡単なのだが、やっかいなのは、3 TRANSMIT 。これは、ISP コマンドそのものを やりとりするもので、(PCから見て) 4 バイトをデータを送り 4 バイトのデータを受け取る。

ブートローダで USBasp プロトコルをサポートする場合、どこまでサポートしたら良いかが微妙なのだ。

Warning を一切出さないようにするには、READ 系のほとんどと、EEPROM の Write をサポートすべきなのだが、それではコード量が増える。で、サボると どこまでもサボれる。強制オプションを付ければ シグネチャーの READ さえもいらない(はず)。

ISP コマンド



ISP コマンドでは、4 バイトを返却するが、意味があるのは最後の 1 バイト。


       不可能 推奨 必須
    CHIP ERASE 0xAC 0x80 - - △ ○ −

    READ 系
    READ FLASH (HI) 0x28 ADDR(2) - − ○ −
    READ FLASH (LO) 0x20 ADDR(2) - − ○ −
    READ EEPROM 0xA0 ADDR(2) - − ○ ○
    READ LOCKBIT 0x58 0x00 (0x00) - − ◎ −
    READ SIGNATURE 0x30 0x00 ADDR(1) - − ◎ ◎
    READ FUSE (LO) 0x50 0x00 (0x00) - − ◎ −
    READ FUSE (HI) 0x58 0x08 (0x00) - − ◎ −
    READ FUSE (EXT) 0x50 0x08 (0x00) − ◎ −

    WRITE 系
    WRITE EEPROM 0xC0 ADDR(2) DATA(1) − ○ −
    WRITE LOCKBIT 0xAC 0xE0 (0x00) DATA(1) − ○ −
    WRITE FUSE(LO) 0xAC 0xA0 (0x00) DATA(1) × − −
    WRITE FUSE(HI) 0xAC 0xA8 (0x00) DATA(1) × − −
    WRITE FUSE(EXT) 0xAC 0xA4 (0x00) DATA(1) × − −


最後のマークは、ブートローダでどこまでサポートするか/できるかの目安。

    不可能△: CHIP ERASE は、FUSE とか LOCKBIT は変更できないから

    推奨の◎:avrdude では FUSE とかチェックして変だと元に戻そうとするため。

    必須の◎:SIGNATURE ぐらいは読めないと面倒なため。しかし本当に必須というわけではない。


さて、usb162 をベースに ブートローダもどきを動かそうとしている。いまのコード:usb162-0.2-wk10.tar.gz

SD は諦めたわけではなく部品待ち。その間に USBasp のブートローダを組みこもうとしている。

一応ソースは共通。USBasp を動かしつつ CDC-ACM でデバッグしたり出来ている。

防忘をかねてちょっと説明しておくと ... bootloader というディレクトリでビルドすると、usb162aspbl.hex が出来る。

これは、開始アドレスを 0x2000 に移動してある。そのままでは動作しなくて、0x20cc に飛ばす リセットベクタ bootloader/bin/v.hex も書き込む必要がある。

書き込むと

    # avrdude -c usbasp -p usb162 -t

とかで avrdude が動く (Linux だけで確認)

で 8KB( 0x0000 〜 0x2000 )までの プログラムを FLASH に書ける(かも知れない)

リセットベクタの 4 バイト (アドレス 0 〜 3)を読み書きすると、EEPROM の 0x1f0 〜の 4 バイトに読み書きするように していて、元のリセットベクタを変更しないようにしている。

EEPROM にセーブした 情報を元に、アプリケーションを実行する機能はまだない。ちゃんと透過に見せているかどうかのテスト中。

bootloader-test というディレクトリでビルドすると、同じ usb162aspbl.hex が出来る。こちらは 0 番地から始まる普通のプログラム。CDC と くっつけていて、デバッグ用。FLASH に書き込みするのはマズイ。自分自身を書き換えてしまうので暴走するはず。ベリファイとか EEPROM の読み書きテスト用。

あと今までのプログラムは、test5 というディレクトリに移動。こちらは、MSC のテスト用。

実を言うといままでの USB162 は、コントロール通信での大量データ受信ができてなかった。USBasp のサポートで まともにしていこうと思っている。

  • USBasp

    USBasp ドライバのインストール (Windows)



    WinAVR には、ライタソフトの avrdude-5.6 と ドライバ(libusb)が同梱されている。ただし、USBasp の 定義ファイルは入っていないようだ。

    USBasp の 定義ファイルは、USBasp オリジナル の、bin/win-driver/libusb_0.1.12.1 にある、usbasp.inf と usbasp*.cat 。

    これを WinAVR の utils\libusb\bin\ にコピーする。

    で、USBasp をつないだときのハードウェアウィザードで、コピーしたディレクトリを指定すれば OK 。

    ちなみに、DFU ブートローダの Flip も libusb を使っている。場所は、c:\Program Files\Atmel\Flip 3.3.4\usb\

    現在は互換性が取れているようだが、将来どうなるか分からないので要注意

      現在使用中のバージョン
    • WinAVR-20090313 (avrdude 5.6)
    • Flip 3.3.4
    • usbasp.2009-02-28 (libusb_0.1.12.1)


    少々分かってきたのでメモ:

    libusb は、WinAVR に含まれているが、ビルドするために必要な usb.h と libusb.a は含まれていない。

    これは、http://sourceforge.net/projects/libusb-win32/files/ にある libusb-win32-device-bin-0.1.12.2.tar.gz に含まれている。  


    $ cp libusb-win32-device-bin-0.1.12.2/include/usb.h /c/MinGW/include
    $ cp libusb-win32-device-bin-0.1.12.2/lib/gcc/libusb.a /c/MinGW/lib


    これで USBasp が使える avrdude が MinGW で ビルドできるようになる。

    互換性について:libusb は、1.0 に移行しているが、Windows は 0.1 系を使うようだ。0.1 系の最新版が 0.1.12 で たぶんこれで打ち止め。互換性の問題は、主に 0.1.10 ⇔ 0.1.12 でおきるらしい。 0.1.12 になっていれば当面気にする必要はなさそう。

    で、バグ修正とかは、-1 -2 とサフィックスが付いてリリースされる。たぶん API は変わらないので使う側は変更しなくて良さそう。ドライバは -1 から -2 とかに上げても良さそう。

    あと libusb で、新規のデバイスをサポートする場合 inf-wizard を使うらしい。これも WinAVR に含まれている。

    フィルタドライバ:これをインストールすると 既にドライバをインストールしたデバイスと libusb で通信できる。

    こちらのやりかたでないと、CDC + USBasp のようなデバイスは制御できない。ただググってみてもトラブルの話しか出てこない。 --- あきらめた方が無難なようだ。
  • posted by すz at 19:15| Comment(0) | TrackBack(0) | USBasp関係