PIC24

USB MSC Host Sample

FatFsで USBメモリをコントロールしたくて、PICマイコンでUSBのホストコントロールに挑戦。

ターゲットはPIC24FJ64GB002です。


いくつかのPICマイコンは、USBホストとして動く OTGモジュールを持っています。 これをUSBホストとして動かすためには通常、1.Harmonyを導入する。 2.MLAを導入する。 いずれかの方法となります。

最近(2019)は MCCでも USBホスト機能を実装できるようになってきていますが、残念ながら HIDやCDC のみであり、MSCとしての実装がありませんでした。


しかしながら、Interface 2014年11月号のUsbStadyの記事によれば、単純に一つのUSBデバイスをマイコンに接続するだけならば、エニュメレーションをすっ飛ばしてUSBにアドレスとCONFIGを設定するだけで、後は単純なシリアル通信が可能と説いています。


UsbStady記事では、PIC24FJ64GB002を使用したサンプルプロジェクトも公開されており、これをベースに自分好みの USB MSC ドライバを構築できそうです。 サンプルプロジェクトから自分好みに組み直して、曲がりなりにも動くようになり、いくつか気づいた点を以下にメモしておきます。


・USBモジュールのレジスタで U1EPxという名前のレジスタがあるのですが、これが各USB通信のエンドポイントと対応した名前となっています。 しかしながら、ホストモードでは、U1EP0 のレジスタのみ使用するとあり(BDTについても同様 0番 のみ使用)これを使用して、通信のEP0,EP1,EP2 をコントロールする為注意が必要です。

・USB通信のトランザクションは、トークン → データ → ハンドシェイク の流れです。トークンは、U1TOKレジスタを更新した段階で自動発行され、またハンドシェイクは、U1EP0.EPHSHK bitをセットすればUSBモジュールが自動で発行・取得してくれます。 ですのでデータやアドレスの準備をして トークンをU1TOKに更新してやれば、トークン→データ→ハンドシェイクの一連流れをUSBモジュールが自動で実行してくれます。

・取得したハンドシェイクのPID情報は、BDTテーブルのPIDへと反映されます。 またデータについては、BDTテーブルに設定するアドレスのバッファへDMAで格納、もしくはバッファからDMAで転送されます。

・また SOFパケットも U1CON.SOFEN bitをセットすれば、自動で 1ms事にUSBモジュールが発行するので、一度送信設定すれば、後は気にする必要はありません。

・USBメモリ側が返す NAK について、、

USBメモリ側の動作が非常に遅い(使用したUSBメモリが古い)ので マイコンのUSBモジュールがコマンドを 発行すると、USBメモリ側からは NAK ばかりが返信されてきます。

USB通信の受信(マイコンのUSBモジュールではRX)でUSBメモリから帰ってくる NAK については、すぐさま受信をリトライし続けると、無応答となってしまいますが、1msのインターバル(SOFトークン1回分のwait)を設けてリトライすれば、無応答とはならずにNAKを返し続けてくれて、最後はACKとなり受信が完了する事ができました。(この現象はUSBにアドレスを設定するところで顕著でした。USBメモリ側のアドレス設定は重たい処理なのかもしれません。)

USB通信の送信(マイコンのUSBモジュールではTX)においては、SCSIでWRITEコマンドを発行し、続いて 64バイトのデータを8回(計512バイト)連続して送ると、NAKすら返さずいきなり無応答となってしまう現象が発生しました。 試行錯誤して、64バイト送るごとに 4msのインターバルを入れる事で、無応答となるのを回避する事ができました。(速いUSBメモリでは1msのインターバルでOK) その為 512バイトを書き込むのに36msかかってしまう事になってしまいました。


下記に成果物をアップしておきます。

PIC24_USBMSCtest プロジェクト

PIC24 USBMSC Driver sample