USBLotIO

Aus Hobbyelektronik.org
Version vom 26. Dezember 2009, 23:19 Uhr von Chris (Diskussion | Beiträge) (Download-Link hinzugefügt)

Die parallele Schnittstelle am PC ist tot. Nachdem sie schon vor einigen Jahren bei Notebooks verschwunden ist, findet man sie heute auch kaum noch bei Desktop-PCs. Selbst bei teureren Mainboards sind oft nur noch Pinheader vorhanden. Ein Slotblech dafür wird generell nicht geliefert. Die ganzen Drucker sind jetzt schneller und mit dünneren Leitungen per USB angebunden. Soweit, so gut. Nur wird die Luft für Bastler langsam dünner, wenn man keine größeren Ambitionen zu RS232 hat (deren Anschlüsse am PC auch langsam aussterben).

Aus diesem Grund hatte ich die Idee, eine kleine Schaltung zu bauen, die zwar keinen Ersatz aber eine Alternative zum guten alten Parport darstellt.

Anforderungen

  • Anbindung, die auch noch in ein paar Jahren funktioniert
  • Einfacher Aufbau
  • Einfach vom PC ansprechbar
  • Erweiterbar

Hardware

Mit POV-Ray gerendertes Layout der Platinen

Die Anbindung an den PC findet per USB statt. Hier soll (wieder einmal) V-USB zum Einsatz kommen. Davon gibt es zwar schon ein Referenzdesign (PowerSwitch), dieses hat meiner Meinung ein paar Schwachstellen:

  • keine Erweiterbarkeit
  • Treiber erforderlich (laufen die vorhandenen überhaupt unter Win7?)
  • relativ großer Aufbau

Diesen Schwächen möchte ich mit einem ATTiny45 entgegenwirken. Dieser ist schön klein und braucht dank PLL (und automatischer Taktkalibrierung per USB) keinen externen Quarz. Damit man keine Treiber braucht, soll er sich dem Computer gegenüber als HID (Human Interface Device) ausgeben. Bleibt nur noch eines: Mit der Anbindung am PC bleiben nur noch 4 Pins am Tiny über - einer davon ist der Reset-Eingang - wie soll man da großartig Ausgänge schalten können? Ganz zu schweigen von der angestrebten Erweiterbarkeit...

Die Lösung hierfür ist einfach: der Mikrocontroller steuert Schieberegister an, die beliebig kaskadiert werden können. So kann man quasi beliebig viele Ausgänge an den AVR dengeln. Als Ausgabeschieberegister dienen 74xx595, welche einen Latch haben und die Datenleitungen in einem Rutsch aktualisiert werden können.

Um Signale auch lesen zu können, kommen 74xx165 zum Einsatz. Zwar haben diese auch einen Latch, allerdings ist dieser (anders als beim 595) low-aktiv. Damit wird's mit 4 I/Os am AVR eng. Gut, die Strobe-Leitungen muss man trennen, Clock kann gemeinsam laufen, nur sind jetzt schon alle Pins belegt. Es ist zwar möglich, die Daten ins Register zu laden, aber was bringen die Daten, wenn man sie nicht lesen kann?

Mit einem kleinen Trick kann man das aber bewältigen: Die Datenleitungen beider Richtungen auf einen I/O. Zum Schutz des Ausganges des Registers gibt es aber einen Reihenwiderstand. Zwischen dem Lesen und Schreiben muss die Datenleitung einfach nur noch als Eingang bzw. Ausgang geschalten werden.

Aber Vorsicht: dadurch, dass der Reset-Pin auch verwendet wird, kann der Mikrocontroller nur mit HVSP programmiert werden! (oder man lässt eine "Richtung" weg).

Software

AVR

Wie bereits erwähnt läuft auf dem AVR objective developments V-USB als HID. Grundlage für meine Implementierung war das "Datastore"-Beispiel, das zusätzlich um die automatische Kalibrierung der CPU-Frequenz erweitert wurde.

Da die USB-Schnittstelle zwangsläufig auf einem Interrupt-Pin hängt, der gleichzeitig auch für SPI verantwortlich ist, müssen die Schieberegister mit einem wesentlich langsameren Soft-SPI angesprochen werden.

Der USB-Client reagiert bei dem Beginn einer Übertragung mit einem Aufruf der Methode usbFunctionSetup. In ihr wird dann entschieden, ob es sich um einen Schreib- oder Lesevorgang handelt. Hier wird zum einen die Speicheradresse auf 0 gesetzt und beim Leseaufruf die Zustände der Registereingänge in den RAM geschrieben.

Anschließend wird von V-USB usbFunctionWrite bzw. usbFunctionRead je nach Reportgröße mehrmals aufgerufen. Im Read wird einfach nur der Inhalt des RAMs an den PC übertragen, beim Schreiben wird zuerst die Variable (die gleiche wie beim Lesen) gefüllt und nach dem letzten Wert vom PC die Methode processCommand aufgerufen.

Dort findet das eigentliche Schreiben auf die Register statt. Zusätzlich zum simplen Schreiben kann man den Controller mit ein paar Logikfunktionen beauftragen. Diese werden immer mit der letzten Ausgabe verwurstet. Folgende Operationen sind möglich:

  • Überschreiben
  • OR
  • AND
  • XOR

Zusätzlich kann man ein Flag zum Invertieren übergeben, dadurch werden die Funktionen NOR, NAND und XNOR sowie invertiertes Überschreiben ermöglicht. Mit einem weiteren Flag kann man die errechneten Werte ins EEProm des Controllers schreiben. Dadurch kann man direkt beim Einschalten der Hardware einen definierten Zustand ausgeben.

Das einzige, das man in der Software noch anpassen muss, ist die Anzahl der jeweiligen Schieberegister. Oder einfach unverändert lassen - dann werden jeweils 8 Register angenommen.

Ferner kann man eine ID in den EEProm schreiben, um mehrere (256) Devices zu unterscheiden. Diese ID wird bei jedem Lese-Vorgang im untersten Byte des Reports zurückgegeben.

PC

Auf dem PC kann eigentlich alles werkeln, was auf die entsprechenden Betriebssystem-APIs zugreifen kann. Ich beschränke mich auf Windows, die Portierung auf *nix/Mac/etc. sollte aber nicht allzu schwierig sein.

Im Grunde muss man nicht viel machen, das Schwierigste dürfte wahrscheinlich das Finden des Devices sein. Ich habe im C#-Programm Teile aus der Wiimote-Lib von Brian Peek genommen. Ist das HID gefunden und ein Handler gesetzt, können mit HidD_SetFeature und -GetFeature Reports an den AVR gesendet oder von ihm angefordert werden.

Wichtig ist hier eigentlich nur die Größe des übergebenen Arrays, bei falscher Länge kommt einfach nichts beim Device an! Man kann relativ viel Zeit damit verbringen, dort nach einem Fehler zu suchen, zumal sich ein vollbelegter Mikrocontroller (der nicht einmal UART hat) schlecht debuggen lässt.

Download

Datei:Usblotio.zip Firmware, EAGLE-Dateien und C#-Testprogramm