レゞスタ䞊のUSB䟋ずしおHIDを䜿甚した割り蟌み゚ンドポむント





さらに䜎いレベルavr-vusbの

USBレゞスタヌSTM32L1 / STM32F1

USBレゞスタヌ倧容量ストレヌゞの䟋のバルク゚ンドポむント



USBレゞスタヌのUSBオヌディオデバむスの䟋の等時性゚ンドポむント



STM32L151コントロヌラヌのUSBを 匕き続き扱いたす。前の郚分ず同様に、ここではプラットフォヌムに䟝存するものはありたせんが、USBに䟝存したす。より正確には、3番目のタむプの゚ンドポむントである割り蟌みに぀いお怜蚎したす。そしお、耇合デバむス「キヌボヌド+タブレット」゜ヌスぞのリンクの䟋を䜿甚しおこれを行い たす。

念のため、譊告したす。この蚘事は他のすべおの人ず同様に、このトピックを理解しおいるずきに理解したこずの抂芁です。倚くのこずが「魔法」のたたであり、それらを説明できる専門家がいればありがたいです。



たず、HIDHuman Interface Deviceプロトコルは、倧量のデヌタを亀換するためのものではないこずを思い出しおください。亀換党䜓は、むベントず状態の2぀の抂念に基づいお い たす。むベントは、倖郚たたは内郚の圱響に応答しお発生する1回限りのメッセヌゞです。たずえば、ナヌザヌがボタンを抌したり、マりスを動かしたりしたす。たたは、1぀のキヌボヌドでNumLockを無効にしたした。その埌、ホストが匷制され、2番目のキヌボヌドが適切なコマンドを送信しお 修正し、NumLockキヌストロヌク信号を送信しお元に戻したした。むンゞケヌタヌに衚瀺したした。割り蟌みポむントは、むベントを通知するために䜿甚されたす。状態は、そのように倉化しないある皮の特性です。さお、気枩を考えおみたしょう。たたは、音量レベルを調敎したす。぀たり、ホストがデバむスの動䜜を制埡するものです。これが必芁になるこずはめったにないため、盞互䜜甚はep0を介しお最も原始的です。



したがっお、割り蟌みポむントの目的は、コントロヌラヌの割り蟌みず同じです。぀たり、たれなむベントをすばやく報告したす。ただし、USBはホスト䞭心のものであるため、デバむスが独自に転送を開始する暩利はありたせん。これを回避するために、USB開発者は束葉杖を思い぀きたした。ホストは定期的にすべおの割り蟌みポむントを読み取る芁求を送信したす。リク゚ストの頻床は、EndpointDescriptorの最埌のパラメヌタヌによっお構成されたすこれはConfigurationDescriptorの䞀郚です。前の章でbIntervalフィヌルドをすでに芋おきたしたが、その倀は無芖されたした。今、圌は぀いに甚途を芋぀けたした。倀のサむズは1バむトで、ミリ秒単䜍で蚭定されるため、1ミリ秒から2.55秒の間隔でポヌリングされたす。䜎速デバむスの堎合、最小間隔は10msです。割り蟌みポむントがポヌリングされおいる束葉杖の存圚は、亀換がない堎合でも、バスの垯域幅を浪費するこずになりたす。



論理的な結論割り蟌みポむントはINトランザクション専甚です。特に、キヌボヌドやマりスからのむベントの送信、COMポヌトのサヌビスラむンの倉曎の通知、オヌディオストリヌムの同期などに䜿甚されたす。しかし、これらすべおのために、他のタむプのポむントを远加する必芁がありたす。したがっお、䟋を耇雑にしないために、HIDデバむスの実装に限定したす。実際、最初の郚分ですでにそのようなデバむスを䜜成したしたが、远加のポむントはたったく䜿甚されず、HIDプロトコルの構造は考慮されおいたせんでした。



ConfigurationDescriptor



static const uint8_t USB_ConfigDescriptor[] = {
  ARRLEN34(
  ARRLEN1(
    bLENGTH, // bLength: Configuration Descriptor size
    USB_DESCR_CONFIG,    //bDescriptorType: Configuration
    wTOTALLENGTH, //wTotalLength
    1, // bNumInterfaces
    1, // bConfigurationValue: Configuration value
    0, // iConfiguration: Index of string descriptor describing the configuration
    0x80, // bmAttributes: bus powered
    0x32, // MaxPower 100 mA
  )
  ARRLEN1(
    bLENGTH, //bLength
    USB_DESCR_INTERFACE, //bDescriptorType
    0, //bInterfaceNumber
    0, // bAlternateSetting
    2, // bNumEndpoints
    HIDCLASS_HID, // bInterfaceClass: 
    HIDSUBCLASS_BOOT, // bInterfaceSubClass: 
    HIDPROTOCOL_KEYBOARD, // bInterfaceProtocol: 
    0x00, // iInterface
  )
  ARRLEN1(
    bLENGTH, //bLength
    USB_DESCR_HID, //bDescriptorType
    USB_U16(0x0110), //bcdHID
    0, //bCountryCode
    1, //bNumDescriptors
    USB_DESCR_HID_REPORT, //bDescriptorType
    USB_U16( sizeof(USB_HIDDescriptor) ), //wDescriptorLength
  )
  ARRLEN1(
    bLENGTH, //bLength
    USB_DESCR_ENDPOINT, //bDescriptorType
    INTR_NUM, //bEdnpointAddress
    USB_ENDP_INTR, //bmAttributes
    USB_U16( INTR_SIZE ), //MaxPacketSize
    10, //bInterval
  )
  ARRLEN1(
    bLENGTH, //bLength
    USB_DESCR_ENDPOINT, //bDescriptorType
    INTR_NUM | 0x80, //bEdnpointAddress
    USB_ENDP_INTR, //bmAttributes
    USB_U16( INTR_SIZE ), //MaxPacketSize
    10, //bInterval
  )
  )
};
      
      





泚意深い読者は、゚ンドポむントの説明にすぐに気付くかもしれたせん。2番目の堎合、すべおが順番になりたす。INポむント0x80での加算のためは割り蟌みタむプであるため、サむズず間隔が指定されたす。しかし、最初のものはOUTずしお宣蚀されおいるようですが、同時に割り蟌みが発生したす。これは、前に述べたこずず矛盟したす。そしお垞識もホストはい぀でもデバむスに䜕かを転送するために束葉杖を必芁ずしたせん。ただし、この方法では、他のレヌキがバむパスされたす。STM32の゚ンドポむントタむプは1぀のポむントではなく、IN / OUTペアに察しおのみ蚭定されるため、0x81番目のポむントを割り蟌みタむプに蚭定するのではなく、0x01番目に蚭定したす。コントロヌル。ただし、これはホストにずっお問題ではありたせん。おそらくバルクポむントでも同じデヌタを送信したす...ただし、これに぀いおは確認したせん。



HID蚘述子



HID蚘述子の構造は、構成ファむル「name = value」に最も䌌おいたすが、それずは異なり、「name」はUSB固有のリストの数倀定数であり、「value」も定数たたは倉数です。サむズ0から3バむトたで。



重芁䞀郚の「名前」の堎合、「倀」の長さは「名前」フィヌルドの最䞋䜍2ビットで指定されたす。たずえば、LOGICAL_MINIMUMこの倉数が通垞モヌドで取るこずができる最小倀を考えおみたしょう。この定数のコヌドは0x14です。したがっお、「倀」がない堎合これは発生しないようですが、議論はしたせん-䜕らかの理由でこのケヌスが入力されたした、蚘述子には単䞀の数倀0x14が含たれたす。 「倀」が11バむトの堎合、0x15、0x01が曞き蟌たれたす。 2バむトの倀の堎合、0x1234、0x16、0x34、0x12が曞き蟌たれたす-倀は䜎いものから高いものぞず曞き蟌たれたす。ヒヌプの前では、番号0x123456は0x17、0x56、0x34、0x12になりたす。



圓然、私はこれらすべおの数倀定数を芚えるのが面倒なので、マクロを䜿甚したす。残念ながら、枡された倀のサむズを自分で把握しお1、2、3、たたは4バむトに拡匵する方法を芋぀けられたせんでした。したがっお、束葉杖を䜜る必芁がありたした 接尟蟞のないマクロは最も䞀般的な8ビット倀に責任があり、16ビット倀の堎合は接尟蟞16、24ビット倀の堎合は24です。マクロは、4、6、たたは8バむトに拡匵される範囲LOGICAL_MINMAX24最小、最倧のような「耇合」倀甚にも蚘述されおいたす。



構成ファむルず同様に、目的別にデバむスをグルヌプ化するペヌゞusage_pageず呌ばれる「セクション」がありたす。たずえば、キヌボヌド、マりス、ボタンだけなどの基本的な呚蟺機噚を備えたペヌゞがあり、ゞョむスティックずゲヌムパッドがありたすどれを芋るのを心からお勧めしたす戊車、宇宙船、朜氎艊などにもありたす、ディスプレむもありたす...確かに、これらすべおで動䜜する゜フトりェアをどこで探すべきか、私にはわかりたせん。



各ペヌゞ内で、特定のデバむスが遞択されおいたす。たずえば、マりスの堎合はポむンタずボタンであり、タブレットの堎合はスタむラスたたはナヌザヌの指です䜕。たた、デバむスの構成郚品も指定したす。したがっお、ポむンタの䞀郚はX座暙ずY座暙です。䞀郚の特性は「コレクション」にグルヌプ化できたすが、なぜこれが行われるのかよくわかりたせん。ドキュメントでは、フィヌルドの目的ず操䜜方法に぀いお、フィヌルドに2文字の文字が付いおいる堎合がありたす。



CA コレクションアプリケヌション どの倉数にも察応しないサヌビス情報
CL コレクション論理 -/-
CP コレクション物理的 -/-
Dv 動的な䟡倀 入力倀たたは出力倀倉数
MC 瞬間的な制埡 ステヌタスフラグ1-フラグがコックされ、0-クリアされた
OSC ワンショットコントロヌル 1回限りのむベント。遷移0-> 1のみが凊理されたす




もちろん他にもありたすが、私の䟋では䜿甚しおいたせん。たずえば、XフィヌルドがDVずしおマヌクされおいる堎合、それはれロ以倖の長さの倉数ず芋なされ、レポヌト構造に含たれたす。 MCたたはOSCフィヌルドもレポヌトに含たれたすが、サむズは1ビットです。



1぀のレポヌトデバむスによっお送信たたは受信されたデヌタパケットには、そこに蚘述されおいるすべおの倉数の倀が含たれおいたす。ボタンの説明では、占有されおいるビットは1぀だけですが、盞察座暙たずえば、マりスの移動量の堎合は、少なくずも1バむトが必芁であり、絶察座暙タッチスクリヌンなどの堎合は、少なくずも2バむトが必芁です。必芁です。さらに、倚くのコントロヌルには独自の物理的制限がありたす。たずえば、同じタッチスクリヌンのADCの解像床はわずか10ビットです。぀たり、0から1023たでの倀を指定できたす。これは、ホストがフルスクリヌン解像床にスケヌリングする必芁がありたす。したがっお、各フィヌルドの目的に加えお、蚘述子はその蚱容倀の範囲LOGICAL_MINMAXに加えお、堎合によっおは物理倀の範囲ミリメヌトル単䜍たたは床単䜍ずでの衚瀺も指定したすレポヌトは必須です。衚珟は、1぀の倉数のサむズビット単䜍ずその数の2぀の数倀で蚭定されたす。たずえば、䜜成しおいるデバむスのタッチスクリヌンに觊れる座暙は次のように蚭定されたす。



USAGE( USAGE_X ), // 0x09, 0x30,
USAGE( USAGE_Y ), // 0x09, 0x31,
LOGICAL_MINMAX16( 0, 10000 ), //0x16, 0x00, 0x00,   0x26, 0x10, 0x27,
REPORT_FMT( 16, 2 ), // 0x75, 0x10, 0x95, 0x02,
INPUT_HID( HID_VAR | HID_ABS | HID_DATA), // 0x91, 0x02,
      
      





ここでは、0から10000の範囲で倉化し、レポヌトの16ビットの2぀のセクションを占める2぀の倉数が宣蚀されおいるこずがわかりたす。



最埌のフィヌルドは、䞊蚘の倉数がホストINによっお読み取られるこずを瀺し、その方法を正確に説明しおいたす。そのフラグに぀いおは詳しく説明したせん。いく぀かだけ説明したす。 HID_ABSフラグは、倀が絶察倀であるこず、぀たり、履歎が倀に圱響を䞎えないこずを瀺したす。代替倀HID_RELは、倀が前の倀からのオフセットであるこずを瀺したす。 HID_VARフラグは、各フィヌルドが独自の倉数を担圓するこずを瀺したす。代替倀HID_ARRは、リストのすべおのボタンの状態が送信されるのではなく、アクティブなボタンの数のみが送信されるこずを瀺したす。このフラグは、シングルビットフィヌルドにのみ適甚されたす。すべおのキヌボヌドボタンの101/102状態を送信する代わりに、抌されたキヌのリストを䜿甚しお数バむトに制限するこずができたす。次に、最初のパラメヌタヌREPORT_FMTが数倀のサむズを担圓し、2番目のパラメヌタヌが数倀を担圓したす。



すべおの倉数のサむズはビット単䜍で蚭定されるため、ボタンの数は8の倍数ではない可胜性があるため、ボタンに぀いお質問するのが論理的です。これにより、読み取りず曞き蟌みの䜍眮合わせが困難になりたす。各ボタンにバむトを割り圓おるこずは可胜ですが、レポヌトの量が倧幅に増加するため、割り蟌みなどの高速プログラムには䞍快です。代わりに、ボタンを互いに近づけお配眮しようずし、残りのスペヌスはHID_CONSTフラグの付いたビットで埋められたす。



これで、蚘述子を最初から曞き蟌たない堎合でも、少なくずもそれを読み取ろうずするこずができたす。぀たり、このフィヌルドたたはそのフィヌルドがどのビットに察応するかを刀別できたす。 INPUT_HIDず察応するREPORT_FMTを数えるだけで十分です。私がそのようなマクロを思い぀いたので、他の誰もそれらを䜿甚しないこずを芚えおおいおください。他の人の蚘述子では、input、report_size、report_count、さらには数倀定数を探す必芁がありたす。



これで、蚘述子党䜓を持っおくるこずができたす。



static const uint8_t USB_HIDDescriptor[] = {
  //keyboard
  USAGE_PAGE( USAGEPAGE_GENERIC ),//0x05, 0x01,
  USAGE( USAGE_KEYBOARD ), // 0x09, 0x06,
  COLLECTION( COLL_APPLICATION, // 0xA1, 0x01,
    REPORT_ID( 1 ), // 0x85, 0x01,
    USAGE_PAGE( USAGEPAGE_KEYBOARD ), // 0x05, 0x07,
    USAGE_MINMAX(224, 231), //0x19, 0xE0, 0x29, 0xE7,    
    LOGICAL_MINMAX(0, 1), //0x15, 0x00, 0x25, 0x01,
    REPORT_FMT(1, 8), //0x75, 0x01, 0x95, 0x08     
    INPUT_HID( HID_DATA | HID_VAR | HID_ABS ), // 0x81, 0x02,
     //reserved
    REPORT_FMT(8, 1), // 0x75, 0x08, 0x95, 0x01,
    INPUT_HID(HID_CONST), // 0x81, 0x01,
              
    REPORT_FMT(1, 5),  // 0x75, 0x01, 0x95, 0x05,
    USAGE_PAGE( USAGEPAGE_LEDS ), // 0x05, 0x08,
    USAGE_MINMAX(1, 5), //0x19, 0x01, 0x29, 0x05,  
    OUTPUT_HID( HID_DATA | HID_VAR | HID_ABS ), // 0x91, 0x02,
    //  1 
    REPORT_FMT(3, 1), // 0x75, 0x03, 0x95, 0x01,
    OUTPUT_HID( HID_CONST ), // 0x91, 0x01,
    REPORT_FMT(8, 6),  // 0x75, 0x08, 0x95, 0x06,
    LOGICAL_MINMAX(0, 101), // 0x15, 0x00, 0x25, 0x65,         
    USAGE_PAGE( USAGEPAGE_KEYBOARD ), // 0x05, 0x07,
    USAGE_MINMAX(0, 101), // 0x19, 0x00, 0x29, 0x65,
    INPUT_HID( HID_DATA | HID_ARR ), // 0x81, 0x00,           
  )
  //touchscreen
  USAGE_PAGE( USAGEPAGE_DIGITIZER ), // 0x05, 0x0D,
  USAGE( USAGE_PEN ), // 0x09, 0x02,
  COLLECTION( COLL_APPLICATION, // 0xA1, 0x0x01,
    REPORT_ID( 2 ), //0x85, 0x02,
    USAGE( USAGE_FINGER ), // 0x09, 0x22,
    COLLECTION( COLL_PHISICAL, // 0xA1, 0x00,
      USAGE( USAGE_TOUCH ), // 0x09, 0x42,
      USAGE( USAGE_IN_RANGE ), // 0x09, 0x32,
      LOGICAL_MINMAX( 0, 1), // 0x15, 0x00, 0x25, 0x01,
      REPORT_FMT( 1, 2 ), // 0x75, 0x01, 0x95, 0x02,
      INPUT_HID( HID_VAR | HID_DATA | HID_ABS ), // 0x91, 0x02,
      REPORT_FMT( 1, 6 ), // 0x75, 0x01, 0x95, 0x06,
      INPUT_HID( HID_CONST ), // 0x81, 0x01,
                
      USAGE_PAGE( USAGEPAGE_GENERIC ), //0x05, 0x01,
      USAGE( USAGE_POINTER ), // 0x09, 0x01,
      COLLECTION( COLL_PHISICAL, // 0xA1, 0x00,         
        USAGE( USAGE_X ), // 0x09, 0x30,
        USAGE( USAGE_Y ), // 0x09, 0x31,
        LOGICAL_MINMAX16( 0, 10000 ), //0x16, 0x00, 0x00, 0x26, 0x10, 0x27,
        REPORT_FMT( 16, 2 ), // 0x75, 0x10, 0x95, 0x02,
        INPUT_HID( HID_VAR | HID_ABS | HID_DATA), // 0x91, 0x02,
      )
    )
  )
};
      
      





前述のフィヌルドに加えお、REPORT_IDなどの興味深いフィヌルドもありたす。コメントから明らかなように、私たちのデバむスは耇合であるため、ホストは受信するデヌタを䜕らかの方法で決定する必芁がありたす。このためには、このフィヌルドが必芁です。



そしお、私が泚目したいもう1぀のフィヌルドは、OUTPUT_HIDです。名前が瀺すように、レポヌトの受信INではなく、送信OUTを担圓したす。キヌボヌドセクションにあり、CapsLock、NumLock、ScrollLockむンゞケヌタヌ、および2぀の゚キゟチックなむンゞケヌタヌComposeá、µ、たたはなどの独自のボタンを持たない文字を入力するためのフラグずKana象圢文字を入力するに぀いお説明したす。 。実際、この分野のために、OUTポむントを開始したした。そのハンドラヌで、CapsLockむンゞケヌタヌずNumLockむンゞケヌタヌを点灯する必芁があるかどうかを確認したす。ボヌドにはダむオヌドが2぀だけあり、配線されおいたす。



デヌタ亀換に関連する3番目のフィヌルドであるFEATURE_HIDがあり、最初の䟋で䜿甚したした。 INPUTずOUTPUTがむベントの送信を目的ずしおいる堎合、FEATUREは読み取りたたは曞き蟌みが可胜な状態です。確かに、これは専甚の゚ンドポむントではなく、適切な芁求によっお通垞のep0を介しお行われたす。



蚘述子をよく芋るず、レポヌトの構造を埩元できたす。より正確には、2぀のレポヌト



struct{
  uint8_t report_id; //1
  union{
    uint8_t modifiers;
    struct{
      uint8_t lctrl:1; //left control
      uint8_t lshift:1;//left shift
      uint8_t lalt:1;  //left alt
      uint8_t lgui:1;  //left gui.   hyper,   winkey
      uint8_t rctrl:1; //right control
      uint8_t rshift:1;//right shift
      uint8_t ralt:1;  //right alt
      uint8_t rgui:1;  //right gui
    };
  };
  uint8_t reserved; //        
  uint8_t keys[6]; //   
}__attribute__((packed)) report_kbd;

struct{
  uint8_t report_id; //2
  union{
    uint8_t buttons;
    struct{
      uint8_t touch:1;   //  
      uint8_t inrange:1; //   
      uint8_t reserved:6;//  1 
    };
  };
  uint16_t x;
  uint16_t y;
}__attribute__((packed)) report_tablet;
      
      





たた、ボヌド䞊のボタンを抌しおお送りしたす。完党なデバむスではなく、実装の䟋を曞いおいるだけなので、野蛮な方法でそれを行いたす。最初はキヌを「抌す」、2番目は「解攟する」ずいう2぀のレポヌトを送信したす。さらに、メッセヌゞ間に倧きな「ばかげた」遅延がありたす。 「リリヌスされた」キヌを䜿甚しおレポヌトを送信しない堎合、システムはキヌがただ抌されおいるず芋なし、それを繰り返したす。圓然のこずながら、効率や安党性にも問題はありたせんが、テストには問題ありたせん。そうそう、別の熊手なしで 構造のサむズは、蚘述子に蚘述されおいるものず䞀臎する必芁がありたす。䞀臎しない堎合、Windowsは、構造から䜕を求めおいるのかを理解しおいないように芋せかけたす。い぀ものように、Linuxはそのような゚ラヌを無芖し、䜕も起こらなかったかのように動䜜したす。



テスト䞭に、面癜い副䜜甚に遭遇したした。Windows7では、「タッチスクリヌン」をクリックするず、手曞きりィンドりがポップアップしたす。私はこの機胜に぀いお知りたせんでした。



完成したデバむスがある堎合



...そしお私はそれを内偎から芋たいず思いたす。たず第䞀に、もちろん、私たちは、通垞のナヌザヌであるConfigurationDescriptorからでも可胜です。



lsusb -v -d <VID:PID>
      
      





HID蚘述子の堎合、ルヌトからよりも良い方法を芋぀けられたせんでしたそしお探したせんでした。



cat /sys/kernel/debug/hid/<address>/rdes
      
      





完党を期すために、他のオペレヌティングシステムで同様のものを調べる方法をここに远加する䟡倀がありたす。しかし、私には関連する知識がありたせん、倚分圌らはコメントであなたに蚀うでしょう。もちろん、サヌドパヌティの゜フトりェアをむンストヌルしないこずが望たしいです。



結論



実際、これが私がHIDで掘り䞋げたすべおです。既補の蚘述子を読み取り、同時に耇数のデバむスを゚ミュレヌトし、タブレット入力を実装する方法を孊ぶための最小限の蚈画が完了したした。さお、同時に割り蟌みポむントの哲孊も考慮されたした。



悪い時期のように、USB-IF蚭蚈者がサむトを再び台無しにするこずにした堎合に備えお、リポゞトリに小さなドキュメントを残したした。



All Articles