Christians Webseite        << zurueck        vor >>

USB-HID Tastatur mit Atmel-Prozessor

usb

In diesem Projekt emuliert ein Atmel-Prozessor ein HID-Device für den USB-Port. Auslöser war die Notwendigkeit für eine Mini-Tastatur mit nur 2 Tasten die an einem Tablet benutzt werden kann.

Der Atmel-Prozessor wird per Software zu einem low-speed USB Device programmiert. Es wird keine spezielle USB-Hardware benötigt.

Human Interface Device ist eine USB-Geräteklasse für Tastatur, Maus und ähnliches. Die Treiber dafür sind fester Bestandteil von Windows und die Geräte sind dadurch direkt einsatzbereit.

Funktion und Ergebnis

Das Gerät funktioniert ausgezeichnet und problemlos:)

Direkt nach dem Anstecken am PC wird es vom Gerätemanager als HID-Device erkannt. Die Tasten verhalten sich exakt wie eine ganz normale Tastatur, in allen Situationen und Programmen. Das gleiche gilt für den Betrieb an einem Android-Tablet. Das Tablet muss aber USB-OTG unterstützen und man benötigt einen entsprechenden HW-Adapter.

V-USB

Die Basis ist das Software-Paket V-USB von Objective Development Software.
Das Paket ist ebenfalls auf GitHub verfügbar.

V-USB emuliert eine USB-Schnittstelle in Software. Das USB-Signaltiming ist sehr herausfordernd und wird deshalb teilweise durch Assembler-Routinen sichergestellt. Zusätzlich sind alle Protokolle enthalten um ein primitives Device nachzubilden und im Windows anzumelden.

Die usprünglichen Quellen scheinen deutlich älter als 10 Jahre zu sein. Immerhin sind die letzten Änderungen vor nur ca 2 Jahren eingepflegt worden. Das Alter scheint auch sonst keine Nachteile zu haben. In meiner Win10 Umgebung läuft alles sauber, Win11 habe ich nicht getestet.

Im Verzeichnis Example Projects liegen, wie der Name bereits vermuten lässt, jede Menge Beispiele. Viele sind ursprünglich für die ATTiny45 und 85 Prozessoren geschrieben. Eine Adaption auf bspw ATmega168 ist kein Problem, ein paar Details sind aber zu beachten. So können z.B. offensichtlich nur Devices mit interner PLL (ATTiny) ihren internen Oszillator bis über 16MHz hochdrehen. Ein ATmega168 kann das nicht. Ebenso variieren die Namen der diversen Register über die Prozessortypen.

Alles ist für die WinAVR Entwicklungsumgebung ausgelegt, das kommt mir sehr gelegen :).

Hardware

Auf der V-USB-Seite sind jede Menge Schaltungsbeispiele angegeben. Für meinen Einsatz habe ich daraus die beiden folgenden Schaltpläne abgeleitet. Links mit, rechts ohne Quarz. Man beachte besonders die unterschiedliche Belegung von INT0:
hid hid

Die Schaltung mit Quarz ist möglicherweise nachbausicherer und in der SW anspruchsloser. Dadurch sollte sie unkritischer im Timing sein und mehr Resourcen für eigene SW-Teile verfügbar machen.

Die Hardware ohne Quarz verdreht den internen 8MHz Oszillator sehr extrem, bis auf 12.8MHz. Das liegt (gerade noch) innerhalb der typischen Daten, ist aber keine zugesicherte Eigenschaft. Egal, einen Quarz spart man gerne ein wenn er nicht zwingend notwendig ist.

Mindestens eine der USB-Leitungen muss an den Interrupt INT0 angeschlossen sein. Die Portbelegung kann man bei Bedarf im Config-File ändern, ich würde aber mit dem Default beginnen.

Der Pull-Up auf der D- Leitung signalisiert dem PC dass es sich um ein Low-Speed Device handelt.

Die beiden Taster (nicht eingezeichnet) ziehen die Ports PD5 bzw. PD6 nach Masse. Die beiden 1k sind nur als primitive Absicherung gegen Überspanung eingefügt.

Für die Spannungsversorgung wird ein 3V3 Low-Drop Spannungsregler eingesetzt. Der kommt perfekt mit den 5V vom USB zurecht und man vermeidet die fragwürdigen Z-Dioden-Konstrukte aus den Beispielen.

An einem PC (=USB-Host) sollte das Device direkt erkannt und aktiviert werden. An anderen Geräten (Smartphone, Tablet, etc.) muss möglicherweise zusätzlich USB-OTG aktiviert werden.

Software

Der gesamte usbdrv-Ordner vom GitHub muss zum eigenen Projekt hinzugefügt werden.

Readme.txt und usbconfig.h unbedingt lesen. Dort werden entscheidende Informationen zum Verständnis der Konfiguration gegeben.

Die Datei usbconfig.h enthält die HW-Konfiguration. Sie muss passend editiert werden.

Viele Beispiele verwenden die Default-Portbelegung wie sie in usbconfig.h definiert ist. Sobald man davon abweicht funktioniert nichts mehr weil usbconfig.h nicht in allen Makefiles für einem neuen Build berücksichtigt wird. Mein Makefile habe ich aus mehreren Quellen zusammengestückelt. Leider bin ich kein C-Experte und kann nicht sagen ob das alles richtig und passend ist. Immerhin funktioniert alles..

Vorsicht beim Mischen der Beispiele, die Versionsstände und die HID-Beschreibungen sind unterschiedlich.

Download der Dateien für mein 2-Tasten-Projekt (HID.zip)
Die Zip-Datei enthält die von mir verwendeten Dateien main.c, Makefile und usbconfig.h.
Die V-USB-Bibliothek wird ebenfalls benötigt und muss gesondert von GitHub heruntergeladen werden. Die Revision der von mir verwendeten V-USB Bibliothek ist 2012-12-06 (falls es eine Rolle spielt).

Oszillatoren und Frequenzen

Für die HW und SW stehen verschiedene Frequenzen zur Auswahl. Alle Details sind im Readme.txt im usbdrv-Ordner beschrieben. 12MHz ist die untere Grenze mit der das USB-Timing noch garantiert werden kann. Direkte Vielfache des USB-Takts (1.5MHz) sind vorteilhaft und 18MHz scheint ein Optimum zu sein. Weitere Frequenzen wurden hinzugenommen um die populären Quarze der Arduino-Boards direkt zu unterstützen. Die Bibliothek enthält für jeden Takt speziell ausgelegte Assembler-Bausteine.

Mögliche Quarzfrequenzen: 12, 15, 16, 18 oder 20MHz.

Mögliche Frequenzen des internen RC-Oszillators (ohne Quarz): 12.8 oder 16.5MHz.

Die Betriebsart der RC-Oszillatoren geht hart an deren Abstimmungsgrenzen. Und die 16.5MHz sind nur bei Atmel-Typen wählbar die eine interne 64MHz PLL haben (ATTiny), aber z.B. nicht bei der ATmega8-Familie.

Der interne RC-Oszillator ist relativ ungenau und instabil (im Vergleich mit einem Quarz). Deshalb muss er regelmässig neu abgeglichen werden. Dazu wird der USB-Takt als Referenz verwendet. Der dafür notwendige Interrupt wird aus dem D- Signal abgeleitet, weshalb dieses Signal mit INT0 verbunden sein muss. Ebenso müssen die zugehörigen Routinen aktiviert werden (in der usbconfig.h). In Summe kostet der Verzicht auf den Quarz eine Menge interne Rechenleistung und Speicher-Resourcen (die man aber nicht immer wirklich benötigt).

Die Kalibrierroutine misst die Zeit zwischen den Interupts und verdreht das OSCCAL-Register bis die Zeit, und damit die Frequenz, stimmt.
hid

Aus dem Diagramm kann man im Bereich um 12MHz eine Steigung der Kennlinie von 3MHz/32 Bit ablesen. Das entspricht ca 93KHz/Bit. Die 1% Genauigkeitsanforderung für die 12MHz kann damit gerade so erfüllt werden.

Ein unangenehmer Nebeneffekt ist das das gesamte interne Timing des Prozessors an diesen Takt gekoppelt ist. Dadurch wird z.B. auch das Timing für die internen Eeprom Zugriffe stark beschleunigt (dort wird der OSCCAL-Wert gespeichert..), und das kann grenzwertig werden.

Links

V-USB Main Page

V-USB GitHub

4-Tasten-Keyboard-Beispiel

Key-Injector-Beispiel