2012年08月23日

FT232Rを PIC32MXライタに

pic32progの改造』の記事の要点だけ。

pic32prog-r62-ftdi-05.zip

これを使うと AE-UM232R といった FT232R モジュールや UM232H といった FT232H モジュールを使って PIC32MX の ファームウェアの書き込みができる。(動いたのは ICSP 。/ JTAG もサポートしたつもりだが未だ動かない)



例えば AE-UM232R だとこういう接続で良いはずなのだ。(UM232H で動作確認) 。追加パーツは、4.7K と デジトラ DTC144ESA。結線は 3 本のみ。GND の結線も不要 (USB 側でつながっている場合)。
使い方は、

 pic32prog -t syncbb-icsp-0175 hexファイル

これでいけるはず。(0:PGEC = TXD , 1:PGED_OUT = RXD , 7:PGED_IN = RI, 5:/MCLR = DCD)

UM232H では、MPSSE のBITBANG を使用することもできる。( syncbb-icsp ではなく mpsse-icsp を指定し ACBUS に接続。)。 その場合、外付けパーツも不要。

注意)

    ・ 動作の保証はしません (おやくそく)
    ・ コンフィグの設定を間違えると、動かなくしてしまう可能性があります。PIC32MX を壊してしまっても補償はしません。
    ・ 開発途中のものであり、書き込みに問題があるかも知れません。動いた/動かないといったレポートは歡迎します。
    ・ こちらでは、UM232H のみでテストする予定。手持ちの AE-UM232R は、ピンを交換したため、どこかおかしくなっている模様。(例示の目的だけで写真を撮っています。)
    ・ JTAG は動いていませんが、使わないので優先度を下げました。デバッグは気が向いたときにやります。

付録) ピンアサイン 表

    AE-UM232R と UM232H
     

    PIC32MX-TypeB / PIC32-PINGUINO-MX220

    RA0 (x)AREF PGED3
    o GND
    o D13
    o D12
    RST(o) RB5 (o)D11 TMS
    3V3 o RA1 (x)D10 PGEC3
    5V o o D9
    GND o RB7 (o)D8 TDI
    GND o
    -- o -- o D7
    -- o D6
    A0 o -- -- o D5
    A1 o -- -- o D4
    A2 o RB0 PGED1 RB9 (o)D3 TDO (*1)
    A3 o RB1 PGEC1 RB8 (o)D2 TCK (*1)
    A4 o RB2 o D1 TDO (*2)
    A5 o RB3 o D0 TCK (*2)

    (*1) PIC32MX-TypeB (my bourd)
    (*2) PIC32-PINGUINO-MX220 (Olimex)

関連記事
posted by すz at 23:32| Comment(1) | TrackBack(0) | PIC32MX

アルミケース三種

気になったアルミケースについて。

aitendo のアルミケース(B) 550円


     基板幅 (最大 47.4mm) 基板長 (最大 77mm) ケース高(外寸 21 mm)
     専用基板 P47X77-B
     ケース・フタ B-CAP

これが気になった最初のもの。ケースに溝があって基板が入るのだが、どうやら秋月C基板がはいりそうな感じ。

最近は C基板が入るかどうかより、Fusion PCB や IteadStudio で作る基板に向いているのかどうかの方が大事。5cm x 5cm は $9.99 と格安だから、このサイズに合うかどうか ... 幅はちょうど良いが、少し長い。押し出し材だから切ってしまうという手もあるが、5cm x 10cm も最近は安いようで、$25 出せばカラー基板が作れる。

タカチ MX型丸型モバイルケース (pdf) 590 〜 670円 (標準価格)


    MX2-6-5, MX2-6-8, MX2-6-10 -- 基板幅 (最大 47.7mm) 基板長 (最大 45mm, 70mm, 95mm) ケース高(外寸 18 mm)

あらためて、タカチのケースを見れば、ちゃんとあった。MX型は値段も安いし、45mm と 5cmx5cm に合いそうなものもあった。5cm x 10cm までで作るなら、MX2-6-10 も良いかもしれない。

タカチ MXA型アルミモバイルケース (pdf) 1290 〜 1490円 (標準価格)


    MXA2-6-5, MXA2-6-7, MXA2-6-10 -- 基板幅 (最大 47.7mm) 基板長 (最大 40mm, 65mm, 90mm) ケース高(外寸 18 mm)

    最近は、オールアルミで仕上げが美しいタイプもある。その分お高いが、目指すものによっては、これを選択するのもアリなんだと思う。

... というわけで、ちゃんとケースに入れるものを作ってみたいような気がしている。最初は、MX型の MX2-6-8 か MX2-6-10 あたり? ただし問題は中身。装置として完結していないと ... 。
posted by すz at 21:31| Comment(0) | TrackBack(0) | 日記

2012年08月18日

パラレルポート(PMP)の調査

PIC32MX には、実に多くのデバイスがあるのだが、まだ把握できていない。今回、PMP (Parallel Master Port)について、ちょっと調べて見ることにした。

DIP で使えるものなのか? これをまずは、確認。

    ~MCLR (1) AVdd
    PGED3 RA0 G1 PMD7 AVss
    PGEC3 RA1 G2 PMD6 PMCS1 G1 RB15/SCK2
    PGED1 RB0 G4 PMD0 G4 RB14/VBUSON/SCK1
    PGEC1 RB1 G2 PMD1 PMRD G3 RB13
    SDA2/RB2 G3 PMD2 Vusb3v3
    SCL2/RB3 G1 PMWR G2 RB11/D- PGEC2
    Vss G4 RB10/D+ PGED2
    CLKI Vcap
    CLKO (PMA0) Vss
    SOSCI RB4 G1 PMD3 G4 RB9/SDA1 TDO
    SOSCO RA4 G3 PMA1 PMD4 G2 PB8/SCL1 TCK
    Vdd PMD5 G1 PB7 TDI
    TMS/USBID RB5 G2 Vbus

    USB を使う前提だと、RB4(G1),RB5(G2),RB14(G4) 以外のピンに PMP機能 のピンが割当たっている。自由にできるピンが 3 つ。結構応用が限られるような気がするが ...

バッファ付き スレーブ モード

    気になったのがこれ。RD で、受信バッファから読み出し。WR で 送信バッファに格納 することができる。受信バッファ/送信バッファ は、それぞれ 4 バイトあって、CPU からは 32bit で一度にアクセスすることができる。

    しかも DMA を使うことが可能。DMA の詳細はまだ良くはしらないが、ブロック転送ができるのはありがたそうだ。

    これは一体なにに使えるのか? 真っ先に思いつくのがロジアナ。なんか毎度毎度という気がするが、ロギングの基本形だし。あと、220 円の IC で作れるのならインパクトが違う。

    性能は?

      RD/WR は使う側から見たら 非同期だが、どうも内部では PBCLK (最大 40 MHz) で同期しているようだ。あと、DMA で取り込むには、ディレイが生じる。4 バイト分一度に取り込むなら、このディレイが取り込む最大周波数を決めることになる。まだ、ディレイがいくつかは分かっていないのだが、8 clk だとすると 5 MHz 。十分高速だとは言いがたいが、それでも役に立ちそうなレンジではある。

      DMA は割り込みと併用する必要はない。うまくコードを作らないといけないが、データを処理しながらのポーリングという手法もある。

    バッファの量は?

      220 円の PIC32MX220F032B だと RAM が 8KB 。半分の 4KB ぐらいは ログするのに使えるだろう。サンプリングが遅ければ、なんらかの圧縮ができるかも知れない。さらに余裕があれば、途切れなく PC に転送できるかも知れない。このあたりは、腕の見せ所 -- これに取り組んでみるのも楽しいかも。

      また、上位の PIC32MX250F128B に換装すれば、4KB が 28KB まで増えることになる。ここまで増えると、少しは実用度が上がるかもしれない。(PIC32MX250F128B は、マイクロファン で取り扱っている。)

    他に同じようなことが出来るものは?

      FT245R とかが真っ先に思いつく。これは、似た様なことが出来る。ただ、バッファ溢れ が心配。Hi-Speed の FT232H や FT2232H だと、EEPROM の設定で 245 Type にできる。これだと、転送性能が上がる上に、バッファも増える。(232H は 1KB / 2232H は 4KB ?)。ただ、やっぱり バッファ溢れ が心配。

      よく使っている Sync-Bitbang でも RD/WR はあったりする。(信号名は RDSTB#/WRSTB#) 。一方向の Async-Bitbang でも同様。ただしこれは出力。先に FIFO が必要になるから、お手軽には出来ない。

    追記: FX2LP (CY7C68013A) を忘れていた



      たとえば、こんなの。dealexreame で $19.30



      こっちの USBee AX PRO MINI LOGIC Analizer は、$11.70 。中身は 写真と同じなら、やはり FX2LP 。24 MHz となるとこれしかないはず。

      ロジアナ作ってもこいつにはかなわない。

マスター モード

    アドレスとデータを 多重化したり、いろいろなモードがある。これを使って SRAM をつけたりできるようだ。ただし、ラッチが必要。また、メモリ空間にマップされるわけではないようだ。逆に アドレスをオートインクリメントしたりできるから、FIFO に使えそう。DMA でももちろん使える。

    SRAM のことを忘れると、単純にパラレルポートとして使える。 RD/WR でハンドシェイクできたりするから、グラフィック LCD (ただし 8bit) の制御に便利そう。

    フレームバッファ

      メモリが少ないので厳しいとは思うが、DMA を使っての フレームバッファは作れると思う。RAM は、1 line か 2 line 分だけ用意して、CPU で間に合うようにデータを生成すれば、なにか見れるものは作れそう。

      一応 3 pin 分は余分にあるから、同期信号は、こっち。PWM 相当の Output Capture で生成してやる。

      ただ、フレームバッファを作る場合でも、スレーブ モードにした方が良いのではないかと思える。同期信号を CS や RD にも入れてやるのだ。こうすることで、タイミングを自由に制御できるし、DMA 的にも扱いやすそうな気がする。
posted by すz at 16:38| Comment(0) | TrackBack(0) | PIC32MX

2012年08月16日

USBデバイスドライバ メモ

以前 AVR 向けに作った USB デバイスドライバを PIC32MX に移植しようとしている。これについてのメモ。

    jzlib や pic32progの改造とか 半端な状態なのだが、これもまた 半端。まぁ、全部揃わないと意味ないし、並列にやっていくのだ。『ブートローダの検討』なんて記事も書いたのだが、既存の HID ブートローダは、動けばラッキーみたいに思っていて積極的にデバッグする気は今はない。jzlib がきちんとなれば動くはずなので、後回し。手をかけたいのは、やっぱりこっちの方。

仕様について

    もともとは、V-USB 用のコードを AT90USB162 に移植したくて作ったもの。だから API も V-USB の仕様をベースにしている。

    移植するにあたり、どういうものだったか 思い出さないといけないので、整理しておこう。

    usbPoll()
    __usb_ctrl_recv(setup_data, 8);
    if (pid == _PID_SETUP)
    if (request_type == USB_RQ_TYPE_STANDARD)
    :
    :
    else if (request_type == USB_RQ_TYPE_VENDOR)
    r = (usb_vendor_setup)(setup_data,reply_data);
    else
    r = (usb_user_setup)(setup_data,reply_data);

    if (r == 255) send_zlp();
    else if (r == 254) reply_stall()
    else usb_reply_setup(...);

    else // (pid == _PID_DATA0)
    r = (usb_user_out)(setup_data,len);

    if (r == 255) send_zlp();
    else if (r == 254) reply_stall();

    usbPoll()を定期的に call することで、(コントロールエンドポイントについては) すべてが動作する。

    usb_vendor_setup あるいは usb_user_setup に callback 関数を設定すると、標準以外の SETUP パケットを受け取ったら これらの関数を call する。これらの関数が、reply_data を セットすれば、その後 IN パケットで reply_data を PC に送信することになっている。

    V-USB だと、reply_data のハンドリングも 使う側が行わなければならないのだが、8 バイト毎に データを区切って生成するコードを作るのが面倒なので、MAX_REPLY_LEN までをバッファリングできるようにしている。(MAX_REPLY_LEN は usbconfig.h で指定)

    一方 SETUP に続いて OUT パケットが来るような 使い方があるのだが、こちらの方は、V-USB と同じ。 user_out を設定すると、8 バイト毎に 区切られて user_out が call される。あらかじめ 何バイト来るかは分からないので、やむを得ない。

    ここまで書いて、usb_user_out が 1 つしかないのはまずいと思った。これだと いくつかの プロトコルをサポートするのに不便なのだ。幸い user_out は、SETUP の request に関連づけられる。usb_user_setup が来てから usb_user_out を 設定すれば良いのだ。SETUP が来たらまず NULL に設定するようにすれば、関係ない request に対して usb_user_out が call されることもない。仕様を変更しておこう。

      基本的に、いくつも OUT パケットが来るケースというのは、ライタでいうと 書き込みデータ。処理自体はそれほど難しいわけではないようだ。

    ところで、reply_data を送信するのに、ローカルループを使っている。ここで usbPoll() をリカーシブに call 。今回は、stack の使用量がちょっと多いので、少々まずいと思っている。動きだしたら、どうするか再検討したい。メモ。

コンフィグ

    const char usbDescrDevice[] = { .... };
    const char usbDescrConfig[] = { .... };
    const int16_t usbDescrString0[] = { .... };
    const int16_t usbDescrString1[] = { .... };
    const int16_t usbDescrString2[] = { .... };
    const int16_t usbDescrString3[] = { .... };
    const int16_t *usbDescrStringTable[4] = {
    usbDescrString0,
    usbDescrString1,
    usbDescrString2,
    usbDescrString3
    };

    V-USB と同じシンボル名で const データを作成しておくのだが、V-USB のような縛りはない。すなわち このデータを生成しておきさえすれば良い。別のソースコードにすることもできる。

    void usbInit();

    で、各エンドポイントの設定を含む初期化を行うのだが、usbDescrConfig・usbDescrConfig を解析して 設定を行う。ただし、全部自分で作るのは、面倒なので 定形フォーマットを desc_asp.c と desc_cdcmsc.c に用意している。これを使うにあたりルールが出来ていて、いくつか usbconfig.h に設定する必要がある。

    #define USE_IAD

    #define EP_INT 3 //
    #define EP_TX 1
    #define EP_RX 2
    //#define EP_MS_OUT 4
    //#define EP_MS_IN 5
    #define MAX_EP (EP_INT+1)

    #define EP_SIZE 8
    #define EP_INT_SIZE 8
    #define EP_TX_SIZE 32
    #define EP_RX_SIZE 32
    #define EP_MS_OUT_SIZE 32
    #define EP_MS_IN_SIZE 32
    #define USB_BUFFER_SIZE ((EP_SIZE + EP_SIZE\
    + EP_TX_SIZE + EP_RX_SIZE \
    + EP_INT_SIZE) * 2)


    これは、desc_cdcmsc.c を使うときの例。MAX_EP と USB_BUFFER_SIZE は PIC32MX 移植での新設パラメータ。PIC32MX では RAM から エンドポイントの定義 や バッファーをメモリから切り出すので、必要になった。( デフォルトでも良いが適当に設定してしまうのでメモリが無駄になる。)

    #define EP_SIZE 8
    #define MAX_EP 1

    #define USB_BUFFER_SIZE (EP_SIZE * 4)

    これは、desc_asp.c 関係。ずいぶん単純になる。

    メモ: usbDescrString0 などを送信する部分がバグっていた。

    const int16_t usbDescrString3[] = {
    0 | (3<<8),
    };

    たとえば、こんな風に最初に 文字列部分のバイト数が入るのだが、この情報自体は含まれない。だが、usb_reply_setup() で送るバイト数が p[0] となっている。要するに 2 バイト足りない。これは! AVR の版も同じはず。良く動いていたものだ。

    あと、const を付けているにも関わらず Data の方に行ってしまっている。

    a.out
    a0000020 D usbDescrString0
    a0000024 D usbDescrString3
    a0000028 D usbDescrStringTable

    desc_asp.o
    00000014 R usbDescrConfig
    00000000 R usbDescrDevice
    00000000 G usbDescrString0
    00000028 R usbDescrString1
    00000048 R usbDescrString2
    00000004 G usbDescrString3
    00000000 D usbDescrStringTable

    -G 0 を付けると G の部分が R に変わるのだが ... D は変わらず。どういうことなのだろう?

    とりあえず、アセンブラコードを生成させてチェック。
     .rdata, .sdata, .data
    このどれかのセクションにしているようだ。大きいデータは、read-only なら .rdata になるが、小さいデータは read-only でも .sdata になり結果 .data に割り付けられる。昔あったワークステーション向けの割付けで、キャッシュの効率だとかページの効率だとかを優先しているのだろう。組み込みチップに最適化してくれているわけでは無さそうだ。

HID について

    USB の仕様に詳しい人なら判るかも知れないが、実は いまの枠組みで HID にも対応できる。デスクリプタで HID_REPORT の定義を入れて usb_user_setup で

    if (request_type == USB_RQ_HID_SET_REPORT)

    この判断をすれば良いのだ。ブロックデータを送る場合も 253 バイトまでなら対応できるし、受信は usb_user_out で対応できる。

    いままで対応して来なかったのは、HID_REPORT の定義 自体が面倒だったため。だが、最近はわりと Windows を使っていて、ドライバなしで良いというのが魅力的に思えるようになってきた。今回の移植にあたっては、HID にも対応したいと思う。

CDC (シリアル) や MSC(Mass Storage Class) について

    ここまでなんの説明もしていなかったが、AT90USB162 では、CDC や MSC の対応もしていた.
    いままで説明して来たのは、usb162 (PIC32MX では usb220) モジュールの話で、CDC や MSC のコードは コンフィグ以外 usb162 とは切り離されている。

    これらは、独立した エンドポイント を持っていて、勝手に それらを使う。チップ依存のコードも CDC や MSC 側に入っている。usbPoll() については、

    void usbcdc_poll() {
    モジュール固有の処理
    :
    usbPoll();
    }

    まぁこんな感じで usbPoll() を call している。

    AVR では、それで良かったのだ。エンドポイントの扱いは すごく簡単だったし、コード量的にも性能的にも 有利だった。だが、PIC32MX はすごく面倒。共通関数化を考えた方が良いかも知れない。

PIC32MX でのエンドポイントの扱い方。

    今は、結構コードが組み上がって来ていて、ほんのわずかだが、動き出している。ただ、エンドポイントの扱いが難しく、SETUP の受信がいくつか出来ただけで、デスクリプタの送信がうまく行っていない状況。

    ちょっと AVR でどのように扱えていたか紹介しておこう。

    unsigned char usbcdc_getc(void) {
    unsigned char ret;
    UENUM = EP_TX;
    while (bit_is_clear(UEINTX,RWAL)) {
    usbcdc_poll();
    UENUM = EP_TX;
    }
    ret = UEDATX;
    return ret;
    }

    void usbcdc_putc(unsigned char data) {
    UENUM = EP_RX;
    while (bit_is_clear(UEINTX,RWAL)) {
    usbcdc_poll();
    UENUM = EP_RX;
    }
    UEDATX = data;
    }

    AVR だとこんな風にして アクセスできるのだ。UENUM で エンドポイントを指定してバンクを切り替えて、UEDATX で FIFO のアクセスをする。( RX も TX も同じレジスタ。)。ダブルバッファでも やり方は変わらない。

    PIC32MX では、バッファは全部 RAM に置く。そして、バッファの定義も RAM に置くようになっている。

    struct _usbotg_buffer_desc
    {
    volatile uint8_t ctl;
    volatile uint8_t rfu;
    volatile uint16_t len;
    uint32_t buf;
    };
    struct _usbotg_bdt
    {
    struct _usbotg_buffer_desc rx[2];
    struct _usbotg_buffer_desc tx[2];
    };
    extern struct _usbotg_bdt _usbotg_bdt[16]; /* MAX : 512B */

    struct _usbotg_bdt _usbotg_bdt[16] __attribute__((section(".bdt")));

    memset((void *)_usbotg_bdt, 0, 512); /* need clear first */
    uint32_t p = vtop((unsigned)_usbotg_bdt);
    U_BDTP1 = __ext_bits( p, 8, 8);
    U_BDTP2 = __ext_bits( p, 16, 8);
    U_BDTP3 = __ext_bits( p, 24, 8);

設定はこんな感じ。16 個までの エンドポイントの定義があって、それぞれ 受信用、送信用のバッファが 2 セットづつある。この定義を BDT -- Buffer Discriptor Table と言う。BDT のアドレス(物理アドレス)を USB コントローラに 渡すしくみ。

    PIC32MX は常に 2 個づつ使うのだが、PIC24F では、PPB の指定で、1 個づつにすることもできる。なにもかも同じではないので、注意

面倒なのは、512B アラインされてないといけないということ。しょうがないので、新たな セクションを RAM の先頭に定義して、そこに置くことにした。__attribute__ を使えば、C で定義を書くこともできる。

それぞれのバッファーは、バイトアラインでよい。送信バッファーは、FLASH 上に置くこともできる。... のだが、持っているコードの都合上 AVR と同じように使いたい。全部 RAM に割り当てて、メモリコピーにした。

このバッファは、交互に切り替えて使うらしい。どちらを使っているかを示すレジスタはなく、ずれるとまずい。

そこは、まだ良いのだ。DATA パケットは、送信も受信も DATA0/DATA1 の 2 種類があって、こちらの方も指定してやらないといけない。これは、2つのバッファとは独立。これの指定がよく分かってなくて混乱している。

V-USB のコードを見てみた。( 送信だけ、とりあえず。)

    初期値は DATA1 にして、送信前に切り替え (最初の送信は、DATA0)
    初期値を設定しなおすタイミングは、
     usbInit()
     USBRQ_SET_INTERFACE
     USBRQ_CLEAR_FEATURE, USBRQ_SET_FEATURE
      ( feature 0 == HALT for endpoint == 1 )
    の 3 ケース。後は常にトグル。

今のコード

    void usbcdc_putc(unsigned char data) {
    struct usb_buffer_ctl *bc = &usb_buffer_ctl[EP_RX];
    struct _usbotg_buffer_desc *cur_desc;
    int which;
    uint8_t ret;
    uint8_t *buf;

    while (bc->tx_ptr >= bc->buf_size) {
    usbcdc_poll();
    }
    which = which_buf_tx(bc);
    cur_desc = &_usbotg_bdt[EP_RX].tx[which];
    buf = (uint8_t *)to_kseg1(cur_desc->buf);

    buf[bc->tx_ptr++] = data;
    if (bc->tx_ptr >= bc->buf_size) {
    usbcdc_poll();
    }
    }

    いまは、こんなひどいコードになっている。usbcdc_poll() でバッファが空くまで待つ。bc は、グローバル変数を持っていればこんな計算は不要。buf も アドレス変換済みのものを bc で参照できるようにすれば良い。最後にある 2 回目の usbcdc_poll()は、送信を始めるために必要。

    if ( (bc->tx_ptr >= bc->buf_size)
    || bit_is_set(GPIOR2, USB220_CDC_SEND_REQ)
    || bit_is_set(GPIOR2, USB220_CDC_SEND_EMPTY) ) {
    bc= &usb_buffer_ctl[EP_RX];
    which = which_buf_tx(bc);
    next = which ^ 1;

    cur_desc = &_usbotg_bdt[EP_RX].tx[next];
    if (bit_is_clear(cur_desc->ctl, U_BD_UOWN)) {
    cur_desc = &_usbotg_bdt[EP_RX].tx[which];
    len = cur_desc->len = bc->tx_ptr;
    ctl = cur_desc->ctl & _BV(U_BD_DATA01);
    cur_desc->ctl = ctl | _BV(U_BD_DTS) | _BV(U_BD_UOWN);
    bc->tx_ptr = 0;
    bc->stat ^= _BV(UBC_RX_WHICH);
    bit_clear(GPIOR2, USB220_CDC_SEND_REQ);
    if (!len) bit_clear(GPIOR2, USB220_CDC_SEND_EMPTY);
    }
    }

    こちらは、usbcdc_poll() の中で実際に送信するコード。なんだか長い。ちなみに、USB220_CDC_SEND_REQ は強制的に 送信するための リクエスト。USB220_CDC_SEND_EMPTY は、さらに 0 バイトを送信させるためのもの。GPIOR2 は、AVR では、汎用レジスタでビット操作が効率良くできるため採用。PIC32MX では、ただの グローバル変数。ただ、PIC32MX でも どこか 空いているレジスタがあれば、使ってみたいとは思っている。

参考文献

     ・ PIC32MX220F032B 製品ページのリンク リファレンスマニュアル 『27章 USB On-The-Go』
     ・ PIC24F の『27章 USB On-The-Go』(日本語)

    PIC24F と PIC32MX では、USB OTG の部分はほとんど変わらないので 日本語のリファレンス・マニュアルが便利。

    以下の説明 で U_CON となっているところは、_ を 1 に置き換えて読む。( U1CON ) 。また、レジスタのフィールドは、たとえば U_CON_PPBRST と表現している。 あと U1EPn は、U_EP(n) と記述。

    以下参考文献から転載 (jzlib 用に名称を変更)

    27.4.1 デバイスモードの有効化
    1. PPBRST ビット (U_CON_PPBRST) を一旦セットしてからクリアする事によって、ピンポン
    バッファ ポインタをリセットする。
    2. 全てのUSB 割り込みを無効にする(U_IE = 0 および U_EIE = 0)。
    3. 既存の割り込みフラグがある場合はクリアする (U_IR = 0xFFおよび U_EIR = 0xFF)。
    4. VBUS が存在する事を確認する(OTG 以外のデバイスのみ )。
    5. USBENビット (U_CON_USBEN) をセットしてUSB モジュールを有効にする。
    6. OTGEN ビット (U_OTGCON_OTGEN)を「1」にセットする。
    7. 最初のセットアップ パケットを受信できるように、U_EP_EPRXEN および U_EP_EPHSHK ビット
    (U_EP(0)) をセットし、エンドポイント 0 バッファを有効にする。
    8. USBPWR ビット(U_PWRC_USBPWR)をセットし、USBモジュールに電力を供給する。
    9. DPPULUP ビット(U_OTGCON_DPPULUP = 1)をセットして D+ラインのプルアップ抵抗を有
    効にし、接続を通知する。

    (注) 6,9 の操作は、デバイス専用なら不要。
    (注) U_IR, U_EIRは、1 を書くとクリアされる。

    27.4.2 デバイスモードでの IN トークンの受信
    1. USBホストに接続し、エニュメレーション(USB 2.0仕様書第9章参照)を実行する。
    2. データバッファを作成する。このバッファにホストへ送信するデータを格納する。
    3. 目的のエンドポイントの適切な(EVEN またはODD) TX BDで次の設定を行う。
    a) ステータス レジスタ (BDnSTAT) に正しいデータトグル (DATA0/1) 値とデータバッ
    ファのバイトカウントを設定する。
    b) アドレス レジスタ(BDnADR)にデータバッファの開始アドレスを設定する。
    c) ステータス レジスタのUOWN ビットを「1」にセットする。
    4. USBモジュールは、IN トークンを受信すると自動的にバッファ内のデータを送信する。
    送信が完了すると、USBモジュールはステータス レジスタ (BDnSTAT)を更新し、転送
    完了割り込みビットTRNIF (U_IR U_I_TRN) をセットする。

    27.4.3 デバイスモードでの OUT トークンの受信
    1. USBホストに接続し、エニュメレーション(USB 2.0仕様書第9章参照)を実行する。
    2. ホストからの受信が予想されるデータサイズのデータバッファを作成する。
    3. 所定のエンドポイントの適切な(EVEN またはODD) TX BDで次の設定を行う。
    a) ステータス レジスタ (BDnSTAT) に正しいデータトグル (DATA0/1) 値とデータバッ
    ファのバイトカウントを設定する。
    b) アドレス レジスタ(BDnADR)にデータバッファの開始アドレスを設定する。
    c) ステータス レジスタのUOWN ビットを「1」にセットする。
    4. USB モジュールは、OUT トークンを受信するとホストがバッファに送信したデータを
    自動的に受信する。受信が完了すると、USB モジュールはステータス レジスタ
    (BDnSTAT)を更新し、転送完了割り込みビット TRNIF (U_IR U_I_TRN)をセットする。

    (注) BDnSTAT は、メモリ上(BDT)にある。
posted by すz at 19:47| Comment(0) | TrackBack(0) | PIC32MX

2012年08月14日

USB HUB IC

ちょっと USB HUB IC について気になったのでメモ。

以前目をつけた HUB に、

Quadrate USB 2.0 4-Port Hub with USB Cable (Color Assorted) $4.14
Quadrate USB 2.0 4-Port Hub with USB Cable (Translucent Orange) $4.20

というのがある。どこに目を付けたかというと...

  • 透明なので、外観でどういう構造なのか分かる。改造しやすそうな感じ。片側 2 port のコネクタを取って 外部 2 port + 内部向けみたいなことも出来そう。

  • IC が SSOP28 で、電子工作として扱いやすそう。-- IC が単体で手に入らなくとも HUB から外してしまえば良い。再設計した基板に載せかえれば、自由な形態にできる。

まぁこういうことなのだ。これを、入手したので、ID を見てみた。

さて、しばらくぶりに FE1.1s を ググってみれば、この IC に目を付けたひとがいた。

仕切りなおしのA8
Hubあぶり焼き
空きパターンのアレ


回路図も作ってくれているので、見たところ ... すごくシンプル。SSOP28 だし、なにか、電子工作ネタに良さそうな感じ。


    3.3V と 1.8V のレギュレータがオンチップになっている。 どれだけ電流を流せるのか分からないが、場合によっては、このためだけに使うのもアリか?

記事中にあるが、このひとが入手したのは、上海問屋の これ。今でも 299 円で入手できる安物 HUB 。ケーブルが断線したりして、壊れやすそうだが、壊れても捨ててはいけない。バラして電子工作ネタにするのだ。

基板が小さいので、そのままでも なにかに組み込んだりできそうだし、基板を起こして PIC32MX ボードのマザーボードみたいにするのも楽しいような気がしている。
posted by すz at 22:19| Comment(0) | TrackBack(0) | 日記

2012年08月07日

ブートローダの検討

PIC32MX-PINGUINO-MX220 のブートローダを壊してしまった。要するにライタの方をなんとかしないと先に進めなくなった。それはさておき、自分でブートローダをビルドしたい。

とにかくいまのやつは気に入らないのだ。なにが気に入らないのか?というと

・ サイズがでかい。(プログラム・フラッシュを 12KB 専有する)
・ スタートアドレス のカスタマイズが出来ない。
・ ブートボタン、LED のカスタマイズが出来ない。

    サイズについては、ブートフラッシュ領域を有効に使うようにすると、8KB かうまくすれば 4KB に抑えられる。 で、jzlib の場合 ロードしたアドレスに JUMP してくれれば、ベクタ領域の 4KB をさらに節約できる。32KB しかない PIC32MX220 で この差は大きい。16KB しか使えなかったものが、24KB (うまくすれば 28KB) 使えるようになるのだ。

    あと 、カスタマイズ機能も欲しい。LED のポートを変更するだけで、再ビルドはしたくないのだ。さらに言うと フラッシュ領域の保護機能も欲しい。コンフィグで設定できるとは言え、チェックしておいた方がより安全だ。

それに、自製のブートローダも作ってみたい。自製の USB デバイスライブラリを使うもので一番シンプルなのが ブートローダだったりするのだ。( 要するにデバッグが目的なので、実用的に使えるのかどうかは気にしない。)

オリジナルのコードについて

    RetroBSD のコードをベースにして、PIC32MX220/PIC32MX250 に対応する。調べて見たが、ビルドするために必要なコードは揃っている。これを jzlib にできるだけ 合わせるように改造した上で、コンフィグ機能を付ける。

    retrobsd-src-r561-20110729.tar.gz

    参考用に取った、このスナップショットをベースにする。

ブートフラッシュ領域を有効に使う案

    jzlib で、割り込みベクタを割り当てない リンク・スクリプトと スタートアップを先に作っている。これを元にブートローダ専用の リンク・スクリプトを仕上げるのだ。

    さて、これのメモリマップの(一部)を説明すると

     program flash + 0x4000 exception_mem size 0x180
    .app_reset (_start)
     program flash + 0x4180 kseg0_program_mem
    .text

    こんな感じにしている。jzlib では exception_mem は、もともとスタートアップと割り込みベクタ領域で、1KB これを 384B に切り詰めた。その後に kseg0_program_mem が続く。これには .text すなわちプログラムコードが含まれる。 ブートローダでは、

     boot flash + 0x0000 exception_mem size 0xBE0
    .app_reset (_start)
    .boot
     program flash + 0x0000 kseg0_program_mem size 8K
    .text

    こんな風に変える。普通にビルドすると、コードは全部 .text になるから、プログラム・フラッシュに行ってしまう。コードを選んで .boot セクションに持って行くと ブートローダが専有する プログラム・フラッシュが減るようになる。

    .boot セクションに持って行くには、

     #define BOOT_SECTION __attribute__((section(".boot")))

     int BOOT_SECTION main(void)
     {
         :

    こんな風に関数を宣言する。ひとつひとつ 宣言することになるが、まぁたいした手間ではない。

    ついでに書いておくと、全部をブートフラッシュ領域に持っていくには、別の方法を使う。普通に戻して、kseg0_program_mem 自体を 移動するのだ。440 なんかでは、12KB もあるから それが可能になる。220 のように 3KB しかなければ頑張っても無理だと分かった。boot flash 3KB + program flash 4KB が精々。

カスタマイズの方法

    リンク・スクリプトには、もともと コンフィグ領域の 指定をする仕組みが仕込まれている。コンフィグ領域は、ブート・フラッシュの 最後 16バイト。これに倣って、その下 に 16Bの ブートローダ・コンフィグ領域を作る。
     
    MEMORY(追加)
    bl_config3 : ORIGIN = 0xBFC00BE0, LENGTH = 0x4
    bl_config2 : ORIGIN = 0xBFC00BE4, LENGTH = 0x4
    bl_config1 : ORIGIN = 0xBFC00BE8, LENGTH = 0x4
    bl_config0 : ORIGIN = 0xBFC00BEC, LENGTH = 0x4

    SECTIONS
    .bl_config3 : {
    KEEP(*(.bl_config3))
    } > bl_config3
    .bl_config2 : {
    KEEP(*(.bl_config2))
    } > bl_config2
    .bl_config1 : {
    KEEP(*(.bl_config1))
    } > bl_config1
    .bl_config0 : {
    KEEP(*(.bl_config0))
    } > bl_config0
    }

    こんな記述を リンク・スクリプトに追加するのだ。

    使う方は、

    #define BLCFG3 (*(unsigned *)0xBFC00BE0)
    #define BLCFG2 (*(unsigned *)0xBFC00BE4)
    #define BLCFG1 (*(unsigned *)0xBFC00BE8)
    #define BLCFG0 (*(unsigned *)0xBFC00BEC)

    こんな風に定義して

    * BLCFG0 アプリケーション領域の先頭(kseg1 address)
    * BLCFG1 アプリケーション領域の最後(kseg1 address) + 1
    * BLCFG2 スタートアドレス (kseg1 address, 省略可)
    * BLCFG3 ボタンとLED のコンフィグ

    struct blcfg3 {
    unsigned REDLED_BIT:4;
    unsigned REDLED_PORT:3; /* 0 A/1 B/... */
    unsigned reserved1:1; /* 0 */

    unsigned GRNLED_BIT:4;
    unsigned GRNLED_PORT:3;
    unsigned reserved2:1; /* 0 */

    unsigned BUT_BIT:4;
    unsigned BUT_PORT:3;
    unsigned reserved3:1; /* 0 */

    unsigned REDLED_TYPE:2; /* 0: LAT_SET 1: LAT_CLR
    2: TRIS_SET 3: TRIS_CLR */
    unsigned GRNLED_TYPE:2;
    unsigned BUT_TYPE:1; /* 0: NOT-PULLUP 1 : PULLUP */
    unsigned reserved:3; /* 000 */
    };

    こう使おうかと思う。

スタートアドレスのサーチ

    jzlib でシングルベクターモードにして コードを節約したのに、ブートローダを使うと アプリケーション領域の先頭 + 4K に JUMP してくる。しょうがないので、4KB 後ろにずらして使っている。これが一番気に入らない。

    でも、アプリケーション領域の先頭に JUMP するようにしたら互換性がなくなってしまう。どうしたものかと思ったのだが、a.out を ディスアセンブルすると 必ず先頭が

    9d004000: 3c1a9d00 lui k0,0x9d00

    これで始まっている。k0 に 上位アドレスをロードしているのだが、これは決まりきった手順のようなもの。MichroChip 由来の crt0.S を使っていればこうなるし、特に 変える理由もない。

    あと、スタートアドレスは、4KB にアラインされる。2KB を超えることもある割り込みベクタが先頭にあるから当然なのだ。

    つまり、アプリケーション領域の先頭から 4KB 単位でインクリメントして、0x3c1a9d00 を探せば良い。こうすることで、jzlib では、先頭から使えるようになる。

最初のバージョン

     ・ jzlib-0.2d.tar.gz

    jzlib に依存するように作り替えているので、jzlib に同梱することにした。jzlib をインストールして、hidboot ディレクトリで make すればビルドできる。

    ただし、まだ、全然テストしていない。バイナリを置くのはまだ先になる。

    text data bss dec hex filename
    9056 52 1187 10295 2837 usbboot.elf

    サイズは、9KB 弱。これを 振り分けて 8KB からロードできるようにした。7KB 以下にしないと 4KB からのロードはできないので、これで手をうった。(頑張って小さくするつもりはない。これを参考にして自製の USBASP ブートローダを作るのだ。)

      ------------------------------------------------
      : 02 0000 04 9D00 5D
      : 10 0000 00 8800F07700000000FFFF001000000000 F3
      :
      :
      : 04 1A90 00 000088BF 0B
      ------------------------------------------------
      : 02 0000 04 9FC0 9B
      : 10 0000 00 C09F1A3C10005A270800400300000000 5F
      :
      :
      : 10 08D0 00 05977C6730F044DB00EF0363000200A0 63
      ------------------------------------------------
      : 02 0000 04 BFC0 7B
      : 04 0BE0 00 0A1F170E C3 (Red RA10 (0A), Grn RB15(1F) , BUT RB7(17) )
      : 04 0BE4 00 FFFFFFFF 11 (START_ADDR : auto search)
      : 04 0BE8 00 FFFFFFFF 0D (APP_FLASH_END +1: auto)
      : 04 0BEC 00 002000BD 28 (APP_FLASH_START : 0xbd00_2000 )
      : 04 0BF0 00 FFFFFF0F F5
      : 04 0BF4 00 D979F9FF B3
      : 04 0BF8 00 5BCE60FF 71
      : 04 0BFC 00 EEDFFF7E AB
      ------------------------------------------------
      : 04 0000 05 9FC00000 98
      : 00 0000 01 FF

    さて、HEX ファイルはこうなっている。領域内に収まっていることを確認した。あと最後の部分がコンフィグ。ここを編集すれば ビルドしなくともカスタマイズできる。

    DEVCFG の方は、BWP=0(ブート領域保護) と PWP(8KB 保護)にしてある。JTAGEN は Enable だが、

    /* Disable JTAG port, to use it for i/o. */
    DDPCON = 0;

    こんなコードが入っていて、ブートローダの先頭で Disable にしている。こうすることで、AVR の ISP のように 書き込みするときだけ、JTAG を使えるようにしている。 (注) 1xx/2xx では DDPCON をCFGCON に読み替える。

    ちなみに、Makefile で DIP_MX220 を選択できるようにしているが、LED の設定しか変わらない。また 250 でも同じものが使える(220で動けばの話だが)。PINGUINO_MICRO の設定は、440 用のブートローダで 大きく違う点は、全体が ブート・フラッシュに置かれること。これによって プログラムフラッシュの先頭から使えるようになる。当然ながらこれも未テスト。

USBASP ブートローダの検討

    まだまだなのだが、どんなものになるかちょっと触れておこうと思う。

    PIC32 用のライタソフトとして、avrdude を使っているものがある。ちゃんと調べていないのだが、arduino と互換にしているらしい。それがありならば、USBASP でもなんとかできるのかも知れない。自製の USB device ライブラリ向けに移植した USBASP ブートローダのコードがあるし、USB device ライブラリを PIC32MX に移植したいと思っていたので検討してみることにした。

    まず、USBASP ブートローダは割り込みを使わずに実装できている。また、USB シリアル プロトコルの CDC とは違って 基本の機能しか使っていない。... どうもこれでデバッグするのが良さそうなのだ。

    このブートローダは、サイズが小さいのが特徴のひとつで AVR では 2KB で実装できている。PIC32MX では、コードが大きくなってしまって、3KB の領域には収まりそうにない。3KB を超えると 次は 7KB 以内が目標になる。それで、機能を充実させる方向で 検討を進めている。

    text data bss dec hex filename
    5016 64 873 5953 1741 asp162bl.elf

    いまのサイズは 5KB ぐらいで、ブートローダ自体の機能は一応入っている。上で説明したブートローダ・コンフィグ機能なども全部入れた。ただし、USB device ライブラリのほうがまだで、これよりちょっと大きくなる予定。それでも 7KB には収まるだろうし、収める。こうすれば、HID ブートローダより使えるメモリが増えてメリットが出る。

      text data bss dec hex filename
      3924 64 873 4861 12fd asp162bl.elf

      嘘のような話なのだが、ポートをコンフィグ可能にするだけで 1KB 使っている。上は、define で指定したケース。

    さて、機能として最も重要なのが、シグネチャー。ライターソフトは、これを見てどういう動作をするか決める。だが、AVR に合わせないと、avrdude で使うのは厳しい。

    AVR の場合、第一バイトが 0x1E で ベンダーのコードになっている。第二が FLASH サイズで、第三がそのサイズでの識別番号。 で、PIC32MX にも当然デバイスの ID はある。こちらは、1word - 4 バイト。下位 8bit がベンダーコードで 0x53 。その後がどうなるかちょっと調べてみた。

    [1][2][3]
    * 00 A0 04 220 B 32
    * 10 A0 04 210 B 16
    * 20 A0 04 220 C 32
    * 30 A0 04 210 C 16
    * 40 A0 04 220 D 32
    * 50 A0 04 210 D 16

    * 00 D0 04 250 B 128
    * 10 D0 04 230 B 64
    * 20 D0 04 250 C 128
    * 30 D0 04 230 C 64
    * 40 D0 04 250 D 128
    * 50 D0 04 230 D 64

    * 20 94 -- 420 H 32
    * D0 94 -- 440 H 128
    * 20 95 -- 440 H 256
    * 60 95 -- 440 H 512

    * D0 96 -- 440 L 128
    * 80 97 -- 460 L 512
    * 40 97 -- 460 L 256

    一応、第二、第三バイトでデバイスを特定できるようだ。2xx は、規則正しい。5xx/6xx/7xx は、沢山ある上に良くわかっていないのでパス。4xx もリストしただけ。ベンダーコードさえ違えば重ならないから、なんとかなりそう。これをシグネチャの定義にしてしまおうと思う。

    これだけなんとかなれば、後は アドレスを指定してメモリを読み書きする仕組みがあれば、事足りる。USBASP には、上位 16bit を指定する機能と、下位 16 bit でアドレスを指定して ブロックを読み書きする機能がある。

    アドレスの範囲をチェックして、余計なところを読み書きできないようにすることは必要だが、新たなプロトコルの定義はいらない。ちなみに、HID ブートローダには、メモリを読み出す機能がない。製品としては、セキュリティ上必要なんだろうけれども、趣味で使う分には不便でしかたがない。書き込みは、アプリケーション領域のみ。読み込みは、フラッシュ全域のみということにしようかと。こうしておけば、使っているブートローダをバックアップできるし、コンフィグがどうなっているかも分かる。

    ソースコード (USBASP ブートローダの方)

     ・angel_loader-p32mx-wk05.tar.gz

    全然動くことが期待できるものではないが、一応置いておく。周りは固めたのだが、肝心の USB device ライブラリがまだまだ。

関連記事
posted by すz at 19:32| Comment(0) | TrackBack(0) | PIC32MX