SSブログ

USBプロジェクト - HIDデバイス(1) [USB]このエントリーを含むはてなブックマーク#

1516092

設計に時間を要しましたが、ようやく、HIDデバイスができました。

動作中写真は、後日。

HIDのプロトコル

このプログラムは、HIDのレポートとして、送信された8バイトのデータの先頭1バイトの文字コードを液晶モジュールに表示するものです。 ただし、デバッグのための文字も一緒に液晶モジュールに表示されるので、まだ、ごちゃごちゃしています。

また、8バイトのデータをホストに返す機能もありますが、今の所、意味のあるデータを載せていないので、データが到着するのを確認することしかできません。

動作の確認は、WindowsアプリケーションにはBASICが良く似合うで紹介した、"hidclass_vs5.zip"を使用しました。 これで、液晶モジュールに文章を出させるには、根気が続きませんでした。

プロジェクト・ファイル

え~と、いちおうプロジェクト・アーカイブを作成しましたが、切れ端やら、残骸やらが残ったままのプログラムなので、読みたい方だけお読みください。 "HID06.zip"という名前で保存すると再生できるはずです。 協調マルチタスクにしてあるつもりです。

付録 : USBプロジェクト索引

参考文献

USBハード&ソフト開発のすべて―USBコントローラの使い方からWindows/Linuxドライバの作成まで (TECHI―Bus Interface)

USBハード&ソフト開発のすべて―USBコントローラの使い方からWindows/Linuxドライバの作成まで (TECHI―Bus Interface)

  • 作者: インターフェース編集部
  • 出版社/メーカー: CQ出版
  • 発売日: 2006/07
  • メディア: 単行本

nice!(0)  コメント(22)  トラックバック(0)  このエントリーを含むはてなブックマーク#

nice! 0

コメント 22

Tsuneo

おめでとうございます。ついにマスターしましたね。
仕上げに、USBCV通すところまでやっつけちゃいましょう。
Get_Status、Get_Configuration、Get_Interfaceなど、定数あるいは限られた範囲の値を返すリクエストは、コード領域に定数を定義してそのポインタをコントロール読込みハンドラに渡せば、RAMの消費を押さえることができます。

これでもう、どんなUSB MCUでも恐くないですね。試しに他のUSB MCUのサンプルコードを眺めてみて下さい。何をやっているか一目瞭然でしょう。既にOTGホストにも充分手が届くでしょう。

また何かあったら呼んで下さい。

Tsuneo
by Tsuneo (2008-04-07 17:43) 

noritan

て~へんだ。

USBCVを入れて、実行しましたが、反応がなくなりました。
しばらくして、ブルバック画面が出てきて、再起動したところ、見事にUSBが一切使えない状態になってしまいました。ノートPCだったので、一応キーボードとタッチパッドは使えています。

さて、どうやって復旧しようか。

by noritan (2008-04-09 09:36) 

hamayan

> て~へんだ。

江戸っ子?
システムの復元で過去に戻るのはやってみました?。
by hamayan (2008-04-09 13:08) 

Tsuneo

>見事にUSBが一切使えない状態になってしまいました。ノートPCだったので、一応キーボードとタッチパッドは使えています。

タッチパッドを駆使してデバイスマネージャを開けて下さい。
以前のDevManager.batが早速お役立ちですね。
「USB(Universal Serial Bus)コントローラ」の下に
- Intel EHCI Compliance Test Tool
というのがあるか、もしくは
- 黄色いマークの付いたEnhanced Host Controller
というインスタンスがあるでしょう。
このインスタンスをダブルクリックで開けて、「ドライバー」タブに行きます。
「ドライバの更新」か「ドライバのロールバック」で元のMSのドライバに戻します。

しかし、何故USBCVが落ちたんでしょうね。

Tsuneo
by Tsuneo (2008-04-09 13:42) 

Tsuneo

あ、上記の操作は最新の USBCV R1.3.1の場合で、古いバージョンだとほかのUHCI/OHCIホストコントローラのドライバも入れ替わっているかもしれません。

Tsuneo
by Tsuneo (2008-04-09 13:50) 

hamayan

一つ聞いても宜しいでしょうか。
reportDescの
0x06, 0x00, 0xff, // USAGE_PAGE (Generic Desktop)
は何故0x05,0x01ではないのでしょうか?。
by hamayan (2008-04-15 01:45) 

noritan

あれ?何で"Generic Desktop"になっているんだ?コピペミス?
記事にも矛盾がありますね。何でだろう。

http://noritan-micon.blog.so-net.ne.jp/2008-03-20
USBプロジェクト - ファームウェアに立ち返る (2):
新適当マイコン電子工作研究所:So-net blog

正しくは、こうなるはずです。
0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Defined Page 1)

0600FF は、"USAGE_PAGE(Vendor Defined Page 1)"をあらわします。一方、0501 は、"USAGE_PAGE(Generic Desktop)"をあらわします。

USAGEコードは、USAGE_PAGEが示す上位16ビットの値とUSAGEが示す下位16ビットの値で表現されます。プログラムでは、"0901 USAGE(Vendor Usage 1)"が使われているため、"00FF0001"「勝手USAGE」になります。

ところが、"USAGE_PAGE(Generic Desktop)"を使うと"00010001"「Pointer」になってしまい、どこかに"Pointer"を使うアプリケーションがあった場合には、この値を受け取ってしまうはずです。

USAGE_PAGE (Vendor Defined Page 1) 06 00 FF
USAGE (Vendor Usage 1) 09 01
USAGE_PAGE (Generic Desktop) 05 01
USAGE (Pointer) 09 01

"Vendor Defined Page"にしておくと、他と衝突する心配が無いという訳です。

事実確認をしてから、記事の方は修正しておきます。

by noritan (2008-04-15 09:00) 

hamayan

回答有難うございます。

ついでにずっと悩んでいる事が有るので、これも聞いちゃいます。
レポートディスクリプタでHIDキーボードデバイスと定義しているデバイスに、LEDインジケータ以外でデータを送りつける事って可能なのでしょうか。
つまりエンドポイント2をOUTに設定して、そこにPCアプリからデータを送りつける。INエンドポイントは依然としてキーデータを送ってくる。
そんな状況です。

noritanさんのHID6サンプルとアクセルソンさんのVBのプログラムを使ってやっていますが、continueでデータの送信を行うと、「ファイルハンドルが違うよ!、それってもしかしたらマウスかキーボードじゃない?」ってメッセージが出て、送信は行われないようです。

by hamayan (2008-04-15 09:21) 

hamayan

> HID6サンプル
を改造してです。

あとHID6は、IN方向に常にFFを8byte送信し続けているようです。

by hamayan (2008-04-15 09:23) 

noritan

私は、キーボード・クラス・デバイスと認識されたとたんにキーボード・デバイス・ドライバが反応して他のデバイス・ドライバからの接続を拒否するのだと理解しています。キーボードである事は、インターフェース・デスクリプタの bInterfaceProtocol で指定されていたはずです。

で、実際にキーボードに割り当てられたデバイス・ドライバをデバイス・マネージャで確認すると、以下の二つがくっついています。

C:\WINDOWS\system32\DRIVERS\kbdclass.sys
C:\WINDOWS\system32\DRIVERS\kbdhid.sys

もし、キーボード・デバイスでありながら、他の通信も受け付けたいという場合には、複数のインターフェースを定義すればよいのではないでしょうか。具体的には、…私にはまだわかりません。

VBのサンプルプログラムは、「書き出して、読み込む」という一連の動作を行っています。そのため、インタラプト・IN転送に応答する送信機TX2を動作させないと、PC側アプリケーションがハングしてしまいます。
これを解決するために、HID06サンプルのインタラプト・IN転送は、「フラグが立ったら、クリアして、T1SEQを微調整する」動作を行っています。従って、たまたまエンドポイントレジスタに$FFが入っていて、それが出てきたというだけです。

by noritan (2008-04-15 12:43) 

hamayan

なるほど判りました。
回答有難うございました。

by hamayan (2008-04-15 14:01) 

noritan

今、気がついた。

HIDキーボードのUSAGEコードは、ASCIIキーボード前提に作られているから、JISキーボードを作る時には別途変換テーブルが必要になるのか。難儀だな。

by noritan (2008-04-15 17:14) 

Tsuneo

WindowsではUSBキーボードとマウスはシステムデバイスとして認識され、アプリからは普通には通信できなくなります。ただし、Featureレポートだけは、HidD_SetFeature()、HidD_GetFeature()を使ってアプリからもやりとりできます。
ここで、キーボードとマウスに対するCreateFileは、次のパラメータで開けなければエラーになります。
CreateFile()
- dwDesiredAccess = 0
- dwDesiredAccess = (FILE_SHARE_READ | FILE_SHARE_WRITE)

Tsuneo

by Tsuneo (2008-04-16 12:13) 

Tsuneo

>もし、キーボード・デバイスでありながら、他の通信も受け付けたいという場合には、複数のインターフェースを定義すればよいのではないでしょうか。

その通りです。複合(コンポジット)デバイスですね。
一度ここで解説しました(英文)
"USB Composite Device" on SiLabs forum
http://www.cygnal.org/ubb/Forum9/HTML/001050.html

それ以外にもトップレベルコレクションでもできるかもしれませんが、試していません。
キーボードとマウスはトップレベルコレクションを使って一つのインターフェースにまとめられるのは確認済みなんですが。

"multiple HID and one MSD on a -340" on SiLabs forum
http://www.cygnal.org/ubb/Forum9/HTML/001496.html


>HIDキーボードのUSAGEコードは、ASCIIキーボード前提に作られているから、JISキーボードを作る時には別途変換テーブルが必要になるのか。

キーボード側ではJISでも109でも同じキーコードを出します。OS側でキーレイアウトの変換テーブルを持っています。
こちらでJISキーボードについて大変美しい資料を公開されています。

"USBキーボードのキーコード"
http://www2d.biglobe.ne.jp/~msyk/keyboard/layout/usbkeycode.html

Tsuneo

by Tsuneo (2008-04-16 12:41) 

hamayan

> "USBキーボードのキーコード"
http://www2d.biglobe.ne.jp/~msyk/keyboard/layout/usbkeycode.html

このページは参考にさせて頂きました。
by hamayan (2008-04-16 14:27) 

hamayan

> ただし、Featureレポートだけは、HidD_SetFeature()、
> HidD_GetFeature()を使ってアプリからもやりとりできます。

おお、そうするとコントロールエンドポイントを通してデータを受信、送信が出来ると言う事ですか。

by hamayan (2008-04-16 15:12) 

noritan

> ただし、Featureレポートだけは、HidD_SetFeature()、
> HidD_GetFeature()を使ってアプリからもやりとりできます。

HID06には、SET_FEATUREおよびGET_FEATUREは、実装しておりませんので、追加してやってください。

SET_REPORTリクエストから逃れるためにEP2を導入したはずだったのに、やっぱりコントロール書き込み転送は必要なのか。

by noritan (2008-04-16 15:50) 

noritan

ReportDescriptor について、残っているファイルを調べました。

usbdev-HID06.txt
USAGE_PAGE (Generic Desktop) 06 01 00
USAGE (Vendor Usage 1) 09 01

usbdev-HID06.c
0x06, 0x00, 0xff, // USAGE_PAGE (Generic Desktop)
0x09, 0x01, // USAGE (Vendor Usage 1)

usbdev-HID06.hid
USAGE_PAGE(Generic Desktop) 06 01 00

あれ?何だか変だな。
HID Descriptor Tool の問題かも知れません。結果を鵜呑みにしないように気をつけましょう。

by noritan (2008-04-16 22:45) 

Tsuneo

>> ただし、Featureレポートだけは、HidD_SetFeature()、
>> HidD_GetFeature()を使ってアプリからもやりとりできます。
> HID06には、SET_FEATUREおよびGET_FEATUREは、実装しておりませんので、追加してやってください。

たいへん紛らわしいのですが、SET_FEATURE、GET_FEATUREリクエストとは直接関係ありません。たいていの人が初めは混同してしまいます。

ホストアプリのHidD_SetFeature()、HidD_GetFeature()は、それぞれデバイスでのSet_Report( Feature )、Get_Report( Feature )リクエストに対応しています。InputレポートやOutputレポートの替わりにFeatureレポートをやりとりする、と考えてください。
でもやっぱりコントロール転送ですね。

Set_Report、Get_Reportリクエストで、wValueの上位8bitがレポートのタイプを示します。
01 Input
02 Output
03 Feature
Set_Report( Feature )とは、Set_Reportリクエストで、wValueの上位8bitが03であることを示しています。

Set_Reportは、OutputとFeatureレポートを、
Get_Reportは、InputとFeatureレポートを運べます。

Featureレポートの書式は、レポートデスクリプタでInputやOutputレポートとまったく同様に定義します。レポートデスクリプタは、Logical Min/Max, Report Size/Count, Usage と並べてきて、InputとかOutputとかが来ますね。ここでFeatureとやればOKです。

Tsuneo
by Tsuneo (2008-04-19 00:59) 

noritan

はい、見事に混同しておりました。

この場合に実装が必要なのは、SET_REPORTなのですね。
結局、インターフェースを増設してHIDを二つ持つ構成にするにも、SET_REPORT(Feature)を使うのも、SET_REPORTを実装する必要があるということですか。

確認ですが、SET_REPORT(Feature)コントロールリクエストの代わりにEP2のインタラプトOUTを使うわけにはいかないのですよね。

by noritan (2008-04-19 11:24) 

Tsuneo

>確認ですが、SET_REPORT(Feature)コントロールリクエストの代わりにEP2のインタラプトOUTを使うわけにはいかないのですよね。

コンポジットデバイスの構成にして、マウス・キーボード以外のHIDインターフェースを増設すれば、インタラプトOUTを使えます。


どうも混乱してきたようなので、クラスの実装という観点からHIDをちょっとまとめてみましょう。ついでにトップレベルコレクションについても(さらに混乱を招くだけかも :-) )

a) HID クラス
HIDはUSBのクラスで、その機能をインターフェースとしてデバイスに実装します。単独のインターフェースとして、あるいは複合(コンポジット)デバイスとして他のクラスのインターフェースと共に実装することもできます。複数のHIDインターフェースを1つのデバイスに実装することもできます。

ところで、コンポジット(composite)デバイスを複合デバイスと訳すのなら、コンパウンド(compound)デバイスはどう訳すのでしょう?

b) HID インターフェース
HID インターフェースでは、Input、Output、Featureの3タイプのレポートをデバイスとホストの間で転送します。これらのレポートのフォーマットは、レポートデスクリプタでインターフェースごとに定義されます。

レポートのタイプによってそれぞれ転送方向が定まっています。

Input:デバイスからホストへ、
Output:ホストからデバイスへ、
Feature:双方向

またレポートのタイプによって、どのパイプを使うかが定められています。

Inputレポート
- デバイス:インターラプトIN EP - Windows アプリ:ReadFile
- デバイス:Get_Report( Input ) - Windows アプリ:HidD_GetInputReport(XP以降)
Outputレポート
- デバイス:インターラプトOUT EP - Windows アプリ:WriteFile
- デバイス:Set_Report( Output ) - Windows アプリ:HidD_SetOutputReport(XP以降)
Featureレポート
- デバイス:Get_Report( Feature ) - Windows アプリ:HidD_GetFeature
- デバイス:Set_Report( Feature ) - Windows アプリ:HidD_SetFeature

HID インターフェースでは、Get_Report( Input )と、INエンドポイントはデバイスに必ず実装することがUSBスペック上求められています。それ以外のパイプは、必要に応じて実装すればよいのです。

ここでXP以降としたのは、Win2k DDK 以前のHIDSDI.HではHidD_GetInputReportとHidD_SetOutputReportが宣言されていないからです。WinXP DDKで初めて登場します。

c) システムデバイス
マウスとキーボードはHIDクラスを使って実装します。
Windows はマウスとキーボードをシステムデバイスとして、直接のアクセスを制限します。具体的には、HIDマウスとキーボードを実装したインターフェースでは、どのパイプでも直接ホストアプリとInputとOutputレポートを転送することができません。しかし、Featureレポートを転送することは許されています。

つまり、キーボードとマウスに対してもホストアプリでのHidD_GetFeatureとHidD_SetFeatureは有効です。ここで、キーボードとマウスに対するCreateFileは、次のパラメータで開けます。
CreateFile()
- dwDesiredAccess = 0
- dwDesiredAccess = (FILE_SHARE_READ | FILE_SHARE_WRITE)

このシステムデバイスの縛りは、HIDマウスとキーボードを実装したインターフェースに対してのみ適用されます。コンポジットデバイスでは、他のインターフェースには影響しません。

d) トップレベルコレクション
HIDにはコンポジットデバイス以外にも、複数のHID機能を一つのインターフェースに押込めてしまう方法が用意されています。レポートデスクリプタでは通常単独のトップレベルコレクションが宣言されます。しかしここで複数のトップレベルコレクションを宣言すると、それぞれのトップレベルコレクションは独立して機能します。

例えば、この方法を使ってマウスとキーボードを一つのHIDインターフェースにまとめることができます。レポートデスクリプタのアウトラインは、

Collection (Application) キーボード
..Report ID (01)
..Input (Variable, Absolute) Modifier keys
..Output (Variable, Absolute) LEDs
..Input (Array, Absolute) Main keys
End Collection
Collection (Application) マウス
..Report ID (02)
..Collection (Physical) Pointer
....Input (Variable, Relative) X, Y
....Input (Variable, Absolute) Button
..End Collection
End Collection

単純に2つのコレクションをくっつけただけですね。ただ、Report IDの宣言がそれぞれのコレクションに付け加わっています。上記の例ではキーボードは01のReport IDに、マウスは02に指定しています。

デバイスやホストアプリではこのReport IDを使ってそれぞれの機能を区別します。
例えば、インターラプトIN EPでは、01のReport IDを付けてキーボードのinputレポートを、02のReport IDを付加してマウスのinputレポートを送ります。Get_ReportやSet_Reportリクエストも同じです。

複数のトップレベルコレクションを宣言したHIDインターフェースでは、インターフェースデスクリプタのクラス、サブクラス、プロトコルの三組みを以下のように設定しなければなりません。

(bInterfaceClass, bInterfaceSubclass, bInterfaceProtocol)
= (0x03, 0x00, 0x00)
= (HID class, no subclass, no protocol)

つまり、ブートプロトコルを付けることが出来なくなります。

マウス・キーボードに対するシステムデバイスの縛りはこの場合どうなるのかは、まだ確認していません。

[Reference]
"Top-Level Collections" on MSDN
http://msdn2.microsoft.com/en-us/library/ms789908.aspx

HID Descriptor Toolにはマウス+キーボードのサンプルが入っています。
"HID Descriptor Tool" on USB.org
http://www.usb.org/developers/hidpage/dt2_4.zip

Tsuneo
by Tsuneo (2008-04-19 15:44) 

Tsuneo

あらら、間違ったままコピペしてしまいました。

上記のこの部分は、
CreateFile()
- dwDesiredAccess = 0
- dwDesiredAccess = (FILE_SHARE_READ | FILE_SHARE_WRITE)

これと差替えてください。
CreateFile()
- dwDesiredAccess = 0
- dwShareMode = (FILE_SHARE_READ | FILE_SHARE_WRITE)

Tsuneo
by Tsuneo (2008-04-19 15:54) 

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

トラックバックの受付は締め切りました

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。