2010年12月09日

TPI/PDI

ATtiny10 などで新規に採用された プログラミングインターフェイス TPI(Tiny Programming Interface) を調べてみることにした。

この TPI の基本プロトコルは XMEGA で採用された PDI と よく似ている。調べる際 PDI との違いについてもチェックすることにした。

物理層



TPI PDI
リセット RESET x
クロック TPICLK PDI_CLK
データ TPIDATA PDI_DATA
開始方法 (1) RESET を L
(2) TPIDATA を H (1) PDI_DATA を H
(3) TPICLK x 16 (2) PDI_CLK x 16
(4) KEY送付 (3) KEY送付
終了方法 RESET を H PDI_CLK 停止

こんな感じ。データの送受信は 8bit + Parity EVEN + STOP2 が基本で、1本の DATA 線を TX/RX で 共有する半二重。

  • PDI は パリティを常に守るわけではなく パリティ を 無視する 特殊なデータがある。9bit + Parity NONE と思ったほうが しっくりする。

  • PDI は CLK を送付しつづけないといけない。これが扱いにくいところで FT232RL でライターを作ろうとすると エラーが起きたら最初からやりなおす -- みたいな処理が必要になる。(avrdude の terminal mode を愛用しているのだが、特に このモードと相性が悪い)

コマンドセット


TPI も PDI も 『FLASH に書く』といった コマンドがあるわけではない。メモリ空間に レジスタがあって プログラムとおなじようにレジスタにアクセスすることで、FLASH に書き込んだりする仕組み。

コマンドセットは、次のようになっている。

    TPI PDI
    READ ( アドレス直接指定 ) SLDCS LDS
    READ ( ポインタ間接 ) SLD LD
    READ ( ポインタ間接 ++) SLD LD
    WRITE ( アドレス直接指定 ) SSTCS STS
    WRITE ( ポインタ間接 ) SST ST
    WRITE ( ポインタ間接 ++) SST ST
    ポインタ設定 SSTPR ST
    キー設定 SKEY KEY
    READ ( IO空間専用 ) SIN x
    WRTIE (IO空間専用 ) SOUT x
    READ ステータス SLDCS LDCS
    WRITE コントロール SSTCS STCS
    繰り返し指定 x REPEAT
    注) ++は ポストインクリメントつき

完全ではないが、まぁこんな感じ。TPI には REPEAT がないが、空間が小さいから 必要ないのだろう。

さて、コマンドを送れば結果が返ってくる(ものがある) 。そのときに 送信/受信が切り替わるわけだが、ガード 期間が定義されていて、一定期間(クロック)後から 結果を返すようになっている。

この ガード 期間 最小 2 クロック。設定によって +128 クロックまで期間を長くすることができる。

    TPI は、それを設定する専用のレジスタがある。PDI は、コントロールレジスタで 専用のコマンドで設定する。

    なお、このコマンドセットは XMEGA では JTAG に (ほぼ)マッピングできるそうだ。

ライタの設計



TPI/PDI はこういうものなので、いくつかの空間に対して READ/WRITE するような メソッドをライタで提供し、あとは上位レイヤで やってもらう -- というのが 一つの案。

avrdude-5.8 のソース(AVRISPmkII とかに XMEGA用のコードがある)を見てみたのだが、AVRISPmkII も 実際 そういう仕組みになっている。そして avrdude.conf に 各空間の 定義が書いてあり、その定義によって操作するようだ。

もう一つの案として、物理レイヤーをそのまま見せる方法も考えられる。

  • TPI だと

      DTR : クロック送出
      RTS : リセット ON/OFF

      みたいな割り当てをする。で、TX/RX の 共有 をどうするか ... が問題だが AT90USB162/ATMEGA32U2 など コントローラで制御するなら 比較的簡単に 対処できる。

        外付け回路を付けるなら、TX の START BIT から 12 クロック 分 ゲートを開く .. みたいなのが良いかも。

        AT90USB162/ATMEGA32U2 だと PORT の設定をプルアップにしておいて、送信するときだけ TXEN(送信許可)を enable にすれば良さそう。RXEN(受信許可) については、自分の送信データを受信してチェックしても良いし、送信中は disable にしても良いかも知れない。

          追記: PDI では、受信時 プルアップではなく HI-Z にしなくてはならない。プルアップでは衝突検出に引っかかって動かない。(確認した)

        さて、XCK , TX/RX を割り当てるのは必然なのだが、RESET にはなにを割り当てたら良いのだろう? PORTD ならなんでも良さそうだが、過去に作ったボードもチェックして決めようかと思う。


    • 問題なのは PDI 。パリティエラーになるデータを扱っている。これはいったいどうしたものか。

      パリティエラーになるデータは 3 つで、BREAK(0xBB) / DELAY(0xDB) / EMPTY(0xEB) 。
      BREAK は、HOST が中断のために送出するデータで シリアルの SEND_BREAK にマッピングできる。(ちなみに TPI も BREAK があるが、シリアルの BREAK 信号そのもの )

      これがあるだけで、普通の シリアルにマッピングするのが難しい。JTAG インターフェイス にマッピングするのが妥当のような気がしてきた。

        追記: 上記の特殊キャラクタは JTAG のみの話だった。勘違い。TPI と同じでシリアルにマッピング可能。

      ただ、そういうのをわざわざ作っても 遅延の問題があるから あまり高速にできない。結局 メモリ空間を指定してブロック転送するもの を作るほうが 高速になりそうなのだ。

    USBasp の拡張案


    そう言えば ... USBasp のプロトコルにマッピングできないだろうか?

      USBasp にも メモリ空間に対してブロック転送する コマンドはあるのだ。

        SETLONGADDRESS -- 32bit のアドレスを指定
        READFLASH -- FLASH から読み込み (最大 200バイト)
        READEEPROM -- EEPROM から読み込み
        WRITEFLASH -- FLASH に書き込み (最大 200バイト)
        WRITEEEPROM -- EEPROM に書き込み

      SETLONGADDRESS は 32bit あるので、高位アドレスを使い 対象空間を変えることにすれば 多数の空間を扱える。それに FLASH と EEPROM の 2 つの空間も使える。

      EEPROM          FLASH
      TPI IO空間 全空間
      +コントロールレジスタ (0x80 ずらしてマップ)
      PDI コントロールレジスタ メモリ空間

      こういう空間マッピングが良いかも知れない。これなら 上記の コマンドセットの機能を全部使える。

      で、そういう動作にするモードを指定する には どうしたらよいのだろう?

        CONNECT -- TARGET と接続する。
        DISCONNECT -- TARGET を切り離す
        ENABLEPROG -- TARGET をプログラミングモードにする

      こんなコマンドがある。avrdude-5.8 の usbasp のコードを見てみたが、USBの CONTROL パケットの INDEX / VALUE は all 0 。CONNECT の コマンドで mode を設定すれば 切り替えるようなことはできそうだ。

        CONNECT で value_h を プロトコルバージョン とみなし 2 だったら value_l によって メソッドを変える。予定では 2 が TPI 3 が PDI (1 は ノーマルの別チャネルとか)

        という風にすることに決めた。

      ちなみに、その他のコマンドは次のものだけ。

        TRANSMIT -- 4バイトの ISPコマンドを実行する
        SETISPSCK -- BIT CLOCK を設定する。(通常 AUTO 指定)

      SETISPSCK はそのまま使う。TRANSMIT は サポートする必要はない。が、シグネチャー読み出しぐらいは、シミューレートしても良いかも知れない。それ以外にも プログラマ自身の設定を変えたり、ステータスを返したりする機能を仕込むとデバッグが楽になるかも知れない。


    ... というわけで、AT90USB162/ATMEGA32U2 に 移植した USBasp を改造してみようと思う。
    serjtag でやろうとも思ったが まだベースも動いていないし。

    ここまで書いた段階で、avrdude tpiでググってみた。

    • あ、LUFAに、AVRISP-MKII Clone が入っていて PDI/TPI をサポートしているのか。

    • 実装例のひとつが、USBTiny Mkii

      これを読むと、Avrdude 5.10 support for ISP, PDI and TPI と書いてある。

    • ほかに TPI bitbang implementationというのも投稿されているなぁ。最新版に入っているのだろうか?

    USBTiny Mkii は、AT90USB162/ATMEGA32U2 を使っているみたいだし、すなおに LUFA 使えば簡単そうではある。ただ libusb-filter 入れろとか ちょっと気になることが書いてある。

    まぁ、AVRISPmkII は 秋月で 3300円だから すなおに AVRISPmkII 買ったほうがお勧めではある。

    なんというか、使うより作るのが目的のようなものだから、この方針のまま検討を進めよう。ライタのファームウェアより avrdude での対応が 面倒で そっちの方が重要。-- なにはともあれ、avrdudeの最新版 5.10 を見てみよう。

    あと、デバイスをなんとかしなくては。XMEGA は 16A4 と 192D3 を確保済みだが、ATtiny10 は買えるのか?

      デジキーだと ATtiny10 のリードタイムは 1/12/2011 だそうだ。ATmega32u4のリードタイムも 1/23/2011 だし、この際 発注しておくか。


追記: avrdude-5.10 をチェック

avrdude-5.10を見てみた。観点は、どんな風に実装されているか。

まず、flags に AVRPART_HAS_PDI , AVRPART_HAS_TPI が設定される。これを見て動作を切り分ければ良いようだ。

また、AVRPART_HAS_PDI を見ているのは、jtagmkII.c と stk500v2.c のみ。さらに、AVRPART_HAS_TPI まで見ているのは stk500v2.c のみ。... どうも stk500v2.c だけチェックすれば良いようだ。

で、stk500v2 は、次のメモリタイプがあるらしい。

stk500v2_private.h:
avrdude mapping
XPRG_MEM_TYPE_APPL 1 "flash","signature"
XPRG_MEM_TYPE_BOOT 2 "boot"
XPRG_MEM_TYPE_EEPROM 3 "eeprom"
XPRG_MEM_TYPE_FUSE 4 "fuse"
XPRG_MEM_TYPE_LOCKBITS 5 "lockbits"
XPRG_MEM_TYPE_USERSIG 6 "usersig"
XPRG_MEM_TYPE_FACTORY_CALIBRATION 7 "calibration"

stk500v2 は、こうなっているだけの話で、そういう風なメモリタイプの分け方をする必要はないらしい。

avrdude.conf の定義はこんな風になっている。

# ATXMEGA16A4
       :
signature = 0x1e 0x94 0x41;
has_jtag = yes;
has_pdi = yes;
nvm_base = 0x01c0;
:
memory "eeprom"
size = 0x0400;
offset = 0x08c0000;
page_size = 0x20;
readsize = 0x100;
;
memory "flash"
size = 0x00005000;
offset = 0x0800000;
page_size = 0x100;
readsize = 0x100;
;
memory "usersig"
size = 0x200;
offset = 0x8e0400;
page_size = 0x100;
readsize = 0x100;
;
memory "signature"
size = 3;
offset = 0x1000090;
;

offset や readsize が定義されているので、write はともかく read するのには苦労しなさそう。
では、TPI のほうはどうなっているのだろう。

# ATtiny10
:
signature = 0x1e 0x90 0x03;
has_tpi = yes;
:
memory "flash"
size = 1024;
offset = 0x4000;
page_size = 16;
blocksize = 128;
;
memory "signature"
size = 3;
offset = 0x3fc0;
;
memory "fuse"
size = 1;
offset = 0x3f40;
blocksize = 4;
;
memory "calibration"
size = 1;
offset = 0x3f80;
;


まぁ、同じような感じ。

write は、それぞれのメモリタイプ毎の方法を知ってないといけないにしても usbasp 拡張への対応はあまり難しくないような気がしてきた。

追記: コード作成中

大分出来てきた。いろいろ分かってきたので訂正。

  • PDI の特殊コードのうち DELAY と EMPTY は単に無視すれば良さそう。そして残る1つの BREAK は、本当の BREAK と同じ扱いで良さそう。

    具合が悪いこともあるかも知れないが、たぶんタイムアウトでなんとかなる。

    ... そうなると 半二重 + 同期 という特殊なモードを作れば、シリアルのインターフェイスで対応できそう。 それはそれで面白いかもしれないが、とりあえずは、USBasp の拡張をやってみる。

  • TPI で NVM(FLASH など不揮発メモリの総称) に書くには、NVMCMD に WORD_WRITE を設定してから、SST で WRITE するようだ。チップイレーズは、NVMCMD に CHIP_ERASE を 設定して WRITE 。その後 ビジーフラグをチェックする。終わったら NOP を設定しておく。

    PDI も 似たような感じではある。が、機能が多い上に 領域毎に専用コマンドがあったりして すごく面倒。
    こんなのは、上位レイヤーの avrdude でやりたいのだが、ブロック書き込みだと ページ毎に NVMCMD を設定してやらないといけないので、なかなか厳しい。

  • TPI は 空間が 3 つあった。グローバルな空間 と I/O 空間 と コントロール・ステータス空間。仕方ないので、I/O 空間 と コントロール・ステータス空間 の 2つをアドレスで切り分けて もとの EEPROM 空間にマップすることにした。

    PDI では空間は グローバルな空間 と コントロール・ステータス空間の 2つしかないのだが、実を言うと NVM 制御用に 別の空間を定義したくなった。NVM 制御では、ポインターは使わないので、アクセス方法が違う。ただ、1 バイトアクセスが多いので ブロック転送よりは、ISP コマンドでアクセスするほうが効率が良さそうなのだ。なかなか悩ましい。

  • それはそうと、LUFA のコードは 参考になる。実際に動くコードというのは貴重だ。

追記: コード作成中(2)

コード作成がだいぶ進んで、テストに入れそうなぐらいになってきた。ちょっと難しかったところがあるのでメモしておく。


  • NVM_CMD

    FLASH とか EEPROM に書き込む時の手順が難解だった。マニュアルに載っているわけだが、よくわからなかったし、細かいことはやはり分かっていない。

    ページ単位で書き込める リソースには、EEPROM / FLASH(APP) / FLASH(BOOT) / USERSIG と FLASH(ALL) の 5 つがあるようだ。それぞれ NVM_CMD が違う。また FLASH(ALL) は、APP と BOOT のエリアを統一的に扱うもののように見えるが詳しくはわからない。

    これらの書き込みは、NVM_CMD は違うものの 手順 は同じようだ。

    手順はこんな感じ 。マニュアルの用語がわかりづらいので 自分流の用語にしている。

      (1) ページバッファ消去 (CLEAR_BUFF)
      (2) ページバッファへのデータのロード (FILL_BUFF)
      (3) ページ消去 (ERASE_PAGE)
      (4) ページバッファのページへの書き込み (WRITE_PAGE)

      この手順が書いてあるのだが、私には次の方が理解しやすい。

      (1) boot_page_erase (A) ページ消去 (ERASE_PAGE) (B) ページバッファ消去 (CLEAR_BUFF)
      (2) boot_page_fill ページバッファへのデータのロード (FILL_BUFF)
      (3) boot_page_write ページバッファのページへの書き込み (WRITE_PAGE)

      左のは、ブートローダでの自己プログラミングの関数で、この手順だと同じようなことをしていると理解できる。


      EEPROM APP BOOT USERSIG (FLASH)  trigger poll
      (1A) ERASE_PAGE 0x32 0x22 0x2A 0x18 0x2B SPM NVMBUSY
      (1B) CLEAR_BUFF 0x36 0x26 0x26 0x26 0x26  NVMEX NVMBUSY
      (2) FILL_BUFF 0x33 0x23 0x23 0x23 0x23 SPM
      (3) WRITE_PAGE 0x34 0x24 0x2C 0x1A 0x2E SPM NVMBUSY

      NVM_CMD はこのようになっている。CLEAR_BUFF / FILL_BUFF については EEPROM だけが違う。

      (2) の FILL_BUFF で実際に書くデータを埋めていく。SPM と書いてあるのは、PDI で ページがあるアドレスに対して Write する操作。FILL_BUFF だけがデータに意味があり、他は Write でアドレスのみが意味がある。

      さて、こんな風に リソースによってコマンドを切り替えないといけない。結局 stk500v2 のようなメモリタイプの定義になってしまった。残った(書き込む)リソースは FUSE と LOCKBITS のみ。これら は、上記のk記法で書くと

      FUSE LOCKBITS trigger poll
      o WRITE 0x4C 0x08 SPM NVMBUSY

      こう。NVM_CMD をセットして PDI で Write 。


  • USBasp とのインターフェイス

    いろいろ試行錯誤した結果こうなった。


        メソッド 型
    (NEW) ops.pgm_poll (void (*)(void))
    ops.pgm_disconnect (void (*)(void))
    ops.pgm_transmit (void (*)(uchar *, uchar *))
    ops.pgm_enable (uchar (*)(void))
    ops.pgm_read_space0 (uchar (*)(uint16_t))
    ops.pgm_write_space0 (uchar (*)(uint16_t, uchar))
    ops.pgm_read_space1 (uchar (*)(uint32_t))
    ops.pgm_write_space1 (uchar (*)(uint32_t, uchar, uchar))
    (NEW) ops.pgm_blk_start (void (*)(uchar, int16_t))
    (NEW) ops.pgm_open_page (uchar (*)(uint32_t, uchar))
    ops.pgm_close_page (uchar (*)(uint32_t, uchar))

    • (NEW) と書いてないものは、想定どおりで 従来の ISP用メソッドと 1:1 のマッピング。

    • pgm_poll はなんとなく付けたものでつかっていない。pgm_open_page は、page_size が分かれば必要ないのだが、pgm_close_page と対になるようにした。pgm_close_page は、ISP だと ispFlushPage にマッピングされる。

    • pgm_blk_start というのが純粋な新規インターフェイスなのだが、やっぱり事情がある。PDI は、REPEAT 命令があるから これから何バイト分 アクセスされるのか知っていたほうが都合が良い。最初は ブロック READ/WRITE のバイト数だけを引数にしていたのだが、この値は普通 200 で ページサイズとは無関係。上記で説明したように ページの切れ目で REPEAT を解かないといけないことに気づいたので、ページサイズも引数にした。

      ちなみに、pgm_read_space0/pgm_write_space0 は、もとは EEPROM 。これを 0x8000 のビットが立っていれば コントロール・ステータス空間 そうでなければ IO空間(PDI では レジスタがある下位アドレスに対するダイレクトアクセス) に割り付けた。
      pgm_read_space1/pgm_write_space1 はもとは FLASH で、全メモリ空間(PDI ではポインタによる間接アクセス)としている。

      さて、NVM_CMD の コマンドセットを切り替えなければ 書き込めないのだが、どうやって切り替えるか。
      いろいろ考えたのだが、pgm_transmit を使うことにした。ついでなので、ISP コマンドとの互換コマンドも少し取り入れて次のようにした。

      0x30 READ_SIGNATURE
      0xc0 WRITE_EEPROM
      0xa0 READ_EEPROM
      0xf0 CHK_BUSY
      0xac ISP_CONF - 0x80 CHIP_ERASE
      (PDI) 0xac ISP_CONF - 0x01 SET_SPACE
      (PDI) 0xac ISP_CONF - 0x59 RESET

    • READ_SIGNATURE は、まずは知りたい情報だから入れた。WRITE_EEPROM/READ_EEPROM は 上記の space0 への read/write と同じ機能。1 バイトアクセスが多いので こっちの方が使いやすそうだと考えた。 CHK_BUSYは、上記の NVMBUSY のチェック専用。ついでなので CHIP_ERASE も入れた。

    • PDI 用の新規コマンドの SET_SPACE は、上記 NVM_CMD コマンドセット切り替え。RESET は、RESET ON/OFF 用でリセットラインの機能。

    • FUSE と LOCKBITS までサポートするのは、面倒なのでやめた。コマンドを組み合わせて 上位レイヤで実装する。

  • 半二重 同期通信

    TPI/PDI で共通にすることにした。ベースは ゆきさんの R8Cプログラマ 随分変えてしまったが、基本は踏襲。もともと半二重通信を意識したコードだったので 都合が良かった。実をいうとまだ動くかどうかも分かっていないのだが、現状のやりかたをメモしておく。

    • 同期通信

      マニュアルみてもなかなか分からなかったのだが、同期通信 の 速度の設定 は SPIマスタと同じだそうだ。U2X1 は 無意味 -- ではなく 0 に設定する必要があるらしい。

      あと、UCPOL1 は 1 にするはず。これで、XCK からクロックが常時出るようになるのだろうか? 期待通りに 非同期通信のパラメータが効くのだろうか? 不安があるが.. まだテストしていない。

    • 半二重 処理。

      バッファ切り替えの出力も付けたいので完全な 半二重 処理 が必要になる。

      送信と受信が同時に enable されないように UCSR1B を次のように設定している。

      受信モード UCSR1B = (1<<RXEN1)|(1<<RXCIE1);
      送信モード UCSR1B = (1<<TXEN1)|(1<<TXCIE1)|(1<<UDRIE1);


      送信モード になるのは、最初にデータを送ったとき。送信完了割り込みで 解除。
      次々にデータを送る場合は、送信データ空き割り込みで 送られるので、送信完了になるのは、全部データを送信し終わったとき。

      送信を disable にしたとき 通常ポート動作に切り替わるが、pull-up モードにしておけば 問題なさそう。

      正しくデータを送ることができたならば、全部送信が終わらないと データを送ってこないはず。... これもちゃんとは確認してない。

    • その他の処理

      あとタイムアウトを入れている。データを送ってこないようなら エラーになるようにしている。これはベースと同じように 10ms タイマ割り込み。NVMBUSY のタイムアウトもあるので、タイムアウトのタイマー変数は 2 つ作っている。

      気になるのは、受信バッファ溢れ。REPEAT 命令があるからといって REPEAT 数を増やすと どんどんデータが送られてきて 溢れる結果になりそう。REPEAT 数 は 受信バッファのサイズと 同じにしておいた。

       - EMPTY とか DELAY の特殊データも 受信してしまうと 受信バッファが溢れるので、無視することにしている。
       - ただし、BREAK や 本当の受信エラーは 受け取りたいので バッファは 16bit 幅。

      ... といってもこれまた未テストで 少々不安。バグなら直せばよいが、仕様を読み違えていると 一気に不可能になるおそれがある。


追記: ここまでの ソースコード (もちろん未テスト)

  • usbasp.c (テキスト)
  • usbasp.h (テキスト)
  • angel_loader-1.1f.zip AT90USB162/ATMEGA32U2 ファームウェア


  • avrdude-5.10 の usbasp を いままで説明したプロトコルに対応させてみた。未テストで、これをデバッグするのだ。

    従来互換で、PDI/TPI のチップでは、切り替わるようになっている。

    ファームウェアの方も PDI/TPI 用のポートは切り替わる。

      PD2(RX)/PD3(TX)/PD5(XCK) と TPI 用の RESET に PD0 を使う。あと PD4 を バッファ制御用に使えるようにしている (L: TX / H : RX)。

    だが、ISP の場合も USART の SPIマスターモードを使ったほうが 良さそうな気がしてきた。

    ちなみに、正規の 6pin ISP コネクタは とっても適当なアサインになっている。
    AVR042(pdf) を見ると次の配置。()内は 割り当て案

    ISP TPI PDI
    (RX) MISO VCC (RX+TX)DATA VCC (RX+TX)DATA VCC
    (XCK) SCK MOSI (TX) (XCK)CLK N.C. N.C. N.C.
    (PD0) RESET GND (PD0)RESET GND (XCK) CLK GND

    TPI はまだ 良い。PD4=L で TX を RX に ミックスするようなもので 十分対応できる。
    PDI はそれに加えて XCK を PD0 に ミックスする別の制御線が必要になる。そして、PDI のとき PD0 は HI-Z にしておかなければならない。

    それに加えて、MOSI が N.C. にできてない。これも制御する信号線が必要なのだろうか? ... PDIの CLK が TPI の CLK の位置だったら 良かったのに。

追記: コードデバッグ中(1)


(pdi_base.alc : LAP-C ファイル)

シバ某のログ:実験結果小まとめ(TXT)も参考にして いろいろやって、ようやく 思ったようなコマンドが出せるようになった。ロジアナがないとデバッグは厳しい。買ってよかった。ちなみに、ソースコードは随分変わった(公開は別途)。

ターゲットには、XMEGA16A4 を使っているのだが、まだ XMEGA16A4 からの受信は成功していない。


  • 買ったロジアナの使い方すらよくわからなかったのだが、シリアルのデータ を出すには、BUS に信号を入れて BUS Proparty で設定することがやっと分かった。
  • クロックは 250kHz にしているが、TPI の ATtiny10 ですら 2MHz まで OK 。PDI だと 10MHz までいけるが、むしろ最低周波数 (10kHz) をクリアしないといけない。ロジアナの設定は、Find the baud ... にチェックすればよいらしい。 bps のところに数字を入力すればよい。
  • クロックはちゃんと出せていて、ちゃんと 立下りで 信号を切り替えている。
  • USART の同期モードでもちゃんと START BIT/STOP BIT が出ている。-- 未確認だったので、これすらできるか不安だったのだ。もう不可能ということにはならない。デバッグするのみ。
  • 送信は C1 59 81 と連続で出せているが、割り込み使ったバッファ処理は うまくいかなかったので、ポーリングに変更している。

追記: コードデバッグ中(2)

  • usbasp.c (テキスト)
  • usbasp.h (テキスト)
  • angel_loader-1.1h.zip (ファームウェア)
  • avrdude-serjtag04i.zip (usbasp 改造版 含む )


    (isp_base.alc : LAP-C ファイル)

    ISP の PORT を SPI から USART SPI に切り替える ISP2 というのも作っていて これは完成した。usbasp も対応して -c usbasp2 と指定すると チャネルを切り替える。TPI/PDI は どちらでも良いことにした。

    ただ、PDI のテストは進んでいない。ターゲットを 以前作った XMEGAボードにしようと思い製作中。

追記: コードデバッグ中(3)


    (pdi_test-bad1.alc : LAP-C ファイル)

    なんだかうまくいっていない。これは、ガード期間を短くしたときのもので 設定したガード期間を読みだそうとしたデータ。なぜかクロックに同期したデータが来る。

    で、いろいろしらべてみると、XMEGA には衝突検出のロジックがあって、値が 変化するときだけ出力するらしい。プルアップしてたので、XMEGA が ..00.. を 出力しようとしたらこれに引っかかる(はず)


    (pdi_test-bad2.alc : LAP-C ファイル)

    で、XMEGA が送信するタイミングでは HI-Z にするようにしたら L レベルになってしまう。



    ただちょっとうまくいきかけたこともあったのだ。なにか値を返そうとしている。が、1 回限りで 値もおかしい。

    ... 今思えば、pull-up してたから 途中で衝突検出にひっかかったのだと思う。...そうなると XMEGA を壊してしまったとか?

    ところで、TPI のほうにも衝突検出がある。こちらは、内部で pull-up して L レベル と Hレベルの最初のクロックだけ出力。PDI と同じように 受信モード(ターゲット送信)時は HI-Z でも良いし、単に pull-up しても良い。-- こっちの方が嬉しいが、それだとクロックを上げられないのだろう。

    ... それはともかく、だいぶ嫌になってきた。気分転換に LUFA のコードを見たりしてみようと思う。

    • やはり、pull-up は使わず 出力・入力 のどちらかにしていた。
    • 送信する場合は、DATA を H にしてから、1 clock 待っている。(↓↑)
    • 受信する場合は、送信完了を待ってから受信にし、その後で TX を HI-Z に している。

追記: コードデバッグ中(4) -- signature まで確認

  • angel_loader-1.1i.zip (ファームウェア)


  • KEY を送り、PDI_CS_STATUS を READ したところ。OK なので enable 完了

  • シグネチャの最初の 0x1E を読んだところ。
    (pdi_test-ok1.alc : LAP-C ファイル)

    シグネチャ読み込みまで確認できた。XMEGA が壊れたかと思ったが、電源かケーブルの接触の問題だったようだ。

    変更点はよくわからなく... 。もちろん 受信時には、HI-Z にした。あと 受信エラーになったら 次に送信モードにするときに BREAK を送るようにした。(1 回しか 戻ってこないのは、BREAK を送っていないせいだと思うので)。

    これで基本的な通信は OK 。デジアナはもう必要ない。

    (メモ)
  • 受信モードで終わるようにしているが、両者 HI-Z にしているのでマズそう。むしろ受信が終わったら、送信モードにした方が良い。後で直さないと。
  • BREAK はコード入れただけで未検証これも要確認。
  • 1MHz 以上で動作を変えているところがある。これも要検証。
     - TX か RX のどちらかを enable しないと CLOCK が出ないようでバグってた。
  • 最低クロックをあまり低くすると timeout が長くなって デジアナで見にくいので 250KHz にしている。最大クロックは、4MHz (16MHz の場合 8MHz) だがもちろん未検証。
  • せっかく USART 版を 作ったのだが、PORT で制御したい理由があった。これもつくらなくては。

追記: コードデバッグ中(5) -- read ができるようになった。

  • angel_loader-1.1j.zip (ファームウェア)

    read 自体はすんなりできるようにいなったのだが、どうも値がおかしい。よくよく見ると 0x90 のところにシグネチャが見える。

    で、首を傾げていたのだが、原因が分かった。LD 用のポインタを設定するときに 3 バイトのモードを使っていたのだが 上位バイトになにか設定されているようで、違うところ --シグネチャがあるところを READ してたらしい。4 バイトをちゃんと設定するようにしたら OK になった。

    NVM_CMD には、どうも READ_NVM(0x43)を設定すれば良いらしい。よく分からなかったのだが、LUFA のコードをまねしてみたら OK になった。ただ READ ができるようになったといっても正しいかどうかは、未だ分からない。WRITE できるようにならないと。

    さて、SOFT モードはどうしよう。... これは以前作ったボードが XMEGA ボードに付くようにしたのだが、PORT しか割り当てていないので、急遽つくることにした。

    • idle のとき タイマー割り込みで、クロック出しておけば良さそう。シリアルといっても SPI みたいなものだから、通信するときは同期でいける。問題はタイマー割り込みの頻度。-- 今は 250Hz にしているが.. 64 倍の 16KHz にするか。



追記: コードデバッグ中(6) -- SOFT モード ができるようになった。

  • angel_loader-1.1k.zip (ファームウェア)


    (pdi_test-soft.alc : LAP-C ファイル)

    32kHz で割り込みを発生させて 送受信する SOFT_PDITPI が動いた。これで適当に PORT を割りあててしまったボード で書き込むようなこともできるはず。

      上記の画像は、REPEAT 命令を使って 32 バイト連続で読み込もうとしているところ。期待通りに動くようになった。

      ところで、PDI サポートでの通信部分は yukiさんのコードを使わせてもらっていたのだが、デバッグが進むうち書き換えが進んでほんのわずかになってしまっていた。結局これも書き換えて 全部自分のコードにした。

    ただ、書き込みのテストは完了していない。今の状況は、なんとか ページの一部が書けるようになったところ。 flash, boot, application , と usersig は、ページサイズが 256 バイトだが 2 ページ目の 0x1fe からの 2 バイトが書けていない。途中 0xff のデータを使ったのでどこまで書けたかも分からない。eeprom のページサイズは 32 バイト。これも 2 ページ目から書けていない。

    こんなところだが、まぁなんとかなるだろう。

    ところで、chip erase で FLASH , EEPROM は初期化されたのだが usersig は初期化されなかった。一応 write_byte で書き込むと section erase するようなオペレーションを付けておいた。これは、terminal mode で 1 バイトだけ書き込む操作で使える。本当は 1 バイトの書き換えだが エラーにするかわりに 消去する仕様にした。で、問題は usersig の消去をいつやるか。とりあえず eeprom , boot, application, usersig は paged_write のときに write_byte 使って消去することにしている。(都合が悪そうなら変更する)


追記: コードデバッグ中(7) -- tiny10 入手。TPI もテスト中。

tiny10 を手に入れたので、テストしてみることにした。TPI などちょろいだろうと思ってたが、まだ書き込みができていない。ロジアナでみているが、シーケンスは正しそうなのだが、書かれない。ひょっとして、3.3V 電源しか使っていないのが原因? (TPI は 5V)

ちなみに、nega32u4 も同時に入手したので、対応中。一応は動いているのだが、USB の認識に失敗することが多い。(認識されればちゃんと動く)
posted by すz at 22:02| Comment(0) | TrackBack(0) | 日記
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント: [必須入力]

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


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

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