CUPS — the Common Unix Printing System — is an open source print spooling and scheduling system. One of the interesting aspects of CUPS is its filtering system, which can reconstitute print job data between formats. For example, rasterizing PDF graphics for output on non-PostScript printers.

Turns out there’s a CUPS filter for thermal printers similar to those Adafruit offers. With a little setup, it’s possible to have these producing razor-sharp graphics unlike anything I’ve seen from a thermal receipt printer before. Much nicer than our improvised Python library!

This guide is based on a tutorial by Stewart Russell, with some changes and additions to work with Adafruit’s various thermal printers.

Required items:

  • Raspberry Pi computer (any model or version)
  • Adafruit Mini Thermal Receipt Printer (any model, though the “Tiny” model with USB is easiest to interface)
  • Thermal paper roll(s) — the smaller printer models require special smaller rolls — and you may want at least one spare to run through while experimenting with settings
  • 5V power supply (2A or larger)
  • DC jack adapter and perhaps some breadboard jumper wires
  • Latest “full” version of Raspbian or Raspberry Pi OS from Raspberry Pi web site (not the “Lite” version)
  • 8 GB or larger SD/microSD card as appropriate
  • Monitor, keyboard and mouse
  • Network connection — Ethernet or WiFi

Some prior Raspberry Pi experience is assumed — downloading the OS, writing an SD card, basic system and network configuration, etc. You can search the Adafruit Learning System for related guides if any of this is unfamiliar.

If you’re using a TTL printer (not USB), DO NOT connect it to the Raspberry Pi yet! It will spit paper like mad. Some system configuration is required first…

Download the latest full (not “Lite”) version of Raspberry Pi OS or Raspbian from the official Pi downloads page. You’ll also need a keyboard, mouse and monitor attached. Write the OS to an 8GB or larger SD card, insert in the Raspberry Pi and power it up. After a minute or two you’ll see the Pi desktop.

On first boot, the system will prompt for some basic configuration like language and time zone. Once that’s set up to your liking, some additional configuration is needed…

From the “Pi” menu at the top left, select Preferences→Raspberry Pi Configuration…

Select the Interfaces tab.

Turn Serial Port ON, and Serial Console OFF, as shown in the image.

Click the “OK” button. You’ll be asked whether to reboot. Select “Yes” unless there’s other setup you want to do on your own first (such as networking) before rebooting.

Alternately, you can do this through a Terminal window if that’s more your style:

sudo raspi-config

You’ll find the Serial Port settings under “Interface Options.” Select “No” for the login shell, and “Yes” if asked about the serial port hardware (this option might not show up on older Pi models, where it’s always on). Tab over to “Finish” and reboot when asked.

All the Adafruit thermal printer varieties are bare units; they don’t have a DC barrel jack for power. Use a Female DC Power Adapter to connect to a 5V 2A power supply (our 5V 4A and 10A supplies can also work, if you already have one around, but do not use a 12V adapter).

During initial testing, you can press a couple of breadboard jumper wires into the printer’s JST power plug; the red wire is +, black wire is –. This is not very durable though…once you’re confident everything is working, you can remove the wires, clip off the JST plug, strip the ends and screw them directly to the adapter’s terminals.

For TTL printers (not USB): connect GND, RX and TX to the Raspberry Pi GPIO header in the positions shown. The transmit/receive lines will cross: the TX pin on the printer connects to RXD on the Pi, RX on the printer to TXD on the Pi.

If using the “Mini” Thermal Receipt Printer, the data plug from the printer can fit directly over these pins. Handy! Make sure you skip over the two 5V pins.

The “Tiny” and “Nano” printers (and “Printer Guts”) have a single 5-pin connector for power and data. Use something like F-M jumper wires or a Pi Cobbler and breadboard to make these connections. You’ll also need to split GND from the power supply to both the printer and the Pi GND pin.

The “Tiny” printer also features USB — that’s much easier if you have a port available!

It’s perfectly safe to connect the TX/RX directly to the Raspberry Pi GPIO pins. Though these printers are sometimes called “5V TTL,” in reality the controller logic all runs at 3.3 Volts…the inputs are simply 5 Volt tolerant so they can work with Arduino and similar.

If using a TTL printer and it starts printing a bunch of junk, disconnect power immediately! Follow the steps on the prior page to disable the serial console, then reboot.

Get to Know Your Printer

This is a simple but vital step for TTL printers. For USB printers, you can skip ahead, just after the first set of images below.

Your thermal printer may have arrived with a test page in the box or the paper bay. If not, or if you threw that away, you can generate a new one by installing a roll of paper and holding the feed button (on printers that have one) while connecting power, or tapping the button on the back of the “Nano” printer or the “Printer Guts.”

You need two or three pieces of information from the test page: the firmware version, the baud rate, and (for certain firmware types) the flow control setting. We’ll need these later.

Current TTL printers have a firmware version starting with “GV2,” and you’ll find all this information near the top of the page. The baud rate and flow control settings might match the photo, or might be different, that’s okay.

Earlier printers have “2.XX” firmware (e.g. 2.68) and all the information is near the bottom of the test page. 9600 and 19200 are common baud rate values.

Don’t fret if your printer has “older” firmware or if the baud rate is “only” 9600. All of these print images equally well, and the baud rate has no practical impact on the speed of printing! The paper feed rate is really the bottleneck…the baud rate just determines how we’ll get the Pi and printer communicating.

Once your printer’s connected, powered up and not spouting junk, launch a Terminal window and we’ll enter a few commands…

For a TTL (not USB) printer, type the following (substitute the correct baud rate for your printer):

stty -F /dev/serial0 19200
echo -e "This is a test.\\n\\n\\n" > /dev/serial0

(In older versions of Raspbian we’d use /dev/ttyAMA0 instead. If the above commands present a problem, check what’s in the /dev directory and use serial0 or AMA0 as necessary.)

If your TTL printer outputs only gibberish: check the baud rate and try again. Substitute 9600 or 19200 (or other) as needed to match what’s on the test page.

USB printers may present themselves to the system differently depending which USB-to-serial chip they use internally. Try the following first:

ls -l /dev/usb/lp0

If the response is something like:

crwxrwxr-x 1 root lp 180, 0 Mar 14 14:11 /dev/usb/lp0

Then this is a recent model. But if instead you get:

ls: cannot access '/dev/usb/lp0': No such file or directory

Then try:

ls -l /dev/ttyUSB0

Don’t fret if your USB printer is the “older” model. All of these print images equally well. Just need to know which it is: /dev/usb/lp0, or /dev/ttyUSB0.

Let’s verify we can print something. For a current “lp0” model, type:

chmod 777 /dev/usb/lp0
echo -e "This is a test.\\n\\n\\n" > /dev/usb/lp0

For an earlier “ttyUSB” printer, instead type:

echo -e "This is a test.\\n\\n\\n" > /dev/ttyUSB0

Whether TTL or USB, sometimes there’s a little bit of gibberish at the start of the first line printed; some residue in the serial buffer. This won’t happen on subsequent lines or after we’re done fully configuring the printer.

If nothing happens, check the following:

  • Is the printer connected to a 5V power source, 2A or larger? You should see an occasional LED blink from the printer.
  • Is thermal paper installed in the bay?
  • For TTL printers: are the TX/RX pins connected between Pi and printer, and do they cross? (i.e. TX on printer should go to RXD on Pi.) Is GND connected between printer and Pi?
  • For TTL printers: did you disable the serial console option and enable the serial port hardware? Check with raspi-config.

Commence Major Installation!

Once the printer passes the above basic test, it’s time to move on to software.

Make sure the package database is up-to-date, then install several packages…

sudo apt-get update
sudo apt-get install libcups2-dev libcupsimage2-dev git build-essential cups system-config-printer

Though not unusually large (about 75 MB total), there are many small pieces to process. This could take about 15 minutes to install if you’re on an older Pi, so you might want to go mow the lawn or something.

Once that’s done, download and install this CUPS filter for the thermal printer:

git clone https://github.com/adafruit/zj-58
cd zj-58
make
sudo ./install

You’ll see some warning messages as this compiles. That’s normal and these can be ignored. Errors will stop compilation, warnings are just being picky.

Extra Step for “GV2” Firmware TTL Printers

This does not apply to “2.XX” firmware or USB-connected printers, only GV2 TTL printers.

If baud rate and flow control on the test page read “19200” and “xon/xoff” respectively, you can skip this step, your printer’s already configured. Most currently have a different flow control setting though, in which case you should type:

python gv2_thermal_printer_config.py

This should respond with:

Setting flow control...OK!

Setting baudrate...OK!

If either step instead responds “no,” it’s probably one of these things:

  • This is a 2.XX firmware printer. This is fine and you can skip ahead.
  • It’s a GV2 firmware printer but is not factory-configured for 19200 baud. Edit the gv2_thermal_printer_config.py file, changing the BAUD value near the top to match what’s on your test page, and run this Python script again.
  • Printer isn’t powered on or correctly wired to the Pi.

You can print another test page if you like to confirm that the new settings worked.

Remaining Steps for ALL Printers

Regardless of firmware version, the rest of this setup is the same…

From the Pi menu, select Preferences→Print Settings.

If the “Print Settings” menu option is not present, the ZJ-58 CUPS filter didn’t install. Check the above steps and try again.

In the Print Settings dialog, click the “Add” button.

In some versions of Raspberry Pi OS, there might be an “Unlock” button at the top-right that you need to click first and enter the admin password.

For USB printers: later models will appear as an “Unknown” item in the Devices list (but the description will mention “USB port”)…no extra settings, just click “Forward.”

Earlier models appear as “USB Serial Port #1” in the Devices list. Highlight that item (not Serial Port #1, but “USB Serial Port #1” specifically), select the correct baud rate, then click the “Forward” button.

For TTL printers: If “Serial Port #1” is present, select that and set both the baud rate (19200 or 9600, to match your test page) and flow control (XON/XOFF (Software)). Make sure you get both of these! Other values can be defaults.

For older Raspbian OS versions, highlight “Enter URI” in the Devices list. Then in the device URI field, type “serial:/dev/serial0?baud=19200” (or 9600) (and might be “ttyAMA0” instead of “serial0”, depending on commands tested earlier). The device name is case-sensitive, so get this exactly right!

Click the “Forward” button…

On the next form, click “Select printer from database,” then scroll to the very bottom of the list and select “Zijiang” — this is a brand of thermal printer that happens to use the same command set.

Click “Forward” again, and on the next form select the “Zijiang ZJ-58” driver.

“Forward” once more, then you’ll have the option of assigning your printer a name…or just stick with the default ZJ-58.

Finally, click “Apply…”

…and you’ll now see the ZJ-58 printer in the Print Settings list.

Click the ZJ-58 icon, then from the “Printer” menu select “Properties.”

Set “Feed distance after print” to “feed 12mm,” then click OK.

Your mileage may vary; if you want more or less paper feed after each print, this is where you’ll find it later.

After clicking “OK,” the printer should now fully work with the Raspberry Pi via the “lp” service.

Let’s give it a try! Back to the Terminal window…

echo "This is a test." | lp

This should print the “This is a test.” string again…but unlike the first test, you’ll notice this one isn’t using the printer’s internal font…it’s actually rasterizing the text and we can tweak settings such as size.

You can try a printing bitmap as well:

lp -o fit-to-page /usr/share/raspberrypi-artwork/raspberry-pi-logo.png

“-o fit-to-page” is important — most graphics, if printed “actual-size,” would print just a narrow strip cropped from the left side.

If you get a lot of text gibberish instead of an image, and are using a “GV2” firmware printer, verify that flow control is set to XON/OFF both on the test page and the serial port properties. The steps for this are explained earlier on this page.

Most raster formats are supported, and for vector there’s PDF.

SVG is not directly supported. If you try to print an SVG file, you’ll see a bunch of text instead! You can use the LibreOffice Draw application included with Raspbian to open SVG files and save them as PDF for printing.

The Raspberry Pi logo shown is from a raster PNG file, you can see it’s a bit “dithery.” The dragon was an SVG file converted to PDF…this uses better halftoning and is amazingly sharp.

CUPS is a complex system way beyond the scope of this guide (there are entire books on the subject), but the CUPS web site explains some command-line options to get you started.

Accessing the printer from other systems on the same network requires just a few extra clicks…

From the Pi menu, select Preferences→Print Settings.

Double-click the ZJ-58 printer, or highlight it and select Printer→Properties:

In the “Policies” section, make sure “Shared” is checked, then click OK.

Returning to the main Print Settings form, now select Server→Settings…

Check the “Publish shared printers connected to this system” box, then click OK.

The printer is now accessible to other systems…even non-Linux computers running Windows or Mac OS X.

For example, on a Mac, go to the “Printers and Scanners” system preference form, click the add (+) icon, and you’ll see the networked printer available there:

It’s then possible to print to the thermal printer from any application.

Due to the peculiar media size, this will require some trial and error and experimentation. Though the media size is described as “58mm” wide, the actual imageable area is more like 48mm. If you try to print any “normal size” artwork, or if Media Size is set to “Letter,” you’ll just get a narrow strip from the left edge of the page.

This guide was first published on Apr 19, 2016. It was last updated on Apr 19, 2016.