Kampis Elektroecke

HID – Eine Einführung in das Protokoll

Die Kommunikation zwischen Mikrocontroller und PC ist erfolgreich hergestellt worden, was uns in die Lage versetzt Daten über USB zwischen zwei Geräten hin- und herzusenden. Um eine universelle Lösung zu erhalten, ist es aber notwendig, dass man auf bereits etablierte Protokolle und Treiber zurückgreift, sodass ein einzelner Treiber Geräte von unterschiedlichen Herstellern bedienen kann. Ich möchte, beginnend mit diesem Teil, zeigen, wie eine USB-Maus über den Mikrocontroller umgesetzt werden kann.

Eingabegeräte, wie z. B. Mäuse, Tastaturen und Joysticks, werden beim USB-Protokoll als HID (Human Interface Device) behandelt und entsprechend klassifiziert. Viele Betriebssysteme besitzen gängige Treiber um mit verschiedenen Eingabegeräten, wie z. B. Mäuse, umgehen zu können. Die Spezifikationen für die HID-Klasse des USB-Protokolls hat das USB-IF in dem Dokument Device Class Definition for Human Interface Devices (HID) zusammengetragen.

Klassenspezifische Gerätebeschreibungen:

Um ein Gerät der HID-Klasse zuzuordnen wird das Feld bInterfaceClass des Interface-Deskriptors auf den Wert 0x03 (USB_CLASS_HID) gesetzt.


Hinweis:

Die vergebenen Klassencodes und der entsprechende Deskriptor für die Konfiguration können beim USB-IF eingesehen werden.


Für jedes HID-konforme Interface muss dann noch ein entsprechender HID-Deskriptor angelegt werden.

Dieser HID-Deskriptor wird dann um beliebig viele Deskriptoren (mindestens aber einen Report-Deskriptor) erweitert.

Deskriptor Funktion
Report Descriptor Definiert, wie und in welchem Format, der Host und das Gerät Daten austauschen.
Physical Descriptor Beinhaltet Informationen über die Art der Eingaben und wie diese getätigt werden (optional).

Beide Deskriptorarten werden genutzt um das Eingabegerät und die Datenstruktur des Gerätes möglichst genau zu beschreiben. Der Host wählt dann, basierend auf diesen Informationen, einen geeigneten Treiber aus und lädt diesen.

Über das Feld bInterfaceSubClass kann zudem definiert werden ob das Gerät bereits während des Bootvorgangs genutzt werden kann.

Klassencode Beschreibung
0 Keine Unterklasse
1 Boot-Interface Unterklasse
2 – 255 Reserviert

Info:

Dieser Mechanismus wurde eingeführt, weil das Parsen des kompletten Report-Deskriptors immens viel Code benötigt und bei alten Systemen nicht komplett in den BIOS-Code eines Computers implementiert werden konnte. Daher können Eingabegeräte ein alternatives Boot-Interface aktivieren, um ein definiertes Protokoll zu verwenden. Dadurch sparte man sich einen generischen Parser und konnte stattdessen einen schlanken Parser für das eigene Protokoll implementieren.

Dies führe zu dem Umstand, dass man bei älteren Computern oftmals das Problem hatte, dass USB-Eingabegeräte während des Bootens nicht funktioniert haben. Bei modernen Computern ist das zum Glück kein Problem mehr.


Das Feld bInterfaceProtocol wird in Kombination mit dem bInterfaceSubClass-Feld genutzt um dem System während des Bootens mitzuteilen um welche Art von Eingabegerät es sich bei dem verwendeten Boot-Interface handelt.

Protokollcode Beschreibung
0 Kein Protokoll
1 Tastatur
2 Maus
3 – 255 Reserviert

Aufbau der Kommunikation:

Die Klasse der HID-Geräte unterstützt sowohl Low-Speed, als auch High-Speed Geräte. Für die Kommunikation zwischen Treiber und Gerät werden folgende Pipe- (bzw. Endpunkt-) Konfigurationen genutzt:

Konfiguration Beschreibung
Control
  • Kontrolle des USB-Gerätes
  • Übertragung der Daten durch einen GET_REPORT-Request
Interrupt Senden und Empfangen von Daten als Datenstrom

Jedes Gerät aus der HID-Klasse benötigt zwei feste und einen optionalen Endpunkt, die für die Kommunikation mit dem Host genutzt werden:

Endpunkt Funktion Benötigt
Endpunkt 0 Kontrollendpunkt für die Steuerung des Gerätes durch den Host Ja
Interrupt In Daten die vom Gerät zum Host gesendet werden Ja
Interrupt Out Daten die vom Host zum Gerät gesendet werden Nein

Der Host hat, neben den Standard-Requests, Zugriff auf klassenspezifische HID-Requests, mit denen er das Gerät steuern kann. Für die klassenspezifischen Requests werden die Bitfelder Type und Recipient im Feld bmRequestType auf 0x01 gesetzt.

Der GET_PROTOCOL– und der SET_PROTOCOL-Request können nur zusammen mit der Boot-Interface Unterklasse genutzt werden.

Über den GET_IDLE– und SET_IDLE-Request wird die Pollrate für das Gerät eingestellt, was dazu führt, dass das Gerät jede frühere Anfrage mit einem NAK beantwortet. Für die Pollrate können Werte von 1255 übertragen werden. Die Auflösung beträgt 4 ms, woraus ein Intervall von 4 bis 1020 ms resultiert. Wird ein Wert von 0 übertragen, so wartet der Endpunkt mit der Datenübertragung bis sich die Daten geändert haben. Die Genauigkeit der Zeit beträgt ±(10% + 2 ms).

Für eine erfolgreiche Kommunikation mit einem Gerät aus der HID-Klasse muss der Host das Format der empfangenen oder zu sendenen Daten kennen. Dieses Datenformat unterscheidet sich je nach Art des Eingabegerätes. So werden bei einer Maus deutlich weniger Daten benötigt als bei einer Tastatur. Damit die HID-Klasse möglichst alle Eingabegeräte abdecken kann, wurde der Report-Deskriptor eingeführt. Dieser Deskriptor beinhaltet genaue Angaben über das Ein- und Ausgabeformat eines Eingabegerätes. Sobald der Host den Report-Deskriptor ausgelesen hat, kann er über den GET_REPORT-Request einen Report von dem Gerät abfragen oder mittels eines SET_REPORT-Requests Daten zum Gerät senden.


Achtung:

Der GET_REPORT-Request verwendet den Kontrollendpunkt anstatt des entsprechenden Interruptendpunktes zur Kommunikation und soll nur verwendet werden, wenn Daten unabhängig vom Pollingintervall beim Gerät angefragt werden müssen.


Ein Report besteht aus einem Datenfeld mit einer Länge n, sowie einer optionalen Report ID.

Das Datenfeld selber besteht aus mehreren Elementen mit unterschiedlicher Länge. Der Aufbau wird im Report-Deskriptor festgelegt, wobei die einzelnen Elemente in verschiedene Gruppen unterteilt werden:

Aus der Reihenfolge ergibt sich auch gleichzeitig die Hierarchie der Gruppen. Ein Element aus der Gruppe Global verändert bis zum nächsten Global-Element alle Elemente aus der Gruppe Main, wohingegen ein Element aus der Gruppe Local nur für das nächste Main-Element gilt.

So ergibt sich z. B. aus dieser beispielhaften Beschreibung der folgende Report:

Report Size(3)    - Global
Report Count(2)   - Global
   Input          - Main
Report Size(8)    - Global
   Input          - Main
   Output         - Main

Der Report-Deskriptor beschreibt das Datenformat eines jeden Ein- und Ausgabeelementes des Gerätes, wobei ein Main-Item die Länge, den Bezug der Daten (absolut oder relativ) oder andere relevante Informationen definiert. Local– oder Global-Items werden hingegen genutzt um den Wertebereich der Elemente zu definieren.

Ein Report-Deskriptor muss mindestens die folgenden Elemente beinhalten:

  • Input, Output oder Feature
  • Usage
  • Usage Page
  • Logical Minimum
  • Logical Maximum
  • Report Size
  • Report Count

Für die Beschreibung der einzelnen Gruppenelemente werden zwei feste Datenformate genutzt:

Mit diesen Definitionen wird nun ein Report-Deskriptor zusammengebaut, der das Ein- und Ausgabeformat des Eingabegerätes beschreibt. Für eine USB-Maus sieht der Deskriptor z. B. folgendermaßen aus:

Usage Page(GenericDesktop),
Usage Page Usage(Mouse),
    Collection(Application),		
    Usage(Pointer),
    Collection(Physical),
        Usage Page(Buttons)
        Usage Minimum(1),
        Usage Maximum(3),
        Logical Minimum(0),
        LogicalMaximum(1),
        Report Count(3),
        ReportSize(1),
        Input(Data, Variable, Absolute),
        Report Count(1),
        ReportSize(5),
        Input(Constant),
        Usage Page(GenericDesktop),
        Usage(X),
        Usage(Y),
        Logical Minimum(-127),
        LogicalMaximum(127),
        Report Size(8),
        ReportCount(2),
        Input(Data, Variable, Relative), 
    EndCollection,
EndCollection

Damit wären die Grundzüge des HID-Protokolls abgeschlossen. Auf einen Physical-Deskriptor möchte ich aktuell verzichten, da dieser Deskriptor nur optional benötigt wird.

Im nächsten Teil des Tutorials wird der Mikrocontrollercode so angepasst, dass sich der Mikrocontroller als USB-Maus beim Host anmeldet.

Zurück

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert