Cheap LCD Uses USB Serial

Browsing the Asian marketplaces online is always an experience. Sometimes, you see things at ridiculously low prices. Other times, you see things and wonder who is buying them and why — a shrimp pillow? But sometimes, you see something that probably could have a more useful purpose than the proposed use case.

That’s the case with the glut of “smart displays” you can find at very low prices. Ostensibly, these are being sold as system monitors. A business-card-sized LCD hooks up via USB and shows your CPU speed, temperature, and so on. Of course, this requires sketchy Windows software. I don’t run Windows, and if I did, I wouldn’t be keen to put some strange service on just so I could see tiny displays of my system information. But a 3.5-inch IPS LCD screen for $15 or less probably has some other uses. But how to drive it? Turns out, it is easier than you think and the hardware looks reasonably hackable, too.

Like a lot of this cheap stuff, these screens are sold under a variety of names, and apparently, there are some subtle differences. Two of the main makers of these screens are Turing and XuanFang, although you rarely see those names in the online listings. As you might expect, though, someone has reverse-engineered the protocol, and there is Python software that will replace the stock Windows software the devices use. Even better, there is an example of using the library for your own purposes.

Inside Hardware

There’s not much behind the metal cover. Taking out the two screws reveals this neat layout.

The hardware is super simple — at least, the variant I have. A cheap CH552T CPU is an 8051 with a USB core. It should be possible to crack into it and reprogram the whole thing, but that seems like a lot of work. There’s a 3.3 V regulator and a handful of small components on the board.

There are two USB-C ports and a connector to hook up to a motherboard’s internal USB port. You can only use one of the ports at a time, though. There’s actually only one port. The different ports are there so you can route the wire based on your mounting preference.

From the software standpoint, the thing looks like… a serial port! I was hoping the USB conversion occurred outside the chip since a logic-level RS232 LCD display would have been very cool, indeed! Alas, no. The CH552 has its own USB controller. On the other hand, the device does have two normal UARTs, so it would be possible assuming you could reflash the controller.

Inside Software

The Python software is pretty simple to use. There are several versions of the display, and you do need to know which one you have: mine is a revision B. The software can find the serial port automatically, which seems to work well, or you can specify a port number. You can use simple calls to clear the screen, draw text, lay down images, and draw “progress bars” that the stock software uses as a meter.

Reading the code, there are several commands available. One provides a handshake with the display. You can also set the LED lighting, the brightness, and the orientation, portrait or landscape. To display text or graphics, you build an image and send that to the display.

The code provided uses the Pillow library for Python. Of course, it would be possible for you to directly interact with the screen in your own applications using the serial port directly. The underlying protocol sends 8 bytes at a time in a 10-byte packet. The code is easy to read, so you could easily work out your own drivers if you wanted to.

A Quick Example

Naturally, I had to try it out for myself. My goal? Show the last Hackaday headline on the diminutive screen. I stuck with Python since the libraries were ready to go, and I prepared a Jolly Wrencher graphic with a little room on the bottom.

The code just opens the display, scrapes the headline, draws it, and then quits. If you want constant updates, you must run the whole thing from a cron job or a systemd timer.

Here’s the code:

#!/usr/bin/env python3

import requests

from bs4 import BeautifulSoup
from library.lcd.lcd_comm_rev_b import LcdCommRevB, Orientation

# init LCD
lcd=LcdCommRevB() # default is AUTO,320,480
lcd.Reset() # Does nothing for Rev B hardware

# background graphic

# scrape
if (r.ok) :
   soup=BeautifulSoup(r.content, 'html.parser')
   entry=soup.find('div', class_='entry-intro')
# put title on LCD
   print(f"Found {title}\n")
   lcd.DisplayText(" " + title, 0, 280, font_size=16, font_color=(0,0,0), background_color=(255,255,255))
else : # error message
   lcd.DisplayText(" Internet error!", 0, 280, font_size=16, font_color=(0,0,0), background_color=(255,255,255))

The BeautifulSoup library makes it easy to pull the title — at least until we do a site redesign. After that, it is just a matter of calling DisplayText. You can find the code and the graphic you need on GitHub. A good idea to grab it from there since the browser display of the code above is always suspect when you need indentation.

If you need a quick and dirty (and cheap) LCD and you have a USB host port and Python, this could be just the ticket. Even without Python, the protocol would be easy to replicate. We are still tempted to reflash the CH552 to convert it to use a normal serial port. If you decide to give it a go, you’ll need to figure out programming. The header would be a good place to pull up the D+ pin to 3.3V to enter bootloader mode. Let us know how you do!

18 thoughts on “Cheap LCD Uses USB Serial

  1. Did you know there’s a USB HID standard for communicating with dot matrix graphics displays? It’s part of the Auxiliary Display page, alongside character-based displays. I used it a little while back for a project where I converted an old IBM typewriter keyboard which had an attached LCD screen. I was completely unable to find anything else which uses it! In its minimum form it just supports uploading bitmap data, but there are additional reports which can be implemented which add things like simple hardware acceleration.

    I mention this because it’d be ideal for making generic status displays, and is very much the protocol that the designers of this thing _should_ have used…

    1. I am in the process of building some USB controllers for a few LCD displays and this is *exactly* what I’m looking for. I wonder if it has a strange inhibition for low speed USB like CDC has. Hope not.

  2. If the author would like to pull the code from the chip, it looks like there’s two unpopulated resistors on that board R3 and R6. With luck one of them might be the boot mode jumper–put in a 10K resistor and power the board up and it should come up in bootloader mode. From there you can use:
    to dump the flash. Then it’s just some quality time with

    If neither of those resistors work, then you can just solder a small wire to the D+ on the USB connector (or anywhere else on the board you can tap it) and run that through a 10K resistor to +5V. And hope they didn’t program the flash protect bit. :( There may be a way to glitch the chip to bypass that, but I don’t know anything about that.

    1. Even if you can get a firmware (likely WCH already fixed the bug on that bootloader), using ghidra to analyze the binary is not a easy task and takes a long time.
      Just check the communication signals and rewrite a firmware may be way faster.

  3. I admit, EUR 15 for a display like this is not very expensive.
    And although I am interested in small TFT’s I do not find this one particular interesting. My own interests are much more towards a TFT with a much more capable uC on it’s back. The Displays from BigTreeTech may be very interesting. They’ve got different sizes, starting form around EUR 20 (with Touch screen!) and they have a capable STM32 (or clone?) on their back. I have not looked into details very much, but they seem to have some decent github repositories, with at least the basic code to drive the TFT’s.

    If anyone knows, is BigTreeTech friendly towards open Source, or are they mostly leaning on other’s people work?

    1. 3.5 ” lcd touch screen veteran here , I ported BTT’s touch Marlin interface to work on the MKS screens, yes BTT is very willing, they asked me if i would do a PR on my patches for the 2.8/3.5″ stm series MKS screen (MKS robin etc) and if they could fork my bootloader for mks robin (i removed MKS silly file encryption on boot loader despite stm being in RDP2) . While MKS units are ok the BTT clones (who stole from who?) are better in quality.
      see for the current marlin unit and see for the bootloader and fsmc code, whats missing is dma from eeprom to lcd (i only got as far as DMA from eeprom to ram and ram to lcd)
      Pros: handy known connectors (1/2 SPI + sd card reader, 3/4 uarts ) screens from 2.8 to 7″ use same codebase LVDL/LVGA support too
      cons : no on board PSU , limited pin uses for a really general board (no canbus etc)

      1. One thing that I was searching for another day is some kind of cheap, off the shelf, UI interface for my personal projects, something pretty much like the 3d printer interfaces, with LCD and Encoder, and perhaps button and buzzer, but all connected over a single interface, I think I2C would be ideal, one address for LCD, one for the encoder, e one for an io expander connecting some buttons and buzzer or leds

        And just 4 wires connecting this entire UI module to my project

        Is there anything like this already?
        Anyone know?

  4. For those that are interested in this sort of thing, youtuber Brian Lough has a little community around adopting a readily available and cheap ($12 landed to the US) display they’re dubbing the Cheap Yellow Display. They’re forming a bunch of examples and a nice discord for the projects. I’ve already purchased 13 of them from Aliexpress and deployed a few in real world projects and their great.

    They have a full ESP32 with wifi and bluetooth and serial and RGB LED and microsd slot and a few gpio.

    1. Hey, i’ve got one. Haven’t used it for anything though, maybe not the best HW design. Good to know there’s some effort in making use of these.

      This could’ve been nice to have as a display a bit over a year ago when i was still running automated test, so i could see the status of the tests on this screen and keep working on the main display. I used an Arduino and a RGB led ring instead and Julia-language program to communicate with the Arduino.

Leave a Reply

Please be kind and respectful to help make the comments section excellent. (Comment Policy)

This site uses Akismet to reduce spam. Learn how your comment data is processed.