Ich muss mit einem Arduino über SoftSerial einen Bon auf einem Kiosk-Thermodrucker ausgeben. Alle Textausgaben klappen problemlos, aber zuerst kommt ein Logo. Die Daten dafür liegen in einem Array of byte bzw. uint8_t im PROGMEM. Die Größe beträgt 2868 Bytes.
In zwei geschachtelten Loops (für 12 Zeilen zu je 239 Spalten) lese ich die Daten aus dem Array mit "pgm_read_byte(&logo[c])" und sende sie zeilenweise und mit der passenden ESC-Sequenz für den Grafikmode voran, zum Drucker. Da Softserial nur einen Puffer von 64 Bytes hat, mache ich zusätlich alle 32 Bytes eine Pause von 1000 Mikrosekunden (Drucker druckt mit 9600 Bit/s)...
Problem: Immer so ziemlich in der Mitte des Logos (was ja im Grafikmodus gedruckt wird), werden plötzlich anstelle des Grafikblocks für diese eine Zeile einige Buchstaben im Textmodus eingestreut, bevor der Rest des Logos wieder ordentlich gedruckt wird.
Das Argument für pgm_read_byte ist short, reicht also bis 32000, das kann es nicht sein. Gäbe es eine Größenbeschränkung für Arrays im PROGMEN, würde nach der "Störung" wohl nicht der Rest gedruckt ... was kann das sein?
Ich vermute noch einen Pufferüberlauf am Drucker, aber der gibt keine entsprechende Rückmeldung (XMODEM, kein XOFF).
Da Softserial nur einen Puffer von 64 Bytes hat, mache ich
zusätlich alle 32 Bytes eine Pause von 1000 Mikrosekunden (Drucker
druckt mit 9600 Bit/s)...
Du sendest also 12 Zeilen je (239+n) Bytes, mit n ~ 3 oder so
Du sendest mit 9600 Baud (ist das so gemeint?), also ~1Byte pro ms. Zudem machst Du alle 32 Byte 1 ms Pause.
--> Der Funktionsaufruf muss damit "blockierend" sein, denn sonst hilft dir 1ms nicht wirklich.
Du sendest also 8 Blöcke pro Zeile, der letzte nur ~ 18 Byte.
--> ist sicher, dass die nächste Zeile korrekt neu beginnt? Oder gib es ein "Blockgrenzen" Problem?
--> Sind zwei Logos immer gleich kaputt? Oder "random"? Wenn immer gleich, finde die genau Position heraus (notfalls unter einer Lupe die Pixel auszählen).
Da Softserial nur einen Puffer von 64 Bytes hat, mache ich
zusätlich alle 32 Bytes eine Pause von 1000 Mikrosekunden (Drucker
druckt mit 9600 Bit/s)...
Du sendest also 12 Zeilen je (239+n) Bytes, mit n ~ 3 oder so
ja, die ESC-Sequenz 27 '*' 3 239 0 kommt immer vorweg, dann folgen die 239 Bytes
Du sendest mit 9600 Baud (ist das so gemeint?), also ~1Byte pro ms.
Zudem machst Du alle 32 Byte 1 ms Pause.
--> Du sendest also 8 Blöcke pro Zeile, der letzte nur ~ 18 Byte.
ja, 239 (getestet mit der Bronbreite) ist leider eine Primzahl
--> ist sicher, dass die nächste Zeile korrekt neu beginnt? Oder gib es
ein "Blockgrenzen" Problem?
im Druckbild gibt es keine seitliche Verschiebung, ich verwende einen über alle Loops laufenden Zähler, der die Bytes im Array adressiert
--> Sind zwei Logos immer gleich kaputt? Oder "random"? Wenn immer
gleich, finde die genau Position heraus (notfalls unter einer Lupe die
Pixel auszählen).
Ja, das Druckbild ist immer an der gleichen Stelle kaputt, es sind auch immer die gleichen Zeichen, und das im Textmodus.
Ich habe den Eindruck, dass der Drucker intern die Bilddaten komprimiert und bei zu vielen Details ins Stolpern kommt. Ich habe anstelle des Logos mal ein anderes Testbild erstellt (nur ein Rahmen mit einem Kreis und einige Zahlen), das wird problemlos ausgedruckt ...
Zur Erstellung des Soucecodes für das Progmem-Array verwende ich immer das gleiche Programm.
Da Softserial nur einen Puffer von 64 Bytes hat, mache ich
zusätlich alle 32 Bytes eine Pause von 1000 Mikrosekunden (Drucker
druckt mit 9600 Bit/s)...
Verlängere die Pause mal auf mehr als 32 Millisekunden ...
Ich vermute noch einen Pufferüberlauf am Drucker, aber der gibt keine
entsprechende Rückmeldung (XMODEM, kein XOFF).
Ideen, Tips? Danke.
Ist die Übertragung 8-bit clean? Heißt genau: kannst Du jeden 8 Bit Wert senden, und der wird vom Drucker auch korrekt interpretiert. Auch Nullbytes, XON (0x11), XOFF (0x13), CFR, LF etc? Hast Du das verifiziert?
Ist die Übertragung auf der Leitung fehlerfrei? Sind die Daten korrekt? Hast Du das mit einem Logicanalyzer verifiziert?
Ich vermute noch einen Pufferüberlauf am Drucker, aber der gibt keine
entsprechende Rückmeldung (XMODEM, kein XOFF).
Ideen, Tips? Danke.
Ist die Übertragung 8-bit clean? Heißt genau: kannst Du jeden 8 Bit
Wert senden, und der wird vom Drucker auch korrekt interpretiert. Auch
Nullbytes, XON (0x11), XOFF (0x13), CFR, LF etc? Hast Du das
verifiziert?
So lange der Drucker die im ESC-Befehl für den Grafikmodus angegebene Anzahl von Bytes nicht vollständig erhalten hat, ist er 8-bit-clean. Man muss schließlich jedes beliebige Bitmuster drucken können.
Ausserhalb des Grafikmodus reagiert er natürlich unterschiedlich auf Steuercodes. Das hab ich aber alles schon fertig, z.B. Font auswählen, Fett, Condensed, Vorschub, Rückzug, Abschneiden voll und halb ... läuft alles einwadfrei. Nur die Grafik macht Stress.
Ist die Übertragung auf der Leitung fehlerfrei? Sind die Daten
korrekt? Hast Du das mit einem Logicanalyzer verifiziert?
Die Leitung vom Arduino Nano (5V!) zum Drucker ist ca. 30cm lang und führt über ein Max232-Modul (Breakout mit 9pol. Sub-D-Buchse) auf eine "echte" V24 am Drucker.
Ich habe den Eindruck, dass der Drucker intern die Bilddaten komprimiert
und bei zu vielen Details ins Stolpern kommt.
Wäre tatsächlich denkbar, dass er nicht genug Pufferspeicher hat, um das komplette Bild "raw" aufzubewahren, bis er es tatsächlich ausdrucken kann. Auch bei nur 9,6kBaud dürften die Daten weit schneller zu übertragen sein, als der Ducker sie ausdrucken kann.
Wenn es wirklich dieses Problem ist, dann liegt die Lösung klar auf der Hand: einfach langsamer senden. Also: zwar natürlich weiterhin mit 9,6kBaud, aber dafür mit Pausen zwischen den einzelnen Bytes. Die Pausen erst mal sehr großzügig wählen und dann schrittweise verringern.
Mit diesem Ansatz kann man also auf jeden Fall erst mal herausfinden, ob das wirklich das Problem ist. Falls ja, kann man dann die Pausenlänge optimieren.
Ist die Übertragung auf der Leitung fehlerfrei? Sind die Daten
korrekt? Hast Du das mit einem Logicanalyzer verifiziert?
Die Leitung vom Arduino Nano (5V!) zum Drucker ist ca. 30cm lang und
führt über ein Max232-Modul (Breakout mit 9pol. Sub-D-Buchse) auf eine
"echte" V24 am Drucker.
Und hast Du das messtechnisch verifiziert, dass da wirklich die Daten drüberlaufen, von denen Du glaubst, dass sie drüberlaufen? Ansonsten ist das alles nur Raterei.
Du kannst ja auch einen PC ans andere Ende hängen und die ankommenden Bytes mitprotokollieren und vergleichen. Und Du kannst die Daten auch vom PC an den Drucker schicken. Damit schließt Du den Arduino als Fehlerquelle aus.
Schafft der Drucker es eigentlich, nach etwa 240 Millisekunden das Papier um eine ganze Zeile zu transportieren? Druckt das Ding vier (Graphik-) Zeilen pro Sekunde?
Wenn der Drucker /ohne Handshake/ angesteuert wird, könnte bereits das ein Problem sein
Schafft der Drucker es eigentlich, nach etwa 240 Millisekunden das
Papier um eine ganze Zeile zu transportieren? Druckt das Ding vier
(Graphik-) Zeilen pro Sekunde?
Wenn der Drucker /ohne Handshake/ angesteuert wird, könnte bereits das
ein Problem sein
Ganz genau. Und wenn man zu doof/faul ist, das (vermutlich vorhandene Hardware-) Handshake zu benutzen, dann ist halt "Senden mit Pausen" angesagt.
Ich habe einfach nicht die Zeit, das Problem bis zur endgültigen Lösung
zu lösen, muss erstmal so. Wird vermutlich niemandem ausser mir
auffallen. Ist nicht schön, aber so ist das Leben ...
Scheiße schwimmt immer wieder hoch. Dieses mal solltest du dir die Zeit nehmen, das Problem vollständig zu analysieren, anstatt zu raten.
Ich plädiere immer noch dafür, die Stromversorgung zu kontrollieren.
So lange der Drucker die im ESC-Befehl für den Grafikmodus angegebene
Anzahl von Bytes nicht vollständig erhalten hat, ist er 8-bit-clean. Man
muss schließlich jedes beliebige Bitmuster drucken können.
Es gibt keinen Code zum Abbrechen oder neu aufsetzen?
Prinzipiell kann man auch in Bitmuster Escapecodes einbauen. Mit einem speziellen Byte (z.B. 47), dass im Datenstrom verdoppelt wird, wenn es kein Escape-Code ist.