2ヶ月ぶりの投稿です。色々病んでました(意味深)。
5回目にしてやっと USB 機器の実装です。どんな機器を作ろうかな〜と考えていましたが、これまでに作った経験のある USB HID マウスにしたいと思います!
既に完成しているんですが、その名の通りかなりかんたんでした。まあ独特な点で若干ハマったりしましたがね。
本記事は、そのために必要な知識を綴っていきます。USB や HID クラスそのものについての説明はしませんのでご了承を。
これらについて知りたいよ!って人は、マイコンが違いますがこちらの STM32 で USB をやった記事群をご覧あれ。
また、これとは異なるプログラムの記述方法が見つかりましたら、別途記事にします。
参考にしたもの
シリーズ通して参考にしたものたちです。
- EZ-USB のリファレンスマニュアル
- Cypress の USB HID デバイスサンプル
- コードはこちらを参考に。
完成したコード
一通り以下のようなコードになりました。このコードについて説明していく予定です。
ただし、各種ディスクリプタに関しては含めていません。
抑えておくべきこと
説明が長くなってダレそうなので、予め提示しておきます。このマイコンに関して、USB 機器を実装するためには(USB 自体の知識を除いて)何を抑えておくべきか、以下に列挙します。
- USB と CPU の関係
- 要は CPU よりも USB のほうが偉いよって話
- USB の初期化
- そのままだとプログラムのローダーとして動いちゃう
- 割り込み
- Autovectoring とか
- データの転送方法・USB のバッファ構造
- どのレジスタにどうやって書くべきかを抑えましょう
これらについて、私見を交えながらまとめていきたいと思います。順番及び構成は自由にさせてください。
USBの初期化
EZ-USB の USB 機能(この風変わりなマイコンに関してはペリフェラルではなく、USB 自体がメインのコア)では、基本的にホストとの USB 通信はデフォルトのファームウェアが行うことになっています。つまるところは特に自力で USB の挙動について設定をしない場合は、USB は Cypress 謹製のローダーとして動くのです。当然 CPU は 書き込まれたプログラムを実行しながら。
このへんは EZ-USB に関して、USB と CPU の関係を知らないと意味不明だと思うので、こちらの CQ 出版の大昔のページを見ておくととてもいいと思います。
自分で好きな挙動をさせるためにはそれ相応の初期化処理が必要ってことですね。では順を追って行きます。
CPUの設定
まずは何より、CPU の設定等をします。
CPUCS = 0x10;
IFCONFIG |= 0x40;
こちらで CPU クロックを 48MHz にしています。IFCONFIG
については Slave FIFO のクロック設定だけなので不要ですが、なんかこのレジスタをいじるのが作法かなぁ(?)ってことで設定しているだけです。CPUCS
飲みの設定で十分。
もっといいますと、CPUCS
の設定自体も不要です。USB と CPU はクロックが別々に設定されますので(USB は独自に PLL がある)、必須というわけではありません。が、USB 自体が High-Speed で動いているので、せっかくですからなるべく追いつけるようにしたいですよね。
エンドポイントの初期化
今回はマウスもどきとして、デバイス側の EP から一方的にレポートを送り続けるという構成にしたいので、1つの EP を初期化すれば OK です。設定には EP2CFG
に適切な値をセットすれば十分です。今回は 0xF2
。それぞれのビットで以下のような意味を持ちます。
- ダブルバッファを使用
- エンドポイントバッファサイズは 512 Bytes
- インタラプト転送の IN エンドポイント
- エンドポイントを有効化
ダブルバッファは今回ドカドカデータを送るので、有効化しないと変なデータが転送されます(経験談)。転送要求のあるごとにいちいち STALL を設定して、その間に各種データ書き込みをするべきなのですが、まあ面倒ですので処理を省略する目的で導入しています。
その他の EP に関しては、デフォルトでオンになっているものを無効化しています。ユーザーマニュアルにも「使わないやつは無効化してね(意訳)」って書いてあります。
割り込み
動作に欠かせない割り込みの有効化です。
USBIE = (1 << 4) | (1 << 0); // reset IRQ, setup available IRQ
EIE |= 1; // enable USB interrupt
IE |= 0x80; // global interrupt enable
あ、そう言えばこの直下にデバッグ用の IOA とか残っていましたね。許してください。
USBIE
は USB (ペリフェラル)側の割り込み有効化です。リセットと SETUP パケット受信時に割り込みを入れてくれ!ってやってます。
その後、CPU サイドで USB 割り込みを有効化し、最後にグローバル割り込みを有効化しています。
参考にしたサンプルでは、基本的に割り込みは EP0 のみで入れていたよう。その他の EP ではポーリングによって処理するらしい。一応各エンドポイントに割り込みは用意されているが...ひとまずこの書き方で行きます。
USBの再接続
ここまでは USB は単なるプログラムのローダーとして動作しています。今やエンドポイント等の設定が済んだのですから、再接続するべきです。まあ割り込みの挙動を記述してないのでまだ動きませんがね。
リセットを掛けたりするのもだるいので、ソフトウェアから USB のみのリセットを掛けましょう。以下のようにすると OK です。
USBCS = (1 << 3) | (1 << 1); // RENUM. USB is disconnected.
SYNCDELAY;
USBCS &= ~(1 << 3); // connect
USBCS
の 1bit 目は RENUM
ビットと言って、これをオンにしておくと USB 有効化時に再エニュメレーションをホストに促すことが出来ます。
〆
次回は今回のちょっとした補足を書こうかなと思います。
ひとまずこれで初期化は完了なのですが、EZ-USB の仕様をもう少し掘り下げたいなあと思います。