UsbPrn-Adapter

In der Schublade des Bastlers liegt des öfteren ein USB-Paralleldrucker-Konverter herum, der als Fehlinvestition als Ersatz für das fehlende Parallelport des neuen Notebooks oder Laptops schließlich auf die stoffliche Verwertung wartet.

Aber Stopp!

Mit ein paar Bauteilen kann man damit, moderne Software (etwa mein inpout32.dll) vorausgesetzt, trotzdem 8 Leuchtdioden mittels out-Befehl steuern!
Bis zu 4 Schrittmotoren gehen auch, aber das dürfte ruckeln, da der Ausgabedatenstrom nicht gleichmäßig fließt.

Das ganze geht ohne Kernel-Hacks! User-Mode genügt. Kein Treiber zu laden. Ab Windows 98. 64-Bit-Unterstützung inklusive. Linux auch.

in geht auch, allerdings auf 3 Bit begrenzt; siehe unten. Sogar ohne extra Hardware.

Man kann damit gut ein SPI- oder Hochvolt-Programmiergerät für AVR betreiben. Eine PonyProg2000-Erweiterung ist dafür in Arbeit. Immerhin arbeitet ein solches Ensemble aus USB-Paralleldrucker-Konverter und diesem Adapter ungefähr 10x so schnell wie ein USB-Seriell-Adapter im PingPong-Modus. Und man hat das Mehr an Ausgabeleitungen für die Hochvolt-Programmierung von zumindest 6-, 8- und 14-beinigen AVR-Typen.

Viele Programmiergeräte für USB benötigen einen programmierten Mikrocontroller. Ein Programmiergerät auf Basis eines USB-Paralleldrucker-Konverters löst das Henne-Ei-Problem auf elegante Weise. Das pure Einprogrammieren geht sehr schnell, nur das Rücklesen ist langsam.

Eine große Anzahl von Software verwendet inpout32.dll für den Zugriff auf ein (echtes) Parallelport. Da hierbei eine bekannte API als Zwischenschicht arbeitet, habe ich die DLL so umgestrickt, dass Software auf ein solches „unechtes“ Parallelport zugreifen kann. Wohlgemerkt, durch Lesen und Schreiben auf Portadresse 0x378 usw. — virtuell natürlich. Mit gewissen Einschränkungen bei der Anzahl von Portpins sowie Lesegeschwindigkeit. Daher lassen sich derartige Programme — trotz closed source und aussterbener Parallelports — mit diesem billigen Konverter weiter betreiben.

Technischer Hintergrund

Ein USB-Drucker-Konverter ist dazu gemacht, Paralleldrucker anzusteuern. Nichts weiter. Also muss sich das anzuschließende Gerät wie ein Paralleldrucker verhalten: Der Drucker erwartet Daten bei aktivem SROBE, und der Konverter fragt vom Drucker die Geräte-ID im Nibble-Modus ab. Außerdem kann dieser genau 3 Statusleitungen, nämlich Error, PaperEnd und Online, dem Computer melden. Das ist im USB-Standard so festgelegt. Deshalb funktioniert das gleichermaßen unter Windows und Linux.

Das Ausgeben von Bytes geht sehr schnell, einige 100 kByte/s sind kein Problem. Schneller als ein echtes Parallelport. Das hängt jeden USB-Seriell-Konverter locker ab.

Aber: Das Abfragen der 3 Statusbits dauert 1 ms! Das ist im Vergleich zu einem echten Parallelport sehr langsam. Etwa Faktor 100. Daher muss man beim Anfragen seriell arbeitender Geräte sehr viel Zeit mitbringen. Bei USB-Seriell-Adaptern ist es genauso.

Wichtig: Das Gros solcher Konverter hält das Datenport hochohmig im Tristate. Daher muss man das zuletzt ausgegebene Datenbyte auffangen.

Nicht bidirektional?

Druckerschnittstellen werden häufig mit „bidirektional“ beworben. Während PS/2-Bidirektionalität sowie EPP + ECP echte (8-bit)-Bidirektionalität meint, ist bei Druckern in der Regel nur die IEEE1284-Negotiation (BiTronics) gemeint, wofür Nibble Mode, also SPP, ausreicht.

Diese Funktion wird von USB-ParallelDrucker-Konvertern selbständig ausgeführt und an den PC geleitet. Für Bastelprojekte (also Nicht-Drucker) ist davon eher abzuraten:

Merke: Da USB-ParallelDrucker-Konverter nur für Drucker gedacht sind, ist eine 8-Bit-Bidirektionalität nicht eingebaut und daher nicht nutzbar. Parallelport-Scanner lassen sich niemals daran betreiben.

Es ist damit zu rechnen, dass die gängigen Chips 8-Bit-Bidirektionalität eingebaut haben, aber das ist alles undokumentiert. Aus heutiger Sicht lohnt es sich nicht, da herumzuforschen. Es gibt eine API (Windows und Linux gleichermaßen), um den IEEE1284-String abzufragen. Er darf bis zu 64 Kilobyte lang sein und darf binäre Nullen enthalten. Also kann man derartige Datenpakete hardwareseits zusammenstellen.

Einfache Lösung

Nur Eingabe

Für die Abfrage der drei Statusleitungen

wird überhaupt keine extra Hardware benötigt. Einfach anschließen genügt.

Die angegebenen Pin-Nummern beziehen sich auf D-Sub 25, nicht auf den 36-poligen Druckerstecker!

Dazu Ausgabe

Zum Ausgeben der 8 Datenbits wird zwingend ein Latch- oder Flipflop-Schaltkreis benötigt! Ansonsten erscheinen die Daten nur für ein paar Mikrosekunden mit STROBE. (Flankengetriggerte) Flipflops haben den Vorteil, dass man sich um die Polarität des Takteingangs keine Gedanken machen muss, da die Daten sowohl bei fallender als auch bei steigender Flanke von STROBE stabil anliegen. (Transparent-)Latches haben diesen Vorteil nicht, sie müssen bei STROBE=L transparent sein und bei STROBE=H verriegeln. Beim '373 oder '533 ist's dummerweise gerade verkehrt herum. Notfalls muss man STROBE invertieren, was ein weiteres Gatter kostet.

So kann das D-Latch vom Druckerport gespeist werden. Die LEDs sind hier nur zur Demonstration

Wer weniger Bits braucht, kann auch einen Flipflop-Schaltkreis mit weniger Bits verwenden, für 4 Bit beispielsweise 74HC(T)175, '192, '193, '195 … oder CMOS 4029, 4035, 4042, für 2 Bits 74HC(T)74 oder CMOS 4013 … was die Bastelkiste gerade hergibt. Wer nur Bipolarschaltkreise (74LS) vorfindet, kann auch diese verbauen und muss diese mit 5 V fremdspeisen. Fremdspeisung macht die Fangschaltung funktionssicherer.

Software

Beruht die bestehende Software auf InpOut32.dll oder dlportio.dll, muss man diese nur durch meine InpOut32.dll ersetzen. Diese DLL fängt dann Aufrufe von Inp32() und Out32() mit passenden Adressangaben (erster Parameter) entsprechend ab und führt sie zum Windows-Treiber für diesen USB-Paralleldrucker-Konverter. Es können auch mehrere Konverter an einen PC angeschlossen und verwendet werden.

Um die „wegemulierte“ Parallelportadresse herauszufinden, ruft man auf der Kommandozeile rundll32 inpout32.dll,Info auf. Dies ruft die eingebaute Info-Funktion mit standardisierter Parameterliste. Das dann erscheinende CMD-Fenster zeigt alles an und erlaubt es, mit den Bits am USB-Parallelport-Konverter herumzuspielen.

Beruht die bestehende Software nicht auf InpOut32.dll oder dlportio.dll, sollte man sie dahingehend portieren. Oder auf den Direktzugriff auf den USB-Treiber. Das ist jedoch deutlich komplizierter. Da das den Quelltext erfordert, muss man, wenn nicht vorhanden, das Programm neu schreiben. Pech!

Anwendung

Sterngucker: Keinesfalls sollte man die Bilddaten einer altertümlichen CCD-Kamera über ein solches Interface schicken! Es wäre unerträglich langsm, wenn's denn überhaupt funktioniert: Hier muss ein gesonderter Mikrocontroller her. Etwa ein USB2LPT mit problemangepasster Firmware sowie eine problemangepasste (nicht meine) InpOut32.dll.

Anwender-Bericht

Ein Anwender meinte, dass der USB-Paralleldrucker-Konverter von Ugreen sich gesondert verhält. Hier seine Anmerkungen zur Inbetriebnahme und mein Kommentar.

  1. Beim ersten Zugriff auf die Parallelport-Register nach dem Anschließen des Adapters von UGREEN sendet Windows eine Sequenz, um den (vermeintlich) angeschlossenen Drucker zu ermitteln. Dabei werden auch (entgegen Ihrer Vermutung) entsprechende Strobe-Pulse erzeugt, die zwingend mit ACK quittiert werden müssen, sonst "hängt" die Ausgabe der Daten auf den Port! Anschließend funkt Windows 10 aber nicht mehr dazwischen.
    Hm, komisch, ist womöglich eine Windows-10-Macke. Ich bin davon ausgegangen, dass Windows den Drucker ausschließlich mit dem entsprechenden USB-Request ermittelt und jeglicher USB-Paralleldrucker-Konverter daraus eine Abfrage im Nibble-Mode macht.
  2. Zumindest bei diesem Adapter muss während der Initialisierungssequenz von Windows (siehe oben) zwingend die "Paper End"-Leitung auf 0 gelegt werden, sonst erfolgt anschließend keine Ausgabe der Daten auf den Port. Danach kann der Pin jedoch als Input verwendet werden. Die BUSY-Leitung muss permanent auf 0 gelegt werden (oder ein dem 1284-Standard entsprechender BUSY-Puls generiert werden, was aber mit Aufwand verbunden ist).
    Hm, komisch, ist womöglich eine Windows-10-Macke. Das mit BUSY = 0 ist klar und deshalb Pin 11 mit GND verbunden. Danke für die Hinweise!
  3. Die DLL darf erst NACH Anstecken des USB-LPT-Adapters geladen werden, sonst funktionieren die Ausgaben nicht.
    Feature oder Bug: Die Suche nach USB-Paralleldrucker-Adaptern erfolgt beim Laden der DLL und nicht bei PnP-Ereignissen.
  4. Da meine Anwendung zyklische Ausgaben mit nahezu konstanter Frequenz auf den Parallelport erzeugt, konnte ich die aufwändige „Fangschaltung“ mit dem Latch durch eine ganz einfache Schaltung mit 1 Transistor (PNP), 1 Widerstand (100 kΩ) und 1 Kondensator (100 nF) ersetzen: Der Transistor (z. B. BC307) ist als Emitterfolger zwischen dem Strobe-Ausgang (Basis) und dem ACK-Eingang (Emitter) geschaltet; der Kollektor liegt auf GND. Am Emitter ist der 100-kΩ-Widerstand als Pullup (zu Pin 16 INIT) und der Kondensator nach GND angeschlossen, dadurch wird der ACK-Puls auf über 100 ms verlängert, so dass die Ausgänge D0 – D7 ihre Pegel für 100 ms beibehalten. So kann etwa 10× pro Sekunde ein neuer Wert ausgegeben werden, ohne dass zwischen den Daten nennenswerte „Lücken“ entstehen. Mit 22 nF und 82 kΩ kommt man auf etwa 40..50 Ausgaben pro Sekunde. (Das hängt aber auch von der Eingangsimpedanz des ACK-Pins des Adapters ab.) Diese 3 Bauteile konnte ich bei der bestehenden Hardware noch problemlos ohne eine zusätzliche Platine dazu löten. Der BUSY- und der Paper-End-Pin werden von der Hardware nicht benutzt und konnten einfach auf GND geklemmt werden.
    Eine interessante Lösung um das Latch/Flipflop einzusparen! Man erkauft sich das letzlich durch eine konstante maximale Ausgaberate. Ich vermute, gibt man mehr Daten aus, bleiben diese in den verschiedenen FIFOs hängen, bis sie an der Reihe sind. Wie bei einem langsamen Drucker. Es ist außerdem zu vermuten, dass dieser Trick mit allen USB-Paralleldrucker-Konvertern funktioniert.

„Nichtlineares“ Routing oder mehr E/A-Leitungen

Wenn man schon einen Zwischenstecker basteln muss und inpout32.dll eh' virtualisiert, kann man auch Datenausgänge auf Steuerausgänge legen oder per se nicht unterstützte Statuseingänge (BUSY und ACK) benutzen, um bestimmte Hardware glücklich zu machen.

Kann man der DLL irgendwie mitteilen, dass bestimmte Portbits für bestimmte Software entsprechend zu vertauschen ist? Etwa, um STROBE (Pin 1 = 0x37A Bit 0) zu generieren und BUSY (Pin 10 = 0x379 Bit 7) abzufragen? Entsprechendes wenn man ein invertierendes Latch/Flipflop eingebaut hat?

Vielleicht sogar, wenn man 2 6-Bit-Latches eingebaut hat um auf 12 Ausgabeleitungen zu kommen?

Ein voll ausgestattetes Parallelport würde vier Standardlogikschaltkreise erfordern
Die aktuelle (2015) Version von meiner inpout32.dll hat noch nichts dazu eingebaut. Bitte bei Bedarf anfragen!

Komfortable Lösung

Die Schaltung bietet die Parallelisierung der BUSY-Leitung in 3 Bits. Das macht das Lesen von bitseriellen Geräten um den Faktor 3 schneller. Lohnt sich also bei derartigen Geräten sehr. Auf Autodetect mithilfe bestimmter Brücken (wie beim Pony-STK200) wird man zugunsten der Geschwindigkeit besser verzichten.

Die Mehrheit der gesichteten Programmiergeräte verwendet BUSY für serielle Eingabedaten. Deshalb ist dieser Anschluss dafür auserwählt worden. Beispiele:

Gegenbeispiele gibt's natürlich auch:

Schaltplan

Der Schaltplan, auch verfügbar als Eagle-Quelle

Die Schaltung hat durch ihre „möglichst geniale“ Verdrahtung folgende Eigenschaften:

Der Einbau erfolgt einfach fliegend in ein entsprechendes Donglegehäuse, fertig.

So sieht's aus, wenn's fertig zusammengebaut ist. Hier ohne Deserialisierung; der aufgebrachte Schaltplan macht's klar.

Die Verbindungsleitungen zwischen USB-Paralleldrucker-Konverter, diesem Adapter und der Endschaltung (Programmiergerät) sollte möglichst kurz gehalten werden! Die USB-Leitung zu verlängern ist ohnehin viel bequemer.