2009年12月11日

ボタン制御

SRT162 では、ボタンを付けられるようにしているのだが ... いままで使って来なかった。

そろそろ真面目に 使えるようにしようと思う。

ボタン周りは次のような回路にしている。


__
PC2 ------|>|-- R 3.3K--+----o o---- R 33K ----+
| |
| --+--
|
o
PD0


LCD と共用できるように、高い抵抗値の抵抗を使って pull-up/down する ように考えてこんな回路にした。

PC2 は、スイッチをセンスするときに H レベルにする前提。H レベルにしなければ、ボタンを押しても 影響がない。

さて、実際に使うことを考えてみると、LCD に アクセスした後の状態から pull-down で L レベルになるまで、時間がかかる。PD0 が入力容量を持っていて、RC ローパスフィルタになっているからだ。

入力容量 10pF と仮定すると、cut-off 周波数は、480 KHz 。1/2 周期の 1 μ秒(以下 μ秒→us) で ON → OFF が なんとかできることになる。

だから最短でも 1us 待って読み込む必要がある。1us というと 16MHz で 16 CLOCK 。意識してコーディングしないとまずそう。
(実際は、1us では不安で 10us ぐらい待った方が良い。)

一方、pull-up の方は、1/10 の抵抗値なので 時間も 1/10 。PC2 を H にしてから安定するまで 最短 0.1 us 。安全性を とっても 1us 。

とにかく、LCD を最後に使った時から 一定時間経ったことを 保証しないとまずいし、PC2 を ON してから後も 少々待った方が良い。

さて、上のような話とは別に チャタリング制御 はしなければならない。

定期的 に ボタンの状態を見て 8 回連続で L (もしくは H) なら ボタンの状態を変更する。

処理自体は簡単で、こんな感じでできる。


    uint8_t button_state;
    static uint8_t raw_button_state[8];

    uint8_t check_button() {
    uint8_t *p;
    int8_t i;

    bit_set(ENABLE_PORT, ENABLE_BIT);
    bit_set(ENABLE_DDR, ENABLE_BIT);
    _delay_us(1);
    p = raw_button_state;
    for (i=0; i<8; i++,p++) {
    *p <<= 1;
    if (bit_is_set(PIN_BUTTON,i)) {
    *p |= 1;
    }
    if (*p == 0) {
    bit_clear(button_state,i)
    } else if (*p == 0xff) {
    bit_set(button_state,i)
    }
    }
    bit_clear(ENABLE_DDR, ENABLE_BIT);
    bit_clear(ENABLE_PORT, ENABLE_BIT);
    return button_state;
    }


これの使い方だが、こんな感じ


    TCCR0B = 0x4; // 1/256 free running
        :
        :
    (メインループ内)
    if (bit_is_set(TIFR0, TOV0)) {
    button = check_button();
    button_tmp = button ^ button_old;
    if (bit_is_set(button_tmp,0) && bit_is_set(button,0)) {
    usbcdc_put_pstr(PSTR("BUTTON B(1)\r\n"));
    }
    if (bit_is_set(button_tmp,1) && bit_is_set(button,1)) {
    usbcdc_put_pstr(PSTR("BUTTON Y(2)\r\n"));
    }
    if (bit_is_set(button_tmp,4) && bit_is_set(button,4)) {
    usbcdc_put_pstr(PSTR("BUTTON R(3)\r\n"));
    }
    button_old = button;
    bit_set(TIFR0, TOV0);
    }


(at90usb162 では)8 bit タイマカウンタの タイマー0 を 1/256 でフリーランさせて 、オーバフローしたら check_button() を実行。前の状態は、上位レイヤーで覚えておいて 、状態が変化したら、なにか処理をする。

16MHz なので、オーバーフローは 1/256/256 の 244Hz -- だいたい 4ms 間隔。8 個連続の検出だから 検出までに 32 ms かかる。チャタリングに引っかかると、さらに時間がかかる。

ここで、LCD を最後に使った時から 一定時間経ったことを 保証しないといけない話に戻る。

上の チャタリングの制御が入る前提だと、8 回連続誤動作しないと、ボタン状態を間違うことにならない。

そうすると、たまに間違うかも知れないという程度なら問題が起きない。10 us 待つのを 2us とか にしても大丈夫かもしれない。

usb162 に ボタン実装したバージョン:usb162-0.2-wk13.tar.gz

このバージョンは、Linux で、2G の SD をMass Storage Class として認識できるようになった。

    サイズはちゃんと認識できて、READ も OK 。ただし、WRITE は動かない。あと、HARD_SPI も動いていない。SDHC は全部できたあとにテストする予定で 挿してもいない。

Windows で試したところ全然ダメ。CDC も使えないので、ボタンを押すと eeprom にログを書くようにしてデバッグ中。今の環境は、リセットすると、USBaspLoader が立ち上がるので すぐ eeprom の内容が見れる。だいぶ便利になった。

... ログ見ていると なんか WRITE してくる。まずは、WRITE を通さないと。

追記:なんか動いた。(usb162-0.2-wk14.tar.gz

ずっと WRITE を調べていたのだが、READ もバグってた。... まぁよくあること。

READ を直したら、なんか動いたみたい。ただ、認識されるのがすごく遅い。まだまだ何かありそう。

それはともかく、カードの抜き差しに対応してみた。活線挿抜には対応したわけでなく、プロトコル上の対応の話。

Windows も Linux も READY かそうでないかに関わらず 定期的にTEST_UNIT_READY を発行して来るようなので そこで初期化・終了処理を入れてみたところ、それっぽく動いてる。-- カードを壊すおそれがあるので、実用では使えない。

あと、タイムアウトとかエラー処理も少々入れた。これで大分マシになったはず。

HARD_SPI もテスト。実は、関係ないかと思って CS に SS を割り当てていない。データシートを見たら SS は出力にしないとダメなことが分かった。

でも、これでも、全然動かない。-- 試しにクロックを 8 MHz から 2 MHz に落としてみたところ動いた。ノイズ対策全然してないし、やむを得ないと思ったのだが、ひょっとすると、直列に 100 Ωを入れていたり LED までいれているのが原因かも。--- ちょっと適当すぎたか。

追記:SDHC もなんか動いた。(usb162-0.2-wk15.tar.gz

ChaN さんの MMCの使いかた を見ながらデバッグしてたのだが、SDHC がどうにも動かない。困り果てて ググったら SH7144でSDカードコントローラを試作という記事を発見。

なんと、”注意:ダミークロックは、各コマンドの終了後には、必ず1回(1バイト)だします。” という記述が!

半信半疑で mmc_command() で、spi_disable() → spi_enable() している所で間に入れてみたところ、なんか動きだした。

ただ、まだ問題があって、Linux で何故か I/Oエラーになる。どうも READ のようで、READ 中に timeout で I/O エラーにしたら CMD12 を発行して READ コマンドを止めるようにしたら OK になった。... ただ対処したら I/O エラー自体が出なくなった。... ? なぜ?

たぶんまだまだ問題がありそうなのだが、とりあえずは動いた。Windows で試しても やたら時間がかかることもなくなった。

もうちょっと。

... かと思ったのだが、全然 Write が出来ていないことが判った。SD はちゃんと Write できる。が、SDHC は 1 セクタだけ成功して、2 セクタ目でエラー。困った。

追記:とりあえず、困ったことはサテ置いて、そろそろ 0.2 として FIX したい。... というわけで整理中。(usb162-0.2-wk17.tar.gz

CDC のみのサンプルと、MSC のみのサンプルを作れるようにした。 CDC+MSC も作れるが テスト用の位置づけ。だいたい、Windows 用と Linux 用でファームウェアが別になるから テスト用にしか使えない。

あと、ブートローダ。単独で機能するものと、テスト用に CDCもつけたもの。CDC を付ける場合も Windows で使うには いろいろ問題ありで、Linux 向けになりそう。

ついでなので、性能チューニングもしている。SPI のクロックは 4MHz で予定の半分(上限 500KB/sec)なのだが、Read/Write ともに 300 KB/sec ぐらい。8MHz で動くように対策したら 500KB/sec ぐらいになりそう。

ところで、Digikey で ATmega32u2 が 1 個単位で発注できるようになっていた。上限 が 32KB になるのは嬉しいが、ものを手に入れないと対応できない。

    09/12/18 : 在庫ありになってる。一個 387円。... 買いたい。

    あ、chip1stop で、ATmega32U4が 1個単位で買える ようになった。出荷日予定日は 12/28 だそうだ。こっちの方が欲しい。エンドポイントが 6 つあるのが、まず嬉しい。USB 用メモリも 832バイトと 潤沢。さらに ADC や 高速(64MHz) 10bit PWM とか もある。それに、ATmega32U2 のようなエセmega ではなく、乗算命令もある。


posted by すz at 22:32| Comment(0) | TrackBack(0) | SRT162

2009年11月25日

コネクタを付けた

コネクタを付ける。-- これは大きな問題なのだ。ピンヘッダにするか、ピンソケットにするのかよく悩む。付けた種類によって、将来使うであろう相手側のコネクタも決まってしまう。しかも、やりなおしは出来ない。

それに加えて SRT162 の事情もある。ボタンモジュールと液晶が(予定していた方法では)付かなくなる。 コネクタを付けるということは、ただの開発用マイコンボードにするということになる。

液晶とかは、2号機でやると割り切るとして ... コネクタの先に何を付けたいか ...

  • microSD -- いま作っている MSC 用。
  • ライタ -- いま作っている ブートローダ用
  • DAC23 ボード -- DAC23 ボードを作ったらこれにも付けたい。

悩んだ末に、シングルピンソケット(低メス)20P(1x20) を使うことにした。


microSD ソケットと コネクタ





お手軽に microSD-SDアダプタを使ってみた。

ケーブルは、aitendo の ピンヘッダ用接続ケーブル[CB-PH10P-250] を使った。必要なのは 6pin だけなので、両脇の 茶赤と白黒を最初に分離して、切断。切断した残りは、ライターで使うのだ。

で、ソケットを L 形のピンヘッダに接続。



これが、低メスにそのまま付く。

こんなのでいいのか?とも思うのだが、まぁやってみよう。

AE-UM232R ライタ





FT232RL USBシリアル変換モジュール[AE-UM232R] を ライタ専用にしてみた。

ピンが邪魔なので、外してL 形のピンヘッダに換装。そのときに熱を加えすぎて、3 PIN 方のパターンを剥がしてしまった。仕方ないので 3V3 からジャンパ。

次に足を切断→絶縁。ピン自体を外したいのだが、ちょっと無理。

最初、ピンに直接 リボンケーブルを半田つけしていたのだが、どうにも うまくないので、サブ基板を付けて半田づけしなおした。

接続は、ft232r1 で定義したもの (decimila 用と同じ)。以前書いた FT245R/FT232R で avrdude の配置とは違う。

VCC は、VIO からとる。こうしておくと、3.3V or 5V をターゲットに供給することもできるし、ターケットの電源を使うことも出来る。


配線図にすると こう。ft232r0 と ft232r1 の 2 つのチャネルがあるうちの ft232r1 にした。これは dicimila と同じ配線。下に CB4 と CB2 があるのだが、CB4 は、クロック出力にしておいて、外部クリスタルのモードにした AVR に書くときに XTAL1 にクロックを供給しようと思う。CB2 は普通 RX LED 。これを MProg で I/O mode に設定しておくと、CBUS Bitbang 専用になる。そうしておいて、avrdude-serjtag で RDY LED として使えるようにしようと思う。接続は、RX LED と同じでないと困るから

CB2 -- LED -- 電流制限抵抗 -- GND

にしようと思う。

    以下:検討時のメモ

    実をいうと AE-UM232R を使うのは初めて。記事を最初に書いた時点では製品がなかった。その後も特に使う必要はなかったので、そのままになっていた。使うついでに環境を整備していこうと思う。

    Linux 上で avrdude-serjag を avrrdude-5.8 に移植したものは動いた。MISO と MOSI を逆に考えていたので混乱した。いつも混乱してしまうのだが、Master In Slave Out = MISO 。で、Mega の SPI では、どちらが Master になるかは状況によって違う。ISP の場合は、プログラマ側が Master 。ちなみに Tiny の USI では 常に Slave (MISO = DO) 。例えば Mega 同士をつなぐ場合 MOSI 同士をつなぐが、Tiny 同士ではクロスしてつなぐ。

    ところで、終了時の RESET 。常に RESET するのも 変にアプリが起動してしまい困ると思うので どうしようか悩んでいた。

    par.c を見ていたら -E というオプションがあることが分かった。

    -E reset

    を指定したら、RESET を H にして RESET がかかるようにしようと思う。何回か実行する場合 最後に 指定して 書き込んだプログラムを実行する ..といった使い方ができる。ちなみに -x という指定も(コードを書けば)利用できる。.. ただこっちは、拡張設定で、実行の度に変えるという使い方ではないようだ。

    avrdude へのパッチ一式と Windows バイナリを avrdude-serjtag04.zip に置いた。

    これはまだテスト中。同名でファイルを置き換えるかも。注意!

    どうも、ピン配置が気に入らない。FTDI BitBang AVR-Writerの配置は、diecimila として登録してある。使っているピンは、全部デフォルト入力。-E pinz で終了時 RESET 以外入力に戻すようにしたので、大きな問題はないはず。

    で、diecimila 以外のピンは基本 通信に使うわけだ、そのピンは TxD(O),RxD(I),RTS(O),DTR(O)。やっぱりこの 4本で、TxD = mosi , RxD = miso , RTS = sck, DTR = reset がいいんじゃないかと思えて来た。もちろん breakout の定義は残すのだが、Tiny 系などで ISP で書き込んだ後そのまま通信したいときは、こっちを使った方が便利そうなきがする。なぜなら、Tiny 系の USI の SPI は マスタでもスレーブでも MOSI が常に入力(DI)。Mega 系の SPI は スレーブのとき MOSI が入力。困るのは、マスターのときだけだが、PC と通信するなら スレーブにしかならないから困らない。

    (1)もちろん、Mega 系で シリアルで通信する場合 diecimila の設定を使ったほうが便利。... なんというか 2つのチャネルとして綺麗に分けて 場合によって使い分けるようにする.. というか。そういうのを標準として定義しておきたい。

    (2)あと、libftdi もサポートしておきたい。... ちょっと見た感じ open 以外は、単純置き換えが出来そうな気がする。i386 以外のマシンがあるから ソースがなく対応できない FTDI ドライバは嫌いなのだ。

    (3)あと是非やっておきたいのが、PORT の指定方法の改善。今は ft0-ft9 を指定するようにしているが 複数あったときにどれを指定するのか分からない。間違えたときに副作用があるから面倒そうな気がする。プロダクト名 か シリアル番号を port名 として指定できるようにしておきたい。ちなみに、プロダクト名は、MProg ユーティリティで変更できるので、分かりやすい名前を付けることが出来る。

    avrdude へのパッチ一式と Windows バイナリを avrdude-serjtag04a.zip に置いた。

    (1),(3) はたぶん出来た。(2) は ダメだった。コードは作ってみたものの、最初の reset の L/H/L すら動かない。それが解決したとしても、FTD2XX と同じように動かすのは無理だと分かった。
    すぐには作れない。パス。

    あと、pinz のオプションをなくして 常に 終了時は RESET 以外入力にするようにした。

    (1) については、こんな設定

    ft232r0 : FT232R channel 0
    miso : D1/RXD
    sck : D2/RTS
    mosi : D0/TXD
    reset : D4/DTR

    ft232r1 : FT232R channel 1
    miso : D3/CTS
    sck : D5/DSR
    mosi : D6/DCD
    reset : D7/RI

    breakout : sparkfun FTDI Basic Breakout
    miso : RXI (2)
    sck : CTS (5)
    mosi : TXO (3)
    reset : DTR (1)

    diecimila : Arduino Diecimila or clone (same as ft232r1)
    miso : CTS X3(1)
    sck : DSR X3(2)
    mosi : DCD X3(3)
    reset : RI X3(4)

    ft245r : sample configration for FT232R/FT245R (same as ft232r0)

    普通は、チャネル1 を使って シリアルはあける Diecimila と同じ使い方を 推奨。Tiny 系で そのまま通信したい場合のみ チャネル0。

    あーダメダメだ。デバッグコードが残っている。conf のサーチもダメ。失敗。(→ FT245R/FT232R で avrdude (2)に続く)


SRT162 基板改修





内部シリアル FLASH の配線が間違っていたので ソフト SPI しか使えなかった。コネクタを付ける機会に修正。これで、USART を使うハード SPI が使えるようになった。

どれぐらい高速化できるか楽しみ。

... これは一発で動いた
    結果

    READ WRITE
    ソフト SPI 140 kB/s 36.6 kB/s
    ハード SPI(1) 413 kB/s 78.9 kB/s
    ハード SPI(2) 526 kB/s 84.9 kB/s
    ※)消去は 64KB 単位に変更
    (1) SPI と同じ 制御
    (2) USART のダブルバッファを前提にした 制御

SPI の 理論性能が 1MB/sec で、コマンド処理とか USB転送してこの値なのは、まぁがんばった方だと思う。
posted by すz at 07:07| Comment(0) | TrackBack(0) | SRT162

2009年11月24日

DPFmate の通信

ミニ フォトフレームなんかで使われている DPFmate はドライバなしで、画像データを送受信したり、時刻を合わせたりしている。

いったいどうやっているのか?

たまたま SnoopyPro-- Usb Sniffer for Windows というのを知ったので、ちょっと覗いてみたところ ... buffer の先頭に 55 53 42 53 とか 55 53 42 43 とか見覚えのあるデータがならんいる。

これは文字列で USBS と USBC 。前に書いたが Mass Storage Class のパケットだった。

で、SCSI のコマンドを見ると 0x4A 。適当にいくつか見たが同じだった。ググってコマンド一覧をしらべたところ、GET EVENT STATUS NOTIFICATION だった。-- 明らかに READ 系だから Write 系は別のものを使っているのかも知れない。

Windows や Linux で SCSI コマンドを発行するのは、割と簡単らしい。SCSI READ BUFFER でググると結構情報が得られる。

READ BUFFER/WRITE BUFFER とか READ LONG/WRITE LONG とかを使ってプロトコルを定義できるようにして、専用アプリと通信できるようにするのも面白いかも知れない。

posted by すz at 20:02| Comment(0) | TrackBack(0) | SRT162

2009年11月11日

Mass Storage Class の検討(2)

前記事追記からの続き。ようやく Mass Storage Class (以下 MSC)のコードが 動いたので チューニングをしてみた。すこし 一般的な話題になってきたので、追記をやめて別の記事にした。

まず、どういう観点でなにをチューニングしていくかについて、簡単に説明しておこうと思う。


  • 1. RAM の使用量の削減

    AVR は RAM 容量が少ないので、RAM の使用量を減らすことは重要。特に ライブラリ的なものでは アプリケーションが作りにくくならないように出来るだけ使用量を減らすようにすべき。

  • 2. プログラムサイズの削減

    プログラムサイズもそんなに余裕があるわけではない。ブートローダが 4KB 使っているので、全部で 12KB 。少しでも減らしておかないと、アプリケーションが作りにくくなる。

  • 3. MSC の READ/WRITE の性能チューニング

    無駄なコードを 削減していけば、性能も上がる傾向にはある。ただ、性能を上げるためには、あえてコードを追加する場合もある。
    そういう例を紹介しようと思う。



RAM の使用量の削減



シリアルにデータを送るコードで

    usbcdc_puts("\r\n");

というようなコードがある。これは既にダメダメなのだ。

AVR では文字列は、FLASH 上に 元データが配置され、(main の前の)スタートアップで FLASH 上のデータを RAM にコピーする。要するに 文字列を普通に使うだけで、FLASH と RAM の 2 つを消費する。

せめて FLASH だけにデータを置きたい。そうするためには、PSTR() マクロ を使う。こうやって FLASH に置いたデータはメモリと同じようにはアクセスできないので __LPM() などのマクロを使う。

具体的には次のようなコードに変更。

    void usbcdc_put_pstr(const char *str) {
    uint8_t ch;
    while ((ch = __LPM(str)) != 0) {
    usbcdc_putc(ch);
    str++;
    }
    }
    :
    :
    usbcdc_put_pstr(PSTR("\r\n"));


あと、ログ用のコードとバッファ。今はデバッグのために生かしてあるが、まとめて削減できるように ifdef などで 切れるようにしておく。

プログラムサイズの削減



MSCでは、32bit の変数がいくつか必要になっている。AVR では 32bit の処理は効率が悪い。8bit の処理で済ませられないか工夫する。無理な場合でも 32bit の処理をする同じようなコードがあれば1つにできないか工夫する。

こうやって 32bitの処理を減らすと コード量が随分減るのだ。

第一のケースの実際例:

msc_cbw.cbw.trans_len.u32 という変数が転送バイト数を示すのだが、READ/WRITE 以外では、転送量は 256 バイト以内。

    large_trans = msc_cbw.cbw.trans_len.ub[1]
    | msc_cbw.cbw.trans_len.ub[2]
    | msc_cbw.cbw.trans_len.ub[3];

とやっておいて、例えば INQUIRY では large_trans の場合エラーにしてしまう。ちなみに、msc_cbw.cbw.trans_len は、union で、32 bit の u32 と 16bit の配列 u16[2] あと 8bit の配列 ub[4] の定義をしている。同じデータ を 違うアクセス方法にするのは、ちょっと不安だったので volatile も付けている。

    case SC_INQUIRY:
    if (large_trans) goto ill_req;
    msc_trans_proc = msc_trans_inquiry;
    break;

で、INQUIRYの処理(msc_trans_inquiry) では、1 バイトの変数 msc_cbw.cbw.trans_len.ub[0] で処理する。

第二のケースの実際例:

    改善前:
    static void msc_trans_skip() {
    if (msc_cbw.cbw.flags & 0x80) { /* Bulk IN */
    if (usbmsc_can_putc(1)) {
    while (usbmsc_can_putc(1) && (msc_cbw.cbw.trans_len.u32 > 0L)) {
    usbmsc_putc(0);
    msc_cbw.cbw.trans_len.u32--;
    }
    }
    } else { /* Bulk OUT */
    while (usbmsc_can_getc(1) && (msc_cbw.cbw.trans_len.u32 > 0L)) {
    usbmsc_getc();
    msc_cbw.cbw.trans_len.u32--;
    }
    }
    }

    改善後:
    static void msc_trans_skip() {
    while (msc_cbw.cbw.trans_len.u32 > 0L) {
    if (msc_cbw.cbw.flags & 0x80) { /* Bulk IN */
    if (!usbmsc_can_putc(1))
    break;
    usbmsc_putc(0);
    } else {
    if (!usbmsc_can_getc(1))
    break;
    usbmsc_getc();
    }
    msc_cbw.cbw.trans_len.u32--;
    }
    }


if 文を loop の外に持っていくのが、C での常識。なのではあるが、あえて loop の中に if 文を入れて 32 bit の処理を共通にして減らす。これだけの違いで なんと 132 バイトもコードのサイズが減るのだ。(gcc3 の場合 、gcc4 では 78 バイト)

MSC の READ/WRITE の性能チューニング



改善前のコードは次のようになっていた。


    static void msc_trans_read() {
    while (usbmsc_can_putc(1) && (msc_cbw.cbw.trans_len.u32 > 0L)) {
    usbmsc_putc(serflash_proc(0));
    msc_cbw.cbw.trans_len.u32--;
    }
    if (msc_cbw.cbw.trans_len.u32 == 0L) {
    serflash_close();
    return;
    }
    }


これの何をどうチューニングするのか? 疑問に思う人もいるかも知れない。結果を先に書くと ...


    static void msc_trans_read() {
    uint8_t i;
    while (usbmsc_can_putc(32) && (msc_cbw.cbw.trans_len.u16[0] > 0)) {
    for (i=0; i<32; i++) {
    __usbmsc_putc_nc(serflash_proc(0));
    }
    msc_cbw.cbw.trans_len.u16[0]--;
    }
    if (msc_cbw.cbw.trans_len.u16[0] == 0) {
    serflash_close();
    return;
    }
    }


こう。

あらかじめ、32 バイト分の処理ができるのを確認しておいて 、いっきに処理する。

もとの usbmsc_putc は内部でチェックが入って 処理できない場合は xxx_poll を call して待ち合わせる ... みたいになっているのだが、チェックは不要なので単純化でき、さらに単純化したことで inline 関数にできる。

また、32 バイト単位の処理にしたので、msc_cbw.cbw.trans_len をあらかじめ 5bit シフト(1/32) にしておいて、デクリメントで済ます。さらに.. 1/32 にすることで、msc_cbw.cbw.trans_len が 16bit で 2MB まで表現できるようになるため、32 bit 処理をせずに 16bit で済ませられるようになる。

    今回のケースではサイズ自体が 1MB なので 転送長は必ず 16bit に収まるわけだが ... たとえば SD などを使った場合でも大丈夫なのか? ... というと 実はよくわからない。
    ただ、標準的な最大の転送長は 128KB あたり。64KB には収まらないのは確実だが、2MB という上限なら 大丈夫ではないかと思う。

バッファーを ダブルバッファーにする設定とか他の改善もしているのだが... serflash_proc(0) を 定数の 0 にして READ だけの性能を測定したところ

    # dd if=/dev/sdb of=/dev/null bs=512 count=2048
    2048+0 records in
    2048+0 records out
    1048576 bytes (1.0 MB) copied, 1.27792 s, 821 kB/s

ここまで行った。パケット長が 32バイトなので、このあたりが限界かも知れない。

ところで、serflash_proc(0) を使う正規の READ の場合は、

    # dd if=/dev/sdb of=/dev/null bs=512 count=2048
    2048+0 records in
    2048+0 records out
    1048576 bytes (1.0 MB) copied, 11.4399 s, 91.7 kB/s

と一気にしょぼくなる。今は ソフト SPI なので いたし方ない。といっても 最初に動いたときは、59.6 kB/s だったので、1.5 倍ぐらいにはなっている。

本来なら USART を使った SPI にする予定だったのだが、基板の配線間違いで ソフト SPI にせざるを得ない状況。

ここまで性能が出たので、基板を改修して USART を使った SPI を試したくなっている。

ということで、そろそろ 2号機を組もう。

サイズの削減状況(gcc3)




    text data bss dec hex
    6602 76 269 6947 1b23 改善前
    6272 0 269 6541 198d 改善後
    5988 0 76 6064 17b0 改善後 , log なし

data が 76 バイトなくなって text が 330 バイト減った。MSC 以外に CDC や USBの基本処理があるので、MSC 関係は 全体の 5割前後なので まぁがんばったと言えよう。log もばっさり切ると メモリの使用は 76 バイトにまで減る。
ちなみに、gcc4 ( gcc version 4.3.2 (WinAVR 20090313)) の場合:

    text data bss dec hex
    6740 76 269 7085 1bad 改善前
    6344 0 269 6613 19d5 改善後
    5840 0 76 5916 171c 改善後 , log なし

不思議なことに、gcc3 よりサイズが大きかったのが、最終的には gcc3 より小さくなってしまった。

今回のコードは→ usb162-0.2-wk6.tar.gz

追記1:MSC の デバイス API の検討

今の MSC は、シリアルFLASH 専用で もっとも効率よく作ろうと考えて設計している。

さて、これをベースに 違うデバイスをサポートしたり デバイスの追加が出来るようにしようと思う。

もちろん、機能拡張したからといって 性能は落としたくないし、コードもあまり増やしたくない。

結構悩んだのだが... 結局次のようにすることにした。

もともとコマンド解析は switch 文で行っているのだが、解析した結果、データ転送を行う関数を 登録するようになっている。

だから、デバイス固有の処理のうち データ転送部分はまるごと デバイス側に移動できる。

移動する関数は、まずは READ_10/WRITE_10 。関数の場所を移動するだけなので、性能については心配しなくて良くなる(はず)。

あとは、共通処理が多いか/デバイス専用処理が多いかで決める。

微妙なのだが、デバイス専用処理が多いものとして、INQUIRY, READ_CAPACITY の関数を 移動することにした。

次の問題は、どうやって これらの関数を登録させるか ... 。

コードを載せてしまうとこんな感じ。

    static void serflash_devcall(uint8_t sc_lun, uint8_t sc_cmd) {
    switch (sc_cmd) {
    case SC_INQUIRY:
    msc_trans_proc = serflash_trans_inquiry;
    break;
    case SC_READ_CAPACITY:
    msc_trans_proc = serflash_trans_read_capacity;
    break;
    case SC_READ_10:
    serflash_open(SERFLASH_READ);
    serflash_seek(msc_trans_offset.u32,SEEK_SET);
    msc_trans_proc = serflash_trans_read;
    break;
    case SC_WRITE_10:
    msc_trans_proc = serflash_trans_write;
    break;
    default:
    break;
    }
    }

    void msc_serflash_init() {
    serflash_init();
    msc_devattach(serflash_devcall);
    msc_devattach(serflash_devcall);
    }


共通の処理をやった後で、serflash_devcall を CALL して 関数を登録させる。READ など初期化処理が一部あるものも、そのときに実行する。

もちろん、serflash_devcall は直接 CALL するのではなく、関数を登録させるようにする。上の例だと 2 回登録しているから、LUN 0 と 1 の 2つのディスクとして見える。Linux では 期待どおりに動いた。

ちなみに登録する関数 msc_devattach() はこんな感じ

    int8_t msc_devattach(void (*func)(uint8_t,uint8_t)) {
    int8_t ret;
    if (msc_maxlun >= MSC_MAXLUN)
    return -1;
    ret = msc_maxlun;
    mscdev[msc_maxlun++] = func;
    return ret;
    }

配列に関数を登録するだけだが、配列の INDEX が LUN を示していて、戻り値として 割り当てた LUN を返す仕様。(一応 2枚のカードを扱うようなドライバを作れるように)

最後になってしまったが、これで何をしようとしているか ... というと SD のサポート。

SD のコードは、ChaN さん の

を参考にさせてもらおうと思う。

ポートについては、外部デバイス接続用の CONN2 を使う。

    CONN2
    1 VCC(3.3V)
    2 GND
    3 PC5/OC1B (NPN OC)
    4 NC
    5 DEV_VCC (3.1V)
    6 PB3/MISO (100 ohrm)
    7 PB1/SCK (100 ohrm)
    8 PB2/MOSI (100 ohrm)
    9 PB4/T1 or RESET (100 ohrm)
    10 GND

配線を間違えてなければ、ハード SPI が使えるはず。

実際に作ると、API 的な不備がいくつか出てくるはず。つくり終えてはじめて API が FIX する。

今回のコードは→ usb162-0.2-wk7.tar.gz

追記2: SD/MMC ドライバの検討

ChaN さん の コードは、SDHC に対応しているので 参考になるのだが、他のコードとかも見てどれぐらい簡易なものにできるか検討している。

SD/MMC では、6 バイトの固定長のコマンドを使う。6 バイトの内訳は、1 バイトのコマンド、4 バイトの アーギュメント、1 バイトの CRC。いくつかのコードを見てみたのだが ... 大体 コマンドを発行する関数があり、パラメータとして コマンドと uint32_t の アーギューメントを渡す仕様が多いようだ。

アーギュメントが意味を持つのは、READ/WRITE の オフセット指定と、初期化の一部で、その他のコマンドでは 普通 0 。

どうも コード効率が悪くなるような気がするので、このあたり工夫してみようと思っている。


  • 基本方針
    コマンドを発行する関数を作るのは同じだが、パラメータは 1 バイトにする。

    1) READ/WRITE の オフセットは、変数に覚えていて、パラメータにフラグ(CMD_MASK_LBA) を設定することで指定する。

    2) 定型のパラメータは、6 バイトまるごと を FLASH の配列に置く。これを指定する場合、パラメータに フラグ(CMD_MASK_CONST)を設定して、配列のオフセットを指定する。

    3) それ以外のコマンドは、コマンドの番号 を指定する。この場合、アーギュメントは、すべて 0 。

こんな感じ。

これをベースに組み立てていけば、アクセス自体は、なんとかなるのだろう。

    これは、どうもやりすぎみたい。

    caller が 4 バイトの定数をパラメータに追加するコストは、4 命令8バイト。call する所は、20 ヶ所より少なくなる見込みで、全部で 160 バイトより少ない。

    対応コードもある程度量があるし、逆効果になるかも。


さて、コードを見ても良くわからないことがいくつかある。

ひとつは、カードの容量をどうやって知るのかということ。もうひとつは、カードの名前みたいな 文字列を INQUIRY で返したいのだがどうやってそれを知るかということ。

後者は、単に凝りたいだけなので、必要性は薄いが、前者は できるだけ ちゃんとしたい。

調べてみると後者は、16 バイトの CID に含まれていることが判った。CID の読み出しは、CMD10 を使い シングル・ブロック・リードと同じような手順でできる。

問題は CID の中身だが、こんな感じらしい。(用語は適当)

    1 バイト: Vendor の ID (バイナリ)
    2 バイト: Vendor? /OEM の ID (ASCII)
    5 バイト: 製品名 (ASCII)
    1 バイト: 製品のリビジョン (バイナリ)
    4 バイト: シリアルナンバー (バイナリ)


このあたりを使って INQUIRY のデータにしたらどうかと思う。

次は問題の前者。これは 、16 バイトの CSD に含まれている。CSD の読み出しは、CMD9 を使い シングル・ブロック・リードと同じような手順。

CSD のフォーマットは 2 種類ある。2GB までのSD は CSDv1 で、先頭のバイトが 0x00 。SDHC は CSDv2 で、先頭のバイトが 0x40 。容量の計算は、CSDv1 の方がややこしい。ちなみに、MMC は、先頭のバイトが、10xxxxxxb で、CSD フォーマットのサイズ関係は、CSDv1 と同じ。

  • CSDv2

    C_SIZE : オフセット 7(バイト)からの 3バイトを Bigendian で見た値。
     ※ 24 ビットのうち上位 2 bit は別フィールドだが 現在は 0

    容量 = (C_SIZE + 1) x 512 KB

  • CSDv1

    C_SIZE : [73:62] の 12 ビット
    C_SIZE_MULT :[49:47] の 3 ビット(< 8)
    READ_BL_LEN: [83:80] の 4 ビット (< 12)
     ※ 先頭のビットは 127

    容量 = (C_SIZE + 1) x 4 x (2 ^ C_SIZE_MULT) x (2 ^ READ_BL_LEN)

CSDv1 はバイトアラインさえされてなくて、コード書くのも説明するのも面倒。

それはともかく、SD カードスロットもまだ接続していない。基板に適当にコネクタ付けて 後で困るのも嫌だし ... どうしようか悩み中。

あと、コードは 今回はなし。

追記3:ハード SPI とか

実をいうと ハード SPI を使うのは初めてだったりするので、ちょっと調査中。

初期化は、おまじないだから、気にしないことにして ... ソフト SPI 相当の送受信コードならすごく簡単。

    SPI の場合:
    uint8_t spi_write(uint8_t c) {
    SPDR = c;
    while(bit_is_clear(SPSR,SPIF))
    ;
    return SPDR;
    }

    USART の場合:
    uint8_t spi2_write(uint8_t c) {
    UDR1 = c;
    while (bit_is_clear(UCSR1A,RXC1))
    ;
    return UDR1;
    }


ただこのコードは無駄に待ち合わせが入るので、おもしろくない。


    for (i=0; i<32; i++) {
    __usbmsc_putc_nc(spi2_write(0));
    }

今は READの転送の部分が、こんな感じになっているのだが、inline とか使った最速のコードのアセンブラは次のもの。


    ldi r25,lo8(0)
    .L4:
    sts 206,__zero_reg__  2 <<< 転送開始
    .L3:
    lds r24,200 2
    sbrs r24,7 1/2
    rjmp .L3 2
                    <<< 転送完了確認
    lds r24,206 2
    sts 233,r18 2
    sts 241,r24 2
    subi r25,lo8(-(1)) 1
    cpi r25,lo8(32) 1
    brne .L4 1/2


for ループの部分は、10 命令(最速ケースで 16 CLOCK)。だが、転送時間 16 CLOCK を待ち合わせる。

転送をオーバラップさせることで、さらに高速にしたい。


    void spi2_send(uint8_t c) {
    UDR1 = c;
    }

    uint8_t spi2_recv_send(uint8_t c) {
    uint8_t r;
    while (bit_is_clear(UCSR1A,RXC1))
    ;
    r = UDR1;
    UDR1 = c;
    return r;
    }

    uint8_t spi2_recv() {
    while (bit_is_clear(UCSR1A,RXC1))
    ;
    return UDR1;
    }

    spi2_send(0);
    for (i=0; i<31; i++) {
    __usbmsc_putc_nc(spi2_recv_send(0));
    }
    __usbmsc_putc_nc(spi2_recv());


こんな風にして次の転送の開始を出来るだけ早くする。


    ldi r25,lo8(0)
    .L13:
    lds r24,200 2
    sbrs r24,7 1/2
    rjmp .L13 2

    lds r24,206 2
    sts 206,__zero_reg__ 2 <<< 次の転送開始
    sts 233,r18 2
    sts 241,r24 2
    subi r25,lo8(-(1)) 1
    cpi r25,lo8(31) 1
    brne .L13 1/2


ループ部分の命令数は同じだか、後ろの 5 命令分が転送とオーバラップするので高速化できる。

ここまでは、シングルバッファである SPI と共通。ダブルバッファーを活かすとどうなるか ....

実は簡単で、spi2_recv_send(0) を spi2_write(0) に置き換えれば良い。そうするとループ部分は結局最初のコードと同じになる。

多分転送が完全にオーバラップする。sbrs r24,7 にも引っかからないはずで、1ループ 16 CLOCK -- 完璧に最速。

前にも書いたが、こういうやり方には名前がついていて、ソフトウェア・パイプライニングという。覚えておくといいかも。

追記4: SD 対応中

SD のコードを書いているのだが ... ちょっと困った。

基本待ち合わせをしないよう ステートマシンとして設計しているわけだが、SD カードでは 、長時間 BUSY になったりする。

また、エラーがいつでも起きる可能性がある。ちゃんと状態遷移を設計しないとまずい。

    ちなみに ... シリアルFLASH の場合は、長時間 BUSY というのはあるが、消去と WRITE の後だけで、(不完全ながら) 対処はできている。エラーについては、初期化が完了さえすれば エラーを考える必要はない。

    不完全と書いている理由は、転送終了後に後処理を入れられないため。ここは API を変更して、後処理を入れられる構造にしないとダメ 。


さて、SD カードについて ... まずは長時間 BUSY になるケースのまとめ

  • 初期化 : 初期化が終了すると、初期化コマンドのレスポンスが (0x01) → (0x00) になる。この待ち合わせで 数百MS になる場合があるとのこと。

  • Write の後の BUSY : 性能測定の経験からいうと 100 MS ぐらいは普通にある。普通のコードは、コマンド発行前に BUSY チェックをしているようなので、この待ちが Write の後だけなのかどうかは コードを参考にしても よくわからない。

  • Read の Data パケット待ち: Read のデータが送られるまでの待ちで、非常に時間がかかる場合があるらしい。


READ/WRITE の場合で、ちゃんと状態を管理するのは 覚悟ができているので良いのだが、 CSD や CID の READ で時間がかかる前提をするのは 面倒だから 対応したくない。

あと、エラー処理 ... か。

とりあえず、今のものを usb162-0.2-wk8.tar.gz で保存。

SD カードはまだ全然ダメ。とりあえず コンパイルできるレベル。

追記5:AT90USB162 ブートローダ

SD サポートは、部品待ちなので、ひとまず置いておいて ... ブートローダについて。

AT90USB162 ブートローダ



自分仕様で ブートローダを作りたい。USB が付いているわけで、まずは USB からの書き換えをサポートしたい。

DFU ブートローダは、それなりに便利なのだが、ソースコードも公開されていないし、改造できないから、別のものを考えないといけない。-- 簡単そうなものの1つは、シリアル経由のブートローダ (AVR910 ベース) なのだが、便利であるかどうか ...というと疑問。

    ちなみに、www.mikrocontroller.net の "Bootloader" for ATTiny2313に 置いてある ATTiny2313_bootloader というのがある。

    ビルトしてみたら 848 バイト。これぐらい本体は小さいのではあるが、CDC-ACM を入れたら 結構大きくなる。

    それはともかく、ブートローダサポートがない ATTiny2313 でもそれなりに 作れるわけだ。

    DFU ブートローダ を置き換えずに、ブートローダもどきを作ることは可能なのだ。

    当面は、アプリケーションとして ブートローダもどきを作ってテストする予定。


やはり、便利なのは、USBaspLoaderだろう。

ブートローダ自体は、main.c ひとつに収まっていて 327 行。usbdrv API も usb162 を作ったときに研究したので多少知っている。HID をサポートしないといけないので面倒なのだが、たぶんなんとかなるだろう。

こうやって USBasp を理解したら、USBasp のインターフェイスを使った XMEGA ライタも作れるようになるのだろう。

USBasp プロトコルメモ



USBasp は HID プロトコルを使うという認識があると思うが、正確には、デフォルトエンドポイントでのコントロール転送 を使って送受信するプロトコル。実際には HID自体 の規約とはあまり関係なく、HID で通信するのは ホスト側の都合。

で、実際の通信は、8 バイトの SETUP パケットを受け取り、その中に埋め込まれた コマンドによって、送受信する。

以下は、USBasp のコマンドと USBaspLoader でサポートしている範囲。


    OUT IN
    1 o CONNECT 0 0
    2 o DISCONNECT 0 0
    3 o TRANSMIT 0 4
    4 o READFLASH 0 0-200
    5 o ENABLEPROG 0 1
    6 o WRITEFLASH 0-200 0
    7 o READEEPROM 0 0-200
    8 o WRITEEEPROM 0-200 0
    9 o SETLONGADRESS 0 0
    10 x SETISPSCK 0 1

    IN/OUT は HOST から見た方向

    0-200 は、AVRDUDE で使用している範囲。コード上は 0-254

    SETLONGADRESS は、上位 16bit のアドレスの設定。下位 16bit
    は、各コマンドで指定。
    SETISPSCK は ISP の クロックの設定。不要なので未サポート
    CONNECT は、なにもしない。
    DISCONNECT は、アプリケーションを実行(CONFIG した場合)
    TRANSMIT は ISP コマンドの実行。 サポートしているのは以下のもの
    0x30 シグネチャ読み出し
    0xa0 READ EEPROM byte (CONFIGした場合)
    0xc0 WRITE EEPROM byte (CONFIGした場合)
    0xac CHIP ERASE     (CONFIGした場合)


うまく作れば、最小のサイズは 2KB以下 に収まりそうな感じ。

ブートローダ領域を使わない場合どうするか



  • まず プログラム(.text)の場所をできるだけ上位アドレスにする。
  • 0 番地〜 .text の先頭までをプログラムできる範囲として扱う。
    ただし、0番地からの 2ワード(4バイト) は、別の場所に移動する。
  • DISCONNECT での実行機能で、移動した場所のリセットベクタのアドレスを計算して JMP すれば、OK 。
    ただし、ハードリセットではないので、汚した IOレジスタは元に戻さないといけない。


これぐらいで大体説明できるわけなので、簡単と言えば簡単。

XMEGA に拡張できるか?



avrdude-5.8 の avrdude.conf を見てみたところ、FLASH や EEPROM 、ヒューズやロックビットまでも 広大な1つのアドレス空間に マップされているような定義になっている。

それにアクセスする メソッドを READFLASH / WRITEFLASH に 割り付けて、あと チップイレースや シグネチャーの READ を TRANSMIT(ISP コマンド) でエミュレーションすることにすれば、avrdude を少し変更するだけで、いけるような気がする。

追記:USBaspLoader 移植

なんか、ちょっと動き出した。

まず、usb162 のバグが見つかった。ストリングのデスクリプタの定義が間違っていた。次は、正しく直したときの Linux での /proc/bus/usb/devices

    T: Bus=03 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 46 Spd=12 MxCh= 0
    D: Ver= 1.01 Cls=ef(unk. ) Sub=02 Prot=01 MxPS= 8 #Cfgs= 1
    P: Vendor=16c0 ProdID=05dc Rev= 1.02
    S: Manufacturer=www.fischl.de
    S: Product=USBasp
    C:* #Ifs= 3 Cfg#= 1 Atr=80 MxPwr=100mA
    A: FirstIf#= 0 IfCount= 2 Cls=02(comm.) Sub=02 Prot=01
    I:* If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=02 Prot=01 Driver=cdc_acm
    E: Ad=83(I) Atr=03(Int.) MxPS= 8 Ivl=100ms
    I:* If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=cdc_acm
    E: Ad=82(I) Atr=02(Bulk) MxPS= 32 Ivl=0ms
    E: Ad=01(O) Atr=02(Bulk) MxPS= 32 Ivl=0ms
    I:* If#= 2 Alt= 0 #EPs= 0 Cls=ff(vend.) Sub=00 Prot=00 Driver=(none)


要するに次の部分が出てなかった。

    S: Manufacturer=www.fischl.de
    S: Product=USBasp

avrdude では、ID だけじゃなくて、ストリングもチェックしているので、間違っていると認識されない。

ちなみに、INERFACE CLASS を Cls=ff(vend.) に変更していて、DEVICE CLASS も IAD 対応の Cls=ef(unk. ) に変更しても問題ない。Vendor と Product の ID とストリングだけをチェックして、VENDOR CLASS で、コントロール転送できればなんでも良いらしい。

上は、CDC-ACM に USBasp を通す改造をした例。CDC-ACM で ログを取ってみたところ。


    (FLASH の READ)
    SETISPSCK
    CONNECT
    ENABLEPROG
    TRANSMIT (signature read ) x 3回
    TRANSMIT (fuse /lockbit read) x 9 回
    TRANSMIT (eeprom read) x 4 回

    SETLONGADRESS
    READFLASH
    SETLONGADRESS
    READFLASH
    :
    SETLONGADRESS
    READFLASH


というシーケンスだった。SETISPSCK もとりあえず 正常終了 させるようして、fuse /lockbit read もサポートした。( ついでに signature も 読み込むようにした。)

こうした上で自分自身を Verify してみたところ OK 。

いろいろ変なのだが、とりあえず、今のものを usb162-0.2-wk9.tar.gz で保存。
posted by すz at 19:14| Comment(3) | TrackBack(0) | SRT162

2009年10月20日

Mass Storage Class の検討

USB の仕様は、

にあるのだが ... 正直、読む気がしない。なにかとっかかりが欲しいと思っていた。

すこし前になるが、Linux に デバイス側のドライバーがあることを知った。場所は、drivers/usb/gadget 。Mass Storage Class をはじめとして、シリアルや オーディオ、MIDI などのクラスのドライバーもある。さらに USB イーサネットまで。

電子工作で USB を扱うために、これらのドライバーを見ていこうと思う。基本的に、どのようにディスクリプターを定義して、どのようなコマンドがあって、それぞれについてどういう処理をしているかが解れば良いわけで、読むのに Linux の知識はほとんど必要ない。極端な話 処理の中身が解らなければそこで仕様書を紐解けばよいのだ。

まず読んでみたいのは、Mass Storage Class 。SCSI やら ATAPI やら 面倒そうな感じなのだが、どれぐらい面倒なものなのか知りたいと思っていた。このドライバーは、file_storage.c 。 読む Linux のバージョンは、最新の 2.6.31 ということにする。

さて、file_storage.c を開いてみると 4269 行もある。すごく長いのだが、SCSI や ATAPI あと FD 用の UFI など 6 種類のプロトコルの処理が入っていて、転送方法も BBB(Bulk-Only) , CB(Control-Bulk), CBI(Control-Bulk-Interrupt) の 3種類に対応しているようなので仕方がないのかも知れない。

...とか思ってみたのだが、どうも プロトコル毎の差がほとんどない。
プロトコルとしては、

#define USB_SC_RBC 0x01 // Reduced Block Commands (flash)
#define USB_SC_8020 0x02 // SFF-8020i, MMC-2, ATAPI (CD-ROM)
#define USB_SC_QIC 0x03 // QIC-157 (tape)
#define USB_SC_UFI 0x04 // UFI (floppy)
#define USB_SC_8070 0x05 // SFF-8070i (removable)
#define USB_SC_SCSI 0x06 // Transparent SCSI

という風に define されているのだが、USB_SC を サーチして みrると処理自体が変わるところは、2 ヶ所ぐらいしかない。しかも、CONFIG_USB_FILE_STORAGE_TEST が define されている時だけ有効。どうも SCSI かつ Bulk-Only がデフォルトみたい。それ以外は実際は動かないのではないか? という気もしてきた。

define されている SCSI コマンドのうち、なにかしら処理をしているのは、以下のもの。

0x12 INQUIRY
0x15 MODE_SELECT_6
0x55 MODE_SELECT_10
0x1a MODE_SENSE_6
0x5a MODE_SENSE_10
0x1e PREVENT_ALLOW_MEDIUM_REMOVAL
0x08 READ_6
0x28 READ_10
0xa8 READ_12
0x25 READ_CAPACITY
0x44 READ_HEADER
0x43 READ_TOC
0x23 READ_FORMAT_CAPACITIES
0x03 REQUEST_SENSE
0x1b START_STOP_UNIT
0x35 SYNCHRONIZE_CACHE
0x00 TEST_UNIT_READY
0x2f VERIFY_10
0x0a WRITE_6
0x2a WRITE_10
0xaa WRITE_12

特定のプロトコル用に作る場合、たぶん全部は実装する必要はなくて、いくつかは省けるのだろう。

ちなみに、SCSI コマンドの解析実行は、do_scsi_command() という関数で行っている。これを実行しているのは、カーネルスレッド。AVR でいうと、メインループで パケットを受け取り 解析しているような感じか。

ここで フロッピーのUFI(pdf) をみてみることにする。観点はどれぐらい簡略化されているのかということ。

共通のもの
o 0x12 INQUIRY
o 0x55 MODE_SELECT_10
o 0x5a MODE_SENSE_10
o 0x1e PREVENT_ALLOW_MEDIUM_REMOVAL
o 0x28 READ_10
o 0x25 READ_CAPACITY
o 0x23 READ_FORMAT_CAPACITIES
o 0x03 REQUEST_SENSE
o 0x1b START_STOP_UNIT
o 0x00 TEST_UNIT_READY
o 0x2f VERIFY_10
o 0x2a WRITE_10
o 0xaa WRITE_12

処理を入れなくて良さそうなもの
- 0x04 FORMAT_UNIT
- 0x1d SEND_DIAGNOSTIC

UFI では使わないもの
x 0x15 MODE_SELECT_6
x 0x1a MODE_SENSE_6
x 0x08 READ_6
x 0xa8 READ_12
x 0x44 READ_HEADER
x 0x43 READ_TOC
x 0x35 SYNCHRONIZE_CACHE
x 0x0a WRITE_6

上記以外で UFI で定義されているもの

    0x01 REZERO_UNIT
 0x2b SEEK_10
 0x2e WRITE_AND_VERIFY_10


少々コマンドが減ったが、UFI だから簡単かというとあまりそういう感じはしない。ちょっと期待はずれ。

まぁこの程度なら UFI を作って見ることは出来そうな気がしてきた。やっているうちに理解も深まるだろう。


あと、Renesas の SH7216のアプリケーションノートを発見。この pdfを見てみると ... 0x06 Transparent SCSI は、次の 11 個のコマンドで実装できているようだ。

o 0x12 INQUIRY
o 0x1a MODE_SENSE_6
o 0x1e PREVENT_ALLOW_MEDIUM_REMOVAL
o 0x28 READ_10
o 0x25 READ_CAPACITY
o 0x23 READ_FORMAT_CAPACITIES
o 0x03 REQUEST_SENSE
o 0x1b START_STOP_UNIT
o 0x00 TEST_UNIT_READY
o 0x2f VERIFY_10
o 0x2a WRITE_10


Linux の file_storage.c をみながら、この 11 個のコマンドを実装してみることにしよう。転送方法は、BBB(Bulk-Only)。他は考えない。

ところで、ATAPI とは何か。実は知らなかったのだが、Serial ATA (SATA) 開発者向け資料というページを見てだいぶ解ってきた。要するに SCSI プロトコルがベースになっていて、 READ_HEADER、READ_TOC あたりが ATAPI 特有のコマンドなのだろう。

Mass Storage Class で なにをしたいか

もともと、SD カードのファイルを1枚のフロッピーみたいに扱って LCD とボタンでフロッピーの入れ替えをサポートする仮想フロッピー装置を作ってみたかったのだ。

それはいずれ頑張るとして... シリアルFLASH を読み書きするのに転用できないかと思ったのが調べだしたきっかけ。
    Atmelのアプリケーションノートに AVR916: Upgrading the Flash using a U-Disk というのを発見。これをちょっと見てみると .. scsi_decoder.c で SCSI の処理をしている。かなり参考になりそう。ちなみに、対応しているコマンドは ...

    0x06 Transparent SCSI
    o 0x12 INQUIRY
    o 0x1a MODE_SENSE_6
    o 0x5a MODE_SENSE_10
    o 0x1e PREVENT_ALLOW_MEDIUM_REMOVAL
    o 0x28 READ_10
    o 0x25 READ_CAPACITY
    o 0x03 REQUEST_SENSE
    o 0x00 TEST_UNIT_READY
    o 0x2f VERIFY_10
    o 0x2a WRITE_10

    x 0x23 READ_FORMAT_CAPACITIES
    x 0x1b START_STOP_UNIT

    MODE_SENSE_10 が増えているが、全部で10個。実際の USB AVR の処理も含まれているし、こっちの方が参考になるかも。

作るだけなら出来そうな気もしなくはないのだが、4KB 単位で Write しないと いけないとか変な仕様になりそう。セクターサイズを 4KB にするとかも出来そうだけど OS が対応していないような気がするし↑の変な仕様のほうがまだマシかも知れない。


追記1:

usb162-0.1 を使って、シリアルFLASH のデバッグをして、やはり USB シリアル(CDC-ACM)が、デバッグに使えるのは便利だと実感したのだが ... Mass Storage Class のデバッグにもUSB シリアルが使えないかと思ってしまった。実用としても便利そうだしなんとかしたい。

最初の壁は、エンドポイントが 5つしかないこと。Mass Storage Class では、2 つのエンドポイントが必要だが、usb162-0.1 では 4 つ使っている。内訳は、デフォルトエンドポイント、CDC 、CDC-DATA(2つ)。

実をいうと、CDC のエンドポイントは割り当てているものの、なにも処理していない。こいつをどうにかすれば 3つに減らせる。

で、CDCの仕様書をはじめて見てみた。CDC には、1つのエンドポイントが必要と書いてあるが、一方でデフォルトエンドポイントを使うという記述もある。

じゃぁ いらないのかと思って、CDC のエンドポイント を定義しないようにしてみると ... エラーにはならないものの通信がまったくできない。

ここではまったのだが、結局CDC のエンドポイントをデフォルトエンドポイントにしたら動いた。これで良いのか?とも思うのだが動いたから OK としよう。

これで、Mass Storage Class のインターフェイスを追加できるようになった。

次の問題は、インターフェイスを追加するだけで良いのか?ということ。まず SETUP の クラスリクエストは、どのクラスのリクエストなのかという情報がない。どうもCDC と Mass Storage Class とでは 重なっていないようでなんとかなりそう。

後は OS が対応しているかどうか。... 複合デバイスでググってみたら、複合デバイスの作りかたなんてページを発見。なんでも IAD -- USB Interface Association Descriptor というディスクリプタを記述するらしい。普通のでさえ良くわからないのに面倒な話だ。... といっても処理自体は変えなくて良さそうなので、普通に作った後問題だったら対処することにしよう。

さて、Mass Storage Class では、いくつかの SCSI コマンドを用意すれば良いのは分かった。他になにをすれば良いのか?

まず、ディスクリプタについて。

どうも インターフェイスと エンドポイント2つ(BULK IN,OUT)を定義するだけで良いらしい。インターフェイスのクラスは、0x08, サブクラス 0x06 (SCSI)、プロトコル 0x50 (Bulk-Only)。

SETUP は、GET_MAXLUN(0xfe)、RESET(0xff) という 2つのクラスリクエストに対応すればよい。

後は、Bulk-Only がどういうものか分かれば、作り出せる。

これは、SH7216のアプリケーションノートのpdfに解説がある。

コマンドトランスポート(OUT) - データトランスポート(IN or OUT) - ステータストランスポート(IN) の3ステージで通信する規約らしい。

コマンドトランスポートでは、31 バイトの Commannd Block Wrapper(CBW) パケットが送られてきて、 コマンドによって データトランスポートを行い、最後に 13 バイトの Commannd Status Wrapper(CSW) パケットを送る。

少なくとも Bulk-Only では、非同期の処理はなく、コマンドを順番に処理すれば良い。

なんか簡単そうな感じまでするが、メモリが使えないのでデータトランスポートをバッファレスで処理しないといけない。このあたりは、AVR916を参考にしようと思う。

追記2:実装について

AT90USB162 は、エンドポイントのバッファから、1バイトづつ取り出す仕様になっていてメモリのようにランダムアクセスは出来ない。CDC の場合は、xxx_getc という API を作りエンドポイントのバッファから取り出している。(送る場合も同様で xxx_putc を使う)。で、バッファーの面倒を見るのが xxx_poll 。

さて、Mass Storage Class の場合もエンドポイントの処理は同じ。xxx_getc/xxx_putc をコピーして対象のエンドポイントを変更したものを yyy_getc/yyy_putc として作成し、xxx_poll の中の処理をコピーして、 Mass Storage Class のエンドポイントを対象にしたものを xxx_poll に追加する。

次に yyy_getc/yyy_putc を使って、Mass Storage Class 処理を行う関数 zzz_poll を 作る。こいつは、上記3ステージに対応した状態変数で処理を変えるステートマシンとして作る。

コマンドトランスポートでは、バッファーに 31 バイト以上あれば、処理を開始してコマンドを解析・処理をして、次の状態に移る。

データトランスポートでは、何の処理をどのオフセットから何バイト行うかを状態変数として持ち、バッファー分だけ(たぶん 32バイト)の処理をしてポインターを進める。最後まで行けば 次の状態に遷移。途中でエラーになった場合でも最後まで処理をしないといけない(はず)。

ステータストランスポートでも同じ感じ。何を返却するか覚えていて、バッファーが空けばそれを送り 元の状態に戻る。

重要なのは、中で待ち合わせをしないこと。すぐに処理できないのであれば、関数から抜ける (リターンする)。

理由は2つある。ひとつは、他の処理をできるようにするため。zzz_poll の関数名を付ける所以。もうひとつは、RESET がきたら確実に初期状態にするため。

さて、悩んでいるのは、31 バイトの CBW を一旦メモリにコピーするかどうか。31 バイトでも貴重なのだ。

ちなみに CBW のうち後ろ16バイトは、SCSI コマンド。前の15 バイトのうち 4 バイトを使うエリアが3つある。ひとつは シグネチャ 。CBW であることを確認するためのもので、文字列で 'USBC' 。次がタグ(シーケンス番号)。値を覚えていて同じ値を CSW に入れなければならない。最後が データトランスポートの転送長 。そのまま状態変数に使える。あとの3バイトは、転送方向、LUN、SCSI コマンドのバイト数。

ついでに CSW も記しておこう。13 バイトのうち、3つは 4バイトのエリア。最初はシグネチャで、'USBS'。次はタグ。最後が 処理しなかった 転送バイト数。最後1バイトがステータス。0 が成功、1がコマンドのエラー、2 がフェーズエラー。

CBW の 転送バイト数を状態変数として使うとすれば最後に 0 になるから、ちょっと書き換えれば CSW になる。

頭の15 バイトはメモリに置いた方が良さそうだ。SCSI コマンドは微妙。読みながら解析するのもアリかも知れない。

追記3:SCSI コマンドの実装

ちょっと AVR916 と UFI の仕様書をを見ながら実装してみている.

最初に INQUIRY を見てみた。データトランスポート で 36 バイトのデータを返すらしい。データ自体は const なので FLASH に置けば良さそう。パラメータエラーの場合、エラーコードを 覚えておいて、REQUEST_SENSE が来たときにその値を返す。

REQUEST_SENSE も データトランスポート で 18 バイトを返すが、sense_key と sense_asc の 2 つのデータが 18 バイトの中に埋まっている。コードの量を減らすために どういう工夫ができるのか悩み中。

    よく見ると 0 が多い。 4 バイトのデータで 下位 1 バイトしか使わないケースもいくつかある。

    結局 1 バイトを 書き込む yyy_putc 以外に、上位が 0 で 2 バイト書き込む yyy_putc2 とか 4 バイト書き込む yyy_putc4 とかを作る ことにした。

    あと、頭が痛いのが MODE_SENSE 。_6 以外に _10 があって微妙に違う。送るデータも 共通データ以外に 2 種類の PAGE_CODE があり、設定によって切り分け 4 通りのデータになる。_6/_10 の組み合わせを入れると 8 通り。あぁ面倒。

    ちょっと、Linux の file_storage.c を見てみたら、対応している PAGE_CODE は、CACHING_MODE_PAGE のみ... そしてそれは上記の 2 種類とは別。... ということは 特にサポートしなくて良いのかも。

さて、いろんなコマンドに対してデータトランスポートで返却しているようだ。処理するときに switch 文とかで処理するのは、いかにも効率が悪いし コードの量も増える。関数ポインタに処理関数を登録しておいて、それを実行するようにしたほうが良さそうに思えてきた。ちなみに、AVR916 では、コマンド処理の延長で 返却データを 書き込んでいる。そのほうが簡単なのだが... 最初の想定の通りステートマシンにしようと思う。

追記4:Linux (Vine-5.0)につないでみた。

とりあえず エンドポイントを 0 にマップしたやつを つないでみると ...

    usb 3-1: config 1 interface 0 altsetting 0 has an invalid endpoint with address 0x80, skipping
    usb 3-1: configuration #1 chosen from 1 choice
    cdc_acm 3-1:1.0: ttyACM0: USB ACM device


なんか嫌なメッセージを出しつつも、初期化はできた。

で、minicom でつないでみると ...

    minicom: cannot open /dev/ttyACM0: Input/output error


ダメじゃん。どうしよう。

さらに、適当に作った Mass Storage Class をくっつけたのを Linux につないでみた。


    scsi scan: INQUIRY result too short (5), using 36
    scsi 2:0:0:0: Direct-Access PQ: 0 ANSI: 0
    sd 2:0:0:0: [sdb] Sector size 0 reported, assuming 512.
    sd 2:0:0:0: [sdb] 1 512-byte hardware sectors (0 MB)
    sd 2:0:0:0: [sdb] Write Protect is off
    sd 2:0:0:0: [sdb] Mode Sense: 00 00 00 00
    sd 2:0:0:0: [sdb] Assuming drive cache: write through
    sd 2:0:0:0: [sdb] Sector size 0 reported, assuming 512.
    sd 2:0:0:0: [sdb] 1 512-byte hardware sectors (0 MB)
    sd 2:0:0:0: [sdb] Write Protect is off


まだまだダメそうなのだが、とりあえず Linux は scsi デバイスを認識しようとしてくれているみたい。

CDC の エンドポイントは問題だが、Mass Storage Class はテストできそうな感じ。

ちなみに、Windows XP につなぐと ... CDC は使える。Mass Storage Class をくっつけても それは認識されず CDC だけは使える状態。

とりあえずは、Linux で Mass Storage Class を テストできるようにしよう。

    ここに書いた 状態のものを usb162-0.2-wk1.tar.gz に置いておく。当然ながら動かないので注意。

追記5:Linux (Vine-5.0)でなんか動いた。

まずエンドポイントの問題。これは、core の部分で 0 番をはじいているため。なんでもいいかも とか思って、(存在しない) 5 番のエンドポイントを指定したら OK だった。

ちょっといろいろあったのだが、最終的に次のメッセージが出るようになった。

    usb 3-1: new full speed USB device using uhci_hcd and address 22
    usb 3-1: configuration #1 chosen from 1 choice
    cdc_acm 3-1:1.0: ttyACM0: USB ACM device
    scsi20 : SCSI emulation for USB Mass Storage devices
    usb-storage: device found at 22
    usb-storage: waiting for device to settle before scanning
    usb-storage: device scan complete
    scsi 20:0:0:0: Direct-Access ATMEL AT90USB128 M S 0.00 PQ: 0 ANSI: 3
    sd 20:0:0:0: [sdb] 1025 512-byte hardware sectors (1 MB)
    sd 20:0:0:0: [sdb] Write Protect is off
    sd 20:0:0:0: [sdb] Mode Sense: 0c 00 00 00
    sd 20:0:0:0: [sdb] Assuming drive cache: write through
    sd 20:0:0:0: [sdb] 1025 512-byte hardware sectors (1 MB)
    sd 20:0:0:0: [sdb] Write Protect is off
    sd 20:0:0:0: [sdb] Mode Sense: 0c 00 00 00
    sd 20:0:0:0: [sdb] Assuming drive cache: write through
    sdb: unknown partition table
    sd 20:0:0:0: [sdb] Attached SCSI removable disk


ちなみに、いちばんはまったのは、送信のタイミング。0 バイト送信とかしないように 明示的にに flush するようにしたら、きれいに動くようになった。


で、ログをメモリにとって、シリアルを接続して確認したのだが、次のシーケンスで通信している。

    FE (setup 0xff -- RESET )
    FE (setup 0xff -- RESET )
    FC (setup 0xfe -- GET_MAXLUN )
    C0 12 24 00 SCSI INQUIRY - trans 0x24 bytes - OK
    C0 00 00 00 SCSI TEST_UNIT_READY - OK
    C0 25 08 00 SCSI READ_CAPACITY - trans 0x08 bytes - OK
    C0 1A C0 3F 00 SCSI MODE_SENSE_6 (ALL) - trans 0xC0 bytes - OK
    C0 00 00 00 SCSI TEST_UNIT_READY - OK
    C0 25 08 00 SCSI READ_CAPACITY - trans 0x08 bytes - OK
    C0 1A C0 3F 00 SCSI MODE_SENSE_6 (ALL) - trans 0xC0 bytes - OK
    C0 28 00 00 SCSI READ_10 - trans 0xXXXXX00 - OK
    C0 1E 00 00 SCSI PREVENT_ALLOW_MEDIUM_REMOVAL - OK
    C0 00 00 00 SCSI TEST_UNIT_READY - OK
    C0 1E 00 00 SCSI PREVENT_ALLOW_MEDIUM_REMOVAL - OK
    :


実際に READ/WRITE してみる。(ちなみに 先にデバイスはない。 -- /dev/null, /dev/zero のようなもの )

    # dd if=/dev/sdb of=123 bs=512
    1025+0 records in
    1025+0 records out
    524800 bytes (525 kB) copied, 3.83482 s, 137 kB/s
    # dd of=/dev/sdb if=123 bs=512
    1025+0 records in
    1025+0 records out
    524800 bytes (525 kB) copied, 3.70997 s, 141 kB/s

一応エラーは出ていないようだ。

1025 セクタあるのは、READ_CAPACITY で返却するのは 最後のセクター番号のため。-1 しないといけない。

動いた記念に ここに書いた 状態のものを usb162-0.2-wk2.tar.gz に置いておく。

ちなみに、Windows では、ディスクドライブとしてちゃんと認識されたものの ... CDC-ACM が認識されない。inf ファイルを作らないといけなさそうだが、作り方がわからない。あるいは、IAD -- USB Interface Association Descriptor を記述しなければならないのか?

それはともかく、次の段階は、本物の シリアルFLASHをつなげてみるつもり。で、4096B セクター でもいけるかどうかのテスト。

全部うまくいったら、API を整理。

追記5:READ/WRITE できるようになった。

一応 4KB セクターと 512B セクターを切り替えられるように作れた。


    Read:
    1048576 bytes (1.0 MB) copied, 17.6026 s, 59.6 kB/s
    Write:
    1048576 bytes (1.0 MB) copied, 63.263 s, 16.6 kB/s


えらく遅くなってしまった。Write が遅いのは、仕方がない。4KB の ERASE に 0.3 秒かかるはずなので、ERASE だけで Typ. 76.8 秒。
Read が遅いのは、ソフト SPI になってしまっているのも原因。そもそも FLASH なしでも 137 kB/s しか出ていない。バッファのサイズを大きくするか ダブルバッファにすれば .. 多少は速くなるのだが ...

値はちゃんと書き込めているし、2 回 READ して コンペアしても同じ値。

問題はあると思う。512B セクターで 4KB の 先頭しか Write しなければ、残りは 0xff で埋まる。先頭を外して書き込めば、AND になる。4KB セクターなら そのような問題はないが、今度は OS が対応しているかどうかが問題。これからテストしてみるつもり。

ここに書いた 状態のものは、 usb162-0.2-wk3.tar.gz

gcc3 で ビルドすると 6146 バイト。シリアルでのモニターとか デバッグコード入れたままなので、チューニングすれば多少小さくなるはず。

追記6: Windows XP で複合デバイスをつかうには?



これ自体は簡単みたい。

  • 装置のUSBコンフィグレーションに 8 バイトの IAD をインターフェイスの前に追加する。
  • inf ファイルは、VIDとPID のところに、&MI_00 を追加。

これで、CDC-ACM 一個でも複合デバイス。

ただし、Windows XP SP3 以降でしかダメ。

ところで、いろいろ実験しているとドライバの設定が変に残って困る。 USBDeviewを使ってアンインストールするのが、便利で良いらしい。

あと、変にCOMポート番号が増えてしまう。”USB シリアルポート番号を増やさないようにする"という記事が参考になった。
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\COM Name Arbiter の ComDB 。これが使用中のビットマップになっている。

さて、結局CDC のエンドポイントをデフォルトエンドポイント(0 番)にしたら動いた件。

CDC-ACM 一個の複合デバイスでも OK だった。ただし、存在しない 5 番を割り当てるのは NG 。

そして、MSC を追加したときも NG 。困った。

ここで書いている NG の現象は、COMポートが割り当てられてターミナルも開けるのだが、通信が出来ない。Linux でも MSC がダメダメだったときは、あおりをくらって通信できなかったから、MSC が Windows の期待どおりに動けばあるいは通信もできるかも知れない。

追記7: Windows XP でなんか動いた。

EEPROM にログをとって調べたところ、MODE_SENSE_6 で おかしくなっていたことが判った。そうなると、Windows は MSC に対して RESET を出す。まだまだ変なのだが、CDC-ACM 経由で生きている状態で ログを取れるようになった。

以下シーケンス。

    FE (setup 0xff -- RESET )
    FE (setup 0xff -- RESET )
    FC (setup 0xfe -- GET_MAXLUN )
    C0 12 24 00 SCSI INQUIRY - trans 0x24 bytes - OK
    C0 23 FC 05 SCSI READ_FORMAT_CAPACITY - trans 0xFC bytes - ERR
    C0 03 12 00 SCSI REQUEST_SENSE - trans 0x12 bytes - OK
    C0 23 FC 05 SCSI READ_FORMAT_CAPACITY - trans 0xFC bytes - ERR
    C0 03 12 00 SCSI REQUEST_SENSE - trans 0x12 bytes - OK
    C0 23 FC 05 SCSI READ_FORMAT_CAPACITY - trans 0xFC bytes - ERR
    C0 03 12 00 SCSI REQUEST_SENSE - trans 0x12 bytes - OK
    C0 25 08 00 SCSI READ_CAPACITY - trans 0x08 bytes - OK
    C0 28 00 00 SCSI READ_10 - trans 0xXXXXX00 - OK
    C0 1A C0 1C 00 SCSI MODE_SENSE_6 (EXCPT) - trans 0xC0 bytes - OK
    C0 1A C0 3F 00 SCSI MODE_SENSE_6 (ALL) - trans 0xC0 bytes - OK
    C0 25 08 00 SCSI READ_CAPACITY - trans 0x08 bytes - OK
    C0 25 08 00 SCSI READ_CAPACITY - trans 0x08 bytes - OK
    C0 28 00 00 SCSI READ_10 - trans 0xXXXXX00 - OK
    C0 28 00 00 SCSI READ_10 - trans 0xXXXXX00 - OK
    C0 25 08 00 SCSI READ_CAPACITY - trans 0x08 bytes - OK
    C0 25 08 00 SCSI READ_CAPACITY - trans 0x08 bytes - OK
    C0 28 00 00 SCSI READ_10 - trans 0xXXXXX00 - OK
    C0 25 08 00 SCSI READ_CAPACITY - trans 0x08 bytes - OK
    C0 00 00 00 SCSI TEST_UNIT_READY - OK
    C0 25 08 00 SCSI READ_CAPACITY - trans 0x08 bytes - OK
    C0 25 08 00 SCSI READ_CAPACITY - trans 0x08 bytes - OK
    C0 25 08 00 SCSI READ_CAPACITY - trans 0x08 bytes - OK
    C0 28 00 00 SCSI READ_10 - trans 0xXXXXX00 - OK
    C0 28 00 00 SCSI READ_10 - trans 0xXXXXX00 - OK
    C0 28 00 00 SCSI READ_10 - trans 0xXXXXX00 - OK
    C0 1A 0C 3F 00 SCSI MODE_SENSE_6 (ALL) - trans 12 bytes - OK
    C0 00 00 00 SCSI TEST_UNIT_READY - OK
    C0 00 00 00 SCSI TEST_UNIT_READY - OK
    C0 00 00 00 SCSI TEST_UNIT_READY - OK
    :
    :


READ_FORMAT_CAPACITY が来ているがエラーにしている。AVR916 でも実装されていないので、これで良いのだろう。

2 つめの SCSI MODE_SENSE_6 (ALL) が サイズ 12 バイトで来ている。あと MODE_SENSE_6 (EXCPT) というのも。AVR916 に習って実装しなおした。

これで、RESET が来なくなった模様。

CDC-ACM は、なんか反応が悪い。

-- 反応が悪いのは、EEPROM の書き込みでヘマをしてて、コマンドがくるたびに、EEPROM に書いてしまっていたため。EEPROM に書かなくしたらまともになった。

さて、ディスクが見えたので、フォーマットしてみた。1MB あったのだが、フォーマット後は 400KB 弱。とりあえず 30KB のファイルを 3 つばかりコピー。

いったん、取り外して 再度接続すると ... さらに容量が減った。ファイルもちゃんと読めたのは 2つのみ。

これは、4KB 単位でしか書き換えできないのが理由。じゃぁ、セクタサイズを 4KB にしてみると ... Windowsは、フォーマットを完了できませんでした。.. と言われた。たぶん、容量的な問題。

まぁこんなものでも、役に立つのだ。ファイルシステムを作るのに無理があるだけの話。

とりあえずでも動いた記念に ここに書いた 状態のものを usb162-0.2-wk5.tar.gz に置いておく。

追記8: 泥沼化

とりあえず動いたので、チューニングやらなにやらしていたのだが、なにか変になってきた。で、シリアルFLASH の シグネチャーを COMポート経由で READ してみると ... ちゃんと読めない。

壊れた?とか思ってリトライ入れたり、なんだかんだしているうちに、よくわからなくなってきた。

思い立って アクセスランプを付けてみたら、ずっと激しく点滅。どうも Windows が、ずっとアクセスしているらしい。

COMポート経由での アクセスとぶつかると、当然のように正しく動かないが、それが高い確率で起きていたのだった。

とりあえず一安心なのだが ... COMポートの通信ができなかったり段々変になってきた。

もうよく分からないので、いったん wk5 に戻って やりなおそうと思う。

とりあえず Windows がずっとアクセスしている原因の追究:

ログは以下のもの

    C0 1A 0C 3F 00 SCSI MODE_SENSE_6 (ALL) - trans 0xC0 bytes - OK
    C0 25 08 00 SCSI READ_CAPACITY - trans 0x08 bytes - OK
    C0 25 08 00 SCSI READ_CAPACITY - trans 0x08 bytes - OK
    C0 25 08 00 SCSI READ_CAPACITY - trans 0x08 bytes - OK
    C0 28 00 00 SCSI READ_10 - trans 0xXXXXX00 - OK
    C0 1E 00 00 SCSI PREVENT_ALLOW_MEDIUM_REMOVAL - OK
    C0 00 00 00 SCSI TEST_UNIT_READY - OK
    C0 25 08 00 SCSI READ_CAPACITY - trans 0x08 bytes - OK
    C0 25 08 00 SCSI READ_CAPACITY - trans 0x08 bytes - OK
    C0 25 08 00 SCSI READ_CAPACITY - trans 0x08 bytes - OK
    C0 28 00 00 SCSI READ_10 - trans 0xXXXXX00 - OK
    C0 25 08 00 SCSI READ_CAPACITY - trans 0x08 bytes - OK
    C0 28 00 00 SCSI READ_10 - trans 0xXXXXX00 - OK
    C0 25 08 00 SCSI READ_CAPACITY - trans 0x08 bytes - OK
    C0 28 00 00 SCSI READ_10 - trans 0xXXXXX00 - OK
    C0 28 00 00 SCSI READ_10 - trans 0xXXXXX00 - OK
    C0 28 00 00 SCSI READ_10 - trans 0xXXXXX00 - OK
    C0 00 00 00 SCSI TEST_UNIT_READY - OK
    C0 1E 00 00 SCSI PREVENT_ALLOW_MEDIUM_REMOVAL - OK
    C0 1A 0C 3F 00 SCSI MODE_SENSE_6 (ALL) - trans 0xC0 bytes - OK


12 バイトの MODE_SENSE_6 (ALL)の内容が気に入らないのか、はたまた READ したデータの内容が気に入らないのか。

... MODE_SENSE_6 でどういう情報を返すのか?とか よく分かっていないので、SCSI の解説がないかと思ってググったら、こんなのを見つけた。

ハギワラシスコムの 製品の SCSI MODEL Flash Drive の SCSI の仕様書だそうだ。日本語だし 知りたいことが過不足なく書いてあるし ... これはいいものだ。

ちょっとチェックしてみる。

  • 0x12 INQUIRY
    AVR916 を元にしたのだが、今は ANSI Ver 3 になっている。だが、Linux の file_storage.c もこれも Ver. 2 。2 にしたほうが無難か。あと、VENDER_ID の直前のバイトが 0x10 。Sync と書いてある。内部にキャッシュがあって Sync が必要なのか?

  • 0x1a MODE_SENSE_6
    DBD というフラグがあって、これが 0 のときは、Block Descriptor を付けるらしい。Block Descriptor は、8 バイトで READ CAPACITY のようなデータ。サポートしないときは、エラーにするのか?

    あとページコード。0x1C の EXPT はサポートしていない。そのかわり、0x08 CACHING はサポートしている。あと 0x04 GEOMETRY も。

  • 0x1e PREVENT_ALLOW_MEDIUM_REMOVAL
    これは、ロックする機能で、REMOVAL でないからサポートしていないようだ。内蔵FLASH は、実際REMOVAL でないし、おなじようにすればあるいは Windows からのアクセスが止まるのかも知れない。

  • UNIT ATTENSION

    あーそういうものなのか。Windows は、これを待っていたのか。


ちょっと適当なのだが、TEST_UNIT_READYのみ、UNIT ATTENSION に対応したところ、Windows からのアクセスが減った。-- 定常状態では、TEST_UNIT_READYだけが秒間 2 回ぐらい発行されている。

あと、フォーマットのとき、VERIFY_10 を発行するらしく、中身がないものを追加。書かなかったが、512Bセクタでも、フォーマットを完了できませんでした状態になっていたのが直った。

コードが枝分かれしてしまっているので、ここに書いた 状態のものは usb162-0.2-wk5a.tar.gz 。あくまでテスト用。
posted by すz at 22:19| Comment(97) | TrackBack(0) | SRT162

2009年10月19日

SRT162 ソフト編(1)

ステップ1) 動作確認

最低限度の動作ができるかどうかの確認をするのは簡単で、PC の USB に接続してみればよい。... というわけで、おそるおそる接続したところ、新しいデバイスが認識され一安心。

USB が動作しているということで、電源が供給され、水晶、USB の信号線も問題なく 、HWB (PD7) が L になっていることが解る。

さて、以前書いた記事 AT90USB162メモをみながら ... まずは FLIPのページから、FLIP 3.3.4 for Windows (Java Runtime Environement included) をダウンロードして、試してみることにした。

まずは、ダウンロード&インストール、ハードウェア ウィザードでは、インストールしたディレクトリの usb を指定して ドライバーをインストールする。

FLIP を立ち上げ、Settigns → Communication → USB で 接続することで、認識された。

情報を拾ってみると ..

    Signature Bytes 58 1E 94 82
    Device Boot Ids 00 00
    Bootloader Ver. 1.0.5

こんな内容。

作ったソフトを書き込んで、Start Application ボタンで実行ができるようだ。USB AVR はライターいらずで 結構お手軽。AT90USB162 も良いのだが、ADC とかがないのが 残念。ATmega32U4 が 1個単位で買えればよいのに。

ちなみに、デバイスマネージャを見ると LibUSB-Win32 Devices の中に、AT90USB162 が見えている。

デバイスインスタンス ID は、

    VID 03EB
    PID 2FFA / 1.0.5


ステップ2) Linux 環境構築

Windows の環境は、FLIP の追加だけで 良いわけだが、メインの開発環境は Linux にしようと思っている。Linux はいろいろな バージョン使っているのだが、説明は Vine-5.0 を対象にしようと思う。

まずは、dfu-programmer 現在のバージョンは 5.2 。libusb を使うが、0.1.10a 以上であれば良いらしいので、Vine-5.0 ( libusb-0.1.12) では libusb-devel をインストールすればビルドできる。

ちょっと使ってみた。

    # dfu-programmer at90usb162 get manufacturer
    Manufacturer Code: 0x58 (88)
    # dfu-programmer at90usb162 get family
    Family Code: 0x1e (30)
    # dfu-programmer at90usb162 get product-name
    Product Name: 0x94 (148)
    # dfu-programmer at90usb162 get product-revision
    Product Revision: 0x82 (130)

    # dfu-programmer at90usb162 get ID1
    Device boot ID 1: 0x00 (0)
    # dfu-programmer at90usb162 get ID2
    Device boot ID 2: 0x00 (0)

    # dfu-programmer at90usb162 get bootloader-version
    Bootloader Version: 0x05 (5)

Vine-5.0 の libusb の SRPM を取ってきて 玄箱HG(自分ディストリ)でもビルド -- 使えるようだ。ちなみに /proc/bus/usb/devices では

    T: Bus=01 Lev=02 Prnt=02 Port=02 Cnt=03 Dev#= 11 Spd=12 MxCh= 0
    D: Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=00 MxPS=32 #Cfgs= 1
    P: Vendor=03eb ProdID=2ffa Rev= 0.00
    S: Manufacturer=ATMEL
    S: Product=AT90USB162 DFU
    S: SerialNumber=1.0.5
    C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=100mA
    I: If#= 0 Alt= 0 #EPs= 0 Cls=00(>ifc ) Sub=00 Prot=00 Driver=(none)

こんな風に見えている。

これで書き込みする環境は選ばなくなった。一応 ソースRPM 。libusb-devel が必要。


コンパイル環境も みなおしていこうと思う。gcc は、以前作った 3.4 系の予定。4.x はオブジェクト サイズが大きいし、Windows 環境があるのでパス。avr-libc だけは最新にしてみるつもり。

(続き)

結局、一応整備しなおすことにした。パッチ類は、WinAVR-20090313のパッチを取得して ベースにする。それに加えて gcc3 系も再作成。

とりあえず作成したものの ソースRPM 。ソース全部はでかいので、NoSource 版。

avr-binutils のビルド・インストール → avr-gcc のビルド・インストール  → avr-libc のビルド・インストール の順。avr-gcc4 のビルドには、mpfr-devel と gmp-devel が必要。

あと、よくわからないのだが、xmega のパッチを入れるとうまくいかなかったので外してあるし、ada のパッチも削除。WinAVR-20090313 とまったく同じものではないので注意。

ちょっと USBaspLoaderをビルドしてみる。
ターゲットは、atmega328p 。


    3.4.6
    text data bss dec hex filename
    0 1968 0 1968 7b0 main.hex
    4.3.2
    text data bss dec hex filename
    0 2120 0 2120 848 main.hex

サイズが少々増えると 2K 超えてしまうので致命的。これが gcc の ver 3 が手放せない理由。avr-libc も avr-gcc4 でビルドするとサイズが増える。しかし、gcc3 でビルドすると gcc4 でしか使えないデバイスがビルドされない。頭が痛いところ。

さて、これで コンパイルできて、書き込みできるようになった。動作確認はこれから。まったく動かしていないので注意!

ステップ3) プログラミングの構想を練る。

ちょっと以前作った usb162-0.1をビルドしてみる。

    3.4.6
    text data bss dec hex filename
    3314 0 32 3346 d12 test1.elf
    3902 0 36 3938 f62 test2.elf
    4.3.2
    text data bss dec hex filename
    3192 0 32 3224 c98 test1.elf
    3798 0 36 3834 efa test2.elf

あれ? test1,test2 ともに gcc4 の方が小さいという結果に。--- gcc4 も無視するわけにもいかない。

さて、usb162-0.1 を使ってくれている ゆきさんの R8Cプログラマ(ライター)のコードをダウンロードして、変更点をチェックしてみた。

仕様とか WDT 関係とか若干変更があるようだ。ゆきさんの方が実績があるから、マージして使わさせてもらうことにしよう。

で、何から手を付けよう。

を最初にすることにする。デバッグは、USB シリアルで行う。

で、ライブラリにしたり整備しながら、Mass Storage Class に挑戦してみようかと考えている。見込みがなかったり、飽きたりしたら LCD かな。

追記:ボードのテスト状況

1)確認用 LED

適当に付けたら、PB2(MOSI)だった。とりあえず点灯を確認。OK。

2)A25L080

ソフト SPI でまず確認。NG 。調べたところ C(CLK) に PD5(XCK)をつなげたつもりが、PD6 がつながっていた。ソフト SPI なので PD6 に変更したところ シグネチャを読み込めた。いまは回路を変更せずに進める。一通り使えるようになったら、ハードSPI を使うために回路を変更する予定。






posted by すz at 21:12| Comment(0) | TrackBack(0) | SRT162

2009年10月12日

基板が来た!



  • 基板データ表
  • 基板データ裏

    パターンが同じなのは当然として ... シルクがあるべきところにちゃんとある。一見しただけだが、細ってもいない。これも当然なのかも知れないが、パターンと重なったシルクは、ちゃんと 処理されている。

    それにしても、U1 周り VIA が恐ろしいところにあるなぁ。

P板.comから基板が来た! 10/9 出荷予定で、ちゃんと 10/10 に到着。

練習を兼ねて、ht77xx の基板を組み立ててみたが、EAGLE での設計時には、あんなに大きく邪魔にまで感じた部品が、実物では小さすぎるように感じる。

今回はオートルータまかせだったので、部品の半田付けに邪魔になるところに VIA があったりして ちょっと困った。

さて、本番は、srt162 。↑の理由で組み立てに不安を感じながら、ボチボチ組み立て中。回路図的にも 部品の定義自体にも問題あるかも知れないので戦々恐々。

最初はバッテリー周りの回路と 液晶はつけずに、基本動作のテストをする予定。それが終わったら、シリアルFLASH のテスト。次に 液晶 ... なんかやることがいっぱいある。まぁ 長い間 楽しめそうなのでむしろ良いのかも。

ところで、今回の基板の組み立てにあたって買った道具が2つある。


ひとつは、ダイソーの半丸刀(彫刻刀)。平刀の刃が丸くなっているもの。ミニステレオプラグのパターンがおもいっきり間違っていたので、パターンカットするのが目的なのだが、レジストを剥いたりするのにも便利だった。


もうひとつは、セリア、キャンドゥで買った ピンセット 曲型。コスメコーナーで発見。Tweezers Curve Type と書いてある。パッケージも形状もほぼ同じだが、メーカが違い、ものも微妙に違う。形状は、ステンレスの板を端で張り合わせたもので、先が尖っている。精度が高くて小さなチップ部品をしっかり挟める。ただちょっと磁化されていて部品がくっつくことも。

セリアのは、エコー金属製 若干肉厚でバネが硬い。キャンドゥのは、ちょっと薄いがその分密集したとろでも使えそう。中島桐次郎商店。どちらが良いのかよくわからないものの、一枚の板を U 字型に曲げたものとは使い勝手が違う。おすすめ。

追記:製作中(1)



まずは、SRT162A から製作開始。ピンセットを U 字型のものから変えたおかげでだいぶ楽になった。調子に乗ってこまかい部品は全部付けてしまった。テスターでチェックしたら、AT90USB162 を載せる予定。... その前に マスキングテープ買ってこないと。あと、USB のコネクタも手元にない。何年か前に買ったのを探すか新たに買うか。

半田づけは、0.6mm の 鉛ハンダをつかってしている。フラックスは(まだ?)使っていない。不安なところは、水晶。ちゃんと導通しているか シールドとショートしていないか 不安。

ピンセットの使いごこちは良いのだが、部品の密集したところには入らない。中島桐次郎商店のも試してみることにしよう。


あ、ゆきさんからコメントが。

ありがとうございます。もともと、EAGLE で設計して基板を作る ということだけが目標だったりするので、基板という形になっただけで実は嬉しかったりします。全部動くともっと良いのですが 、一部だけでも良しという感じ。

追記:製作中(2)



USB コネクタ、AT90USB162 と シリアルFLASH 、あと 動作確認用 LED を付けた。

USB コネクタは、0.8mm ピッチ。ピッチは広いのだが、シールドがかぶさるので、少々面倒。結局ブリッジしまくりで、ハンダ吸い取り線で掃除。

AT90USB162 は、周りの VIA が気になるのでマスキングテープで ランド以外を覆ってハンダ付け。ハンダを盛って、あとで ハンダ吸い取り線で 修正。マスキングテープはダイソーにあった塗装用。耐熱性が心配だったが、すこし焦げる使い方でも 無問題だった。

シリアルフラッシュは、取り外し品。もとが 鉛フリーらしく ハンダが残っているものの そのまま熱を加えてもうまく付かない。結局ハンダを追加して、あとで ハンダ吸い取り線で掃除。

確認用 LED は、100 Ωが付いている ポートに、Vf が高い 1608 の黄色を選択 。カソード側は レジストを削っている。うまく 穴のフチに ハンダ付けできているように見えるが、なんどもやりなおしている。熱を加えすぎて LED の 樹脂部分が分離してしまう。同じ 1608 の赤と違い 黄色はハンダ付けが難しい。

最後に ハンダ吸い取り線で掃除。ハンダ吸い取り線大活躍。

あと、水晶のところ、NC に見えたところは シールドに接続されていた。一応 レジスト削って GND に接続。

あと、ボタンモジュールも作成。



実をいうと失敗したかも。短辺のほうは ぴったりなのだが、長辺は、広すぎて タクトスイッチが浮く。それは正しい実装なのだが、ぴったりくっつける場合には、1mm ほど幅を狭くしたほうが良いみたい。

ボタンモジュールは、基本楽勝なのだが、1ヶ所 3連ダイオードの HN2S01FU を使ったので、ハンダ付けが難しかった。ピッチは 0.65mm で 多少厳しい程度だが、小さいので位置決めが難しい。アノードは Common なので、カソード側を優先して 位置決め→ハンダ付け。アノード側は、ハンダを盛ってごまかす。



ケースに合わせてみた。本来は LCD が表なので 裏向き。スイッチモジュールは メイン基板と重ならないように付ける。

これで、残りは バッテリー周りと LCD 。だが、最後に付ける予定で、ひとまず第一形態完成。

次はソフトがメイン。

posted by すz at 22:12| Comment(36) | TrackBack(0) | SRT162

2009年09月18日

A25L080 の使い方

ボチボチ ソフトの方も検討していこうと思う。まずは、シリアル FLASH の A25L080 から。

互換品について


こいつは、KDPDK15 などを分解したときに LCD モジュール と共に外して使う。壊してしまったり 単独で使うときのために互換品を探したところ、AT26DF081A が見つかった。

これの系列には、AT25DF041A (4Mbit) , AT26DF161A (16Mbit) , AT25DF321(32Mbit) などがある。AT26DF161 (16Mbit) , AT26DF321 などは、3.3V で使えないので注意。

ちなみに 、よく似た名前の AT25080 とかがあるが、1/1024 の 8K bit の EEPROM 。これともピン配置は同じで、コマンド体系も似ている(というかこちらがオリジナル)。

ここでは、A25L080 と AT26DF081A を見比べて共通に使える機能のみを対象に使い方を検討していく。

基本的な通信手順


通信は SPI mode 0 を使う。ソフトで行うときは、

    SCK 正論理 (初期状態 L )
    1bit send : データを SI にセットして SCK を↑
    1bit recv :↑後、データを SO から取り込み SCK を ↓

こんな手順。

通信は 8bit 単位。送受信順は MSB first 。

通信フォーマット

A25L080 のデータシートでは、

  • コマンド 1 バイト
  • アドレス 0 〜 3 バイト
  • ダミー 0 〜 3 バイト
  • データ 0 〜無制限

という風に説明されている。1つのコマンドシーケンスの前に CS ↓ 終わったら CS ↑するのが基本らしい。

データ長 は 0 でなければ、1〜無制限というのが多い。無制限ということは、CS ↑しなければ終わらないということ。

コマンド



  • シグネチャの読み込み (9Fh : RDID)


      send recv
      1 9Fh xx
      2 xx ベンダーID
      3 xx デバイスID 1
      4 xx デバイスID 2


      Vend ID1 ID2
      A25L080 37h 30h 14h
      AT25DF041A 1Fh 44h 01h
      AT26DF081A 1Fh 45h 01h
      AT26DF161A 1Fh 46h 01h

      M25P20 20h 20h 12h (追記参照)
      M25P40 20h 20h 13h (〃)
      M25P80 20h 20h 14h (〃)

      SST25VF016B bfh 25h 41h (〃)
      SST25VF016B bfh 25h 4Ah (〃)
      SST25VF016B bfh 25h 4Bh (〃)

      MX25L1605D C2h 20h 15h (〃)
      MX25L3205D C2h 20h 16h (〃)
      MX25L6405D C2h 20h 17h (〃)


    まずは、シグネチャーを読んで使えることを確認。容量の認識やブロック消去方法も この情報を元にする。

  • リード (03h : READ)


      send recv
      1 03h xx
      2 AA xx アドレス2 (上位 8bit)
      3 AA xx アドレス1
      4 AA xx アドレス0 (下位 8bit)
      5 xx DD データ0
      : : :


    この READ コマンドは、古いコマンドで、A25L080 では 50Mhz , A26DF081A では 33MHz が最大周波数。アドレス後1バイトのダミーを入れることで、最大周波数が 2倍の 0Bh: FAST_READ コマンドが両者にある。(今回は使わない)

    さらに、SI/SO を出力に使う FAST_READ_DUAL_OUTPUT なんてものが A25L080 にはあり 100Mhz で動くので、なにか面白い使い方ができるかも知れない。(今回は使わない)

    SRT162 では、PD の USART に接続しているので、同じく PD を使う LCD と同時には使えない。通常はバッファリング して使うことになる。

    ただ、SPI とは、同時に使えるので、A25L080 から読み込みつつ、SPI に出力するという使い方ができる。

    たぶん API 的には、open と close があって、1 バイトづつ読み込む getch みたいなのを inline で定義するのが基本で、それを使って バッファへの read 関数を作ることになりそう。

    ちなみに、USART は、最大 1/2 CPU_CLK のビットレート。1 バイト転送するのに 16 クロック。USART なら 2 バイトづつの転送も可能で、うまく作れば CPU_CLOCK 8MHz で READ 512KB/sec 出せる。

  • ページプログラム (02h : PAGE_PROGRAM)


      send recv
      1 02h xx
      2 AA xx アドレス2 (上位 8bit)
      3 AA xx アドレス1
      4 AA xx アドレス0 (下位 8bit)
      5 DD xx データ0
      : : :
      260 DD xx データ255


    かならず 256 バイト境界で、256 バイト のデータを書かないといけない。

    それぞれの ページプログラムの前に、05h: RDSR コマンドで、Write 可能かどうかのチェックが必要。さらに、06h: WREN コマンドで Write Enable Latch (後述) を set しなければならない。Write が完了すれば、Write Enable Latch は reset される。

    ちなみに ページプログラムの時間は Typ で A25L080 は 1.5ms 、AT26DF081A は 1.2 ms 。Max はどちらも 5ms 。

    データ転送の時間を 0 としても Typ で 17KB/sec 相当と遅い。だから 普通は書き込みをせず リードオンリーのデータを置くような使い方になるはず。

  • ライト許可 (06h: WREN)

      send recv
      1 06h xx


    WREN コマンドを発行すると、 Write Enable Latch がセットされる。消去やページプログラムをするには、Write Enable Latch がセットされていなければならない。

    それらの処理が終わると自動的に reset されるようだ。

    ただこのビットはただのラッチであり、実際に プログラム や消去ができるのかどうかを示すものではないようだ。

  • リードステータス (05h: RDSR)


      send recv
      1 05h xx
      2 xx DD ステータス
      : : : :

      ステータス情報
      共通:
      bit7 : SRWD -- Status Register Write Disable
      bit1 : WEL -- Write Enable Latch
      bit0 : WIP -- Write in Progress

      A25L080 :
      bit4 : BP2 -- block protect
      bit3 : BP1
      bit2 : BP0

      BP2-0 プロテクトされる 消去ブロック番号
      0 なし
      1    15
      2 14,15
      3 12-15
      4 8-15
      5 0-15 (all)
      6  0-15 (all)
      7  0-15 (all)

      AT26DF081A :
      bit5 : EPE -- ERASE/Program Error
      bit4 : WPP -- Write Protect Pin
      bit3 : SWP1 -- Software Protect Status
      bit2 : SWP0


    WEL、WIP は上述した。これに加えて、SRWD というのがある。WP ピン が セット(L) されている状態では無条件に 1 だが、そうでない場合、ライトステータスコマンド(01h: WRSR) で、0 にできる。(ソフトウェアプロテクト)。

    AT26DF081A の場合、 Erase/Program Error という便利そうな情報があるのだが、A25L080 のほうはない。これに頼らない違う方法を使わなくてはならない。

  • ライトステータス (01h: WRSR)


      send recv
      1 05h xx
      2 DD xx ステータス

      ステータス情報

      共通:
      bit7 : SRWD -- Status Register Write Disable

      A25L080 :
      bit4 : BP2 -- block Protect 2
      bit3 : BP1
      bit2 : BP0




消去系コマンド




  • セクタ消去 (20h : SECTOR_ERASE)

    send recv
    1 20h xx
    2 AA xx アドレス2 (上位 8bit)
    3 AA xx アドレス1
    4 AA xx アドレス0 (下位 8bit)

  • ブロック消去 (D8h : BLOCK_ERASE)

    send recv
    1 D8h xx
    2 AA xx アドレス2 (上位 8bit)
    3 AA xx アドレス1
    4 AA xx アドレス0 (下位 8bit)

  • チップ消去 (C7h : CHIP_ERASE)

    send recv
    1 C7h xx



A25L080 と AT26DF081A の共通機能は、4KB 単位のセクタ消去、64KB 単位の ブロック消去、チップ全体の チップ消去の 3 種類。

コマンドは簡単だが、これにかかる時間がすごい。


    A25L080 AT26DF081A
             Typ Max Typ Max
    セクタ消去 0.3 0.5 0.05 0.2
    ブロック消去 0.8 1.0 0.40 0.95
    チップ消去 8 20 6 16 (単位 秒)


まぁ、ブロック消去が効率よくて、チップ消去はそれを順番にやっている感じ。セクタ消去は 一応できるというレベル。

データ配置は、できるだけ 64KB 単位がよい。小さなデータでも 4KB 単位に配置しなければならない。

プロテクトできる範囲は、A25L080 では、64KB 単位のブロックで 15, 14-15, 12-15 の 3 種類だけ。AT26DF081 は、0-14 の 64KB 単位と 最後の 64K を 16K,8K,8K,32 に分けた合計 19 のエリアそれぞれにプロテクトできる。

A25L080 の方が機能が低いから、これに合わせて 上位の いくつかのブロックをプロテクトできると考えたら良さそうだ。

でも、たぶん使わない。

こいつに置くデータは?


まず、フォントデータ。ぞろよしさん作の k12x10 を使おうと考えている。これを使った場合 128x128 のエリアに 全角で 10桁 12行が表示できる。

フォントの形式は、FONTX2形式 が普通らしいが... なやみ中。
どのフォント形式を選ぶにせよ 64KB 単位にするなら 192KB のエリアを使用することになる。

つぎに 置きたいのは ロードするファームウェア。

せっかく、画面とボタンがついているのだから、インタラクティブに プログラムをロードできても良さそうなものだ。

ブートローダを入れ替えることによって、シリアル FLASH からロードするようにすればよいはず。ただ、USB からのロードが出来ないと 最初に シリアル FLASH に書き込むことができない。両方の機能を入れると ブートローダのサイズが問題になりそう。

ところで、エリアの割り付けの話。AT90USB162 を使うのだから 最大 16KB なわけだが .. ATmega32U2 なんてのもあるそうだし、プログラムによってはデータを沢山置きたいかも知れない。

64KB 単位で配置するけれども、簡単な管理情報を 各エリアの先頭とかに置いて管理したほうがよいかも知れない。

追記:M25Pxx

M25Pxx 系も おなじコマンド体系だった。ただし、4KB 単位の ERASE は使えない。あと古いものでは、RDID をサポートしていないようだ。RDID がないタイプでは、RES(0xab) コマンドを使う。

RES コマンドには Deep-Sleep からの復帰という機能もあるが、そのケース以外では次のシーケンスで、 デバイスType が得られる。

    send recv
    1 ABh xx
    2 xx xx
    3 xx xx
    4 xx xx
    5 xx デバイスType

    デバイスType:
    11h 2Mbit
    12h 4Mbit
    13h 8Mbit


追記:23K256

SPI RAM の 23K256もピンアサインが同じ。コマンド体系も似ている。

追記: SST25VF016B

    16Mbit の SST25VF016B が安いらしい。
    シグネチャは、bfh, 25h, 41h
    0Bh: FAST_READ コマンドあり。
    セクタ消去 (20h : SECTOR_ERASE 4K) あり。
    ブロック消去 (D8h : BLOCK_ERASE 64K) あり。

    SST25VF032B bfh, 25h, 4ah
    SST25VF064Cbfh, 25h, 4bh

    買えるのは、SST25VF032B のみか。


追記: MX25L1605AM2

2.4 inch の フォトフレームを分解したら MX25L1605AM2 と刻印がよめるチップが載っていた。調べると MX25L1605D のデータシートが見つかった。

0Bh: FAST_READ コマンドあり。
セクタ消去 (20h : SECTOR_ERASE 4K) あり。
ブロック消去 (D8h : BLOCK_ERASE 64K) あり。

MX25L1605D C2h 20h 15h
MX25L3205D C2h 20h 16h
MX25L6405D C2h 20h 17h
posted by すz at 20:02| Comment(0) | TrackBack(0) | SRT162

2009年09月17日

SRT162 パーツリスト

一応、基板も発注したし、パーツリストをまとめておこうと思う。


R1,R2 22 SMD 2012
- USB 信号線 制限抵抗
- 回路図は 33 と書いてあるが 22 の方が良い。(修正予定)
R3 470 SMD 2012
- LED 用制限抵抗 (LED による)。
R4 4.7k SMD 2012
- バッテリー充電電流決定用 ( 重要 )
- 4.7k は 間違い。210mAH 用は 9.1K
- 130mAH 用は 15K 。(or 33K x2 親子 )
- 充電電流は 1/2 C にする。
- 計算は、1000 * 1000 / 電流 (mA)
R5,R7,R9 1k SMD 2012
R6,R8,R10 4.7k SMD 2012
R11,R14,R15,R16 47k SMD 2012
- プルアップ
- 33k はスイッチ系で使うので、違う値にした。
- R11,R14-16 はたぶん不要。
R12 33k SMD 2012
- HWB OFF (プルアップ)
R13 3.3k SMD 2012
- HWB ON (プルダウン)
- R12 >> R13 であること
R17,R18,R19,R20 100 SMD 2012
- 電流制限抵抗 電圧差 3V で 30mA 。
- デバイス制御で 出力がかち合ったときの対策
         - LED 直結可
C1,C2 22p SMD 3216
- データシートでは 12p 〜 22p
- 秋月 10p (3216) で代用予定。
- ダメなら x2 親子。
C3,C6,C8 1u SMD 1608
C9,C10,C11 1u SMD 1608 (SRT162A のみ)
- 秋月 1u
- C3 は 不要 (C6 の隣に配置したので)
C4,C5,C7 10u SMD 2012
- 秋月 10u

D1 SMD 3216
- 1608 も可
- 充電中インジケータ
- 秋月 チップLED から適当に (R3 とペア)
Q1,Q2 SMD SOT-23(SC-59) PNP 秋月 2SA1162-GR など
- デバイス用 SW は、Tr 指定。
- バックライト用は、FETが良いかも。
Q3 SMD SOT-23(SC-59) NPN 秋月 2SC2712-GRなど
         
X1 16MHz 秋月 FA238

U1 AT90USB162 TQFP-32 ( 0.8mm ピッチ)
U2 MCP73831T-2ACI SOT-23-5 (0.95 mm ピッチ)
- バッテリー充電制御
- 2ACI は、標準的 充電最大 4.2V 用
- 使用しないときは、3 - 4 ピンをショート             
U3 MCP1700T-3302E SOT-23
- MCP1702 でも可
- 違いは最大入力電圧で、MCP1700 は 6V 。
- XC6206 やその互換品
- KDPDK15 などからの外し品も OK 。
U4 A25L080M SOP-8 (1.27 mm ピッチ)
         - KDPDK15 などからの外し品
- AT26DF081A で代用可の予定

CONN3 COG-C144MVGS (SRT162A のみ)
- KDPDK15 などからの外し品
CONN3 BG999076A (SRT162B のみ)
- KDPDK15 などからの外し品

SW1(RESET) 秋月 TSKB-2JLLS6J2M-T
SW2(PGM) 秋月 IS-2235


2012 抵抗 について



共立エレ 表面実装用チップ抵抗(詰め合わせパック) をベースに、補充は 足りなくなったり多く使う予定があれば、千石 でバラ買い
	
【数量1〜3組】 10個1組で税込 \53
【数量1〜6組】 50個1組で税込 \210



そういえば、共立のページ 9月上旬入荷予定とあるが 去年の話。とっくに入荷しているので注文できる。

SRT162 バグ情報



実際に 発注したデータは、srt162-007a.zipなのだが、バグ等問題があれば、ここにメモしていこうと思う。

1) シリアルFLASH の CLK の接続間違い (SRT162A/B 共通)

PD5(XCK) を接続しないと ハードSPI が使えないのだが、間違えて PD6 を接続してしまった。とりあえず ソフトSPI でテストしているが、いずれ 高速化するときに問題になる。




LDOレギュレータについてのメモ



MCP1700/1702/1703 について混同していた。なにが違うか分からなかったが、ここを見て分かった。

要するに、入力最大電圧が、MCP1700 は 6V 、MCP1702 は 13.2 V、MCP1703 は 16V 。ただし、MCP1703 は VDO が高い (= 最低電圧が高い)。

普通は 安定化 5V を使う前提で MCP1700 で良いはず。

ところで、この MCP1700 の精度 AVG だが 0.4 % と高い。グラフで読み取るしかないが、温度係数もかなり良い。 さらに、消費電流が、(負荷がないとき)1.6 uA と やたら小さい。

1.2V のやつとかを基準電圧として使うといいかも。

あと、PWM を DAC がわりに使う場合、電源の精度とかノイズが重要になるはずで、精度が高くて余裕があるものを使う必要がある。... でも普通はデジタル回路もいっしょに乗っているから厳しい。
CMOS インバータとかを出力用に別に付けて、その電源を こいつで作るとかすると良いかも。

そういえば、昔読んだ D級アンプの本では、オペアンプみたく負帰還かけていた。そのため PWM と似ていても 電源の影響を受けにくいらしい。

    思い出した、ICM7555 ひとつで D級アンプが作れるような気がする。

    ポイントは、負帰還。LMC555のアプリケーションノートには、Control 入力で パルス幅変調ができるなどと書いてある。そのままでは直線性が悪いからダメだが負帰還をかけられれば問題なくなる。あるいは、50% duty で、発振用 CR に 入力するか ... どちらかで負帰還になるよう にできれば 作れるはず。特に 50% duty は、出力と逆の論理の disch が空いている。

    もうひとつのポイントは CMOS で 100mA 流せること。CMOS ということは、Push-Pull なわけだ。電流さえ流せれば スイッチング電源や D級アンプ的な使い方ができる。だが電流が流せる CMOS なんてのはあまりないのだ。


AT90USB162 について



ATmega32U2/ATmega16U2/ATmega8U2 というのが出るらしい。ただし 機能はほぼ同じ。... 命令数も 125 と変わらず。

掛け算命令がないのに mega とは ... どういうこと?

それはともかく、32KB 品 (RAM 1KB) が出るのは良いことだ。




コネクタのピンアサイン


    CONN1

    1 PC2
    2 PD7
    3 PD6
    4 PD5/XCK
    5 PD4
    6 PD3/TXD
    7 PD2/RXD
    8 PD1
    9 PD0/OC0B
    10 GND

    CONN2
    1 VCC(3.3V)
    2 GND
    3 PC5/OC1B (NPN OC)
    4 NC
    5 DEV_VCC (3.1V)
    6 PB3/MISO (100 ohrm)
    7 PB1/SCK (100 ohrm)
    8 PB2/MOSI (100 ohrm)
    9 PB4/T1 or RESET (100 ohrm)
    10 GND




部品メモ


  • せっかく USB の装置の基板を起こすのなら、ポリスイッチぐらい入れてもよかった。

    秋月の microSMD010は、3225 サイズで 200mA で 切れる。バッテリー充電で 100mA 程度しか流さないのだから ちょうどよいかんじ。場所も余裕あるし。

  • MCP73831 のマニュアルでは、バッテリーがなくとも 動作するようなことが書いてあるが、普通に使えるのかどうかいまいち不安。

    3.3V LDO への入力に USB 5V と バッテリーを SBD を通してつないでもよかったのではないか?

    MCP73831 の調子を見て決めよう。

  • デジタルトランジスタの 採用

    表面実装 抵抗は、意外に面積使うし デジタルトランジスタを使ったほうがよいのではないか? 鈴商とか けっこう扱っているみたいだし。10個 105円と割りと安いし。

  • 抵抗が多すぎる

    不要ということが分かったら、パターンから抜こう。

  • 電源スイッチ

    電源スイッチをなくして、バッテリ + 常時 ON という仕様だが、それで良かったのか?

  • 端子1

    内部配線専用の端子が LCD 用に 、WR/RD/CS/CD と 4 本もある。
    LCD を使わないときのことを考えると パッドぐらい出しておいてもよかったのではないか?

  • 端子2

    R17-R20 を付けて LED を直接駆動できるのだから、ちょっとLED を差し込んでテストできるようなことを考えても良かったかも知れない。

  • 大穴

    ピンソケットの端子部分を打ち込めるようにしてみたい。
    昔そういう実装をみてから、一度やってみたいと思っていた。

    足を残せば それ自体 IC みたいに使えるし、切れば 超ロープロファイル IC ソケットみたいにできるし。

posted by すz at 22:27| Comment(0) | TrackBack(0) | SRT162