HP DeskJet 3050 GLCD Hack

Another post of displays reverse-engineering!
The same friend of my previous post also managed to score some HP DeskJets 3050, so it’s time to salvage its parts.

As usual, the display seems to be the most interesting bit of the printer. It’s a custom made, and no information is available, what a surprise!

 

It seems to be a graphical display, with white backlight and a serial interface.

The board itself is marked as CH376-80001-A, which seems to be the HP part number.

In the back of the display module I saw a “model” branding: BTG-12864CU-FCWB-L-6-C00. I quickly googled it, and of course, nothing.
However, I’ve tried to remove some of the text in the query, only looking for BTG-12864. This time, Google came with some chinese sites with a datasheet for a similar product.
That datasheet mentions a display with more pins than this one, so I left it aside for a while.

First things first: Pinout!

Like the previous hack, I’ve connected the original printer’s mainboard to the display, and hooked an oscilloscope in some of the pins of the module.
I was interested in the pinout of the GLCD module itself, and not the connector of the PCB assembly where it’s soldered; so I probed directly on the display pins.
This task was not so easy, since some pins like /RST or /CS could be misinterpreted as the Vcc or D/C (data or command) pins.

 


Nevertheless, the pinout for the display module (U1 marked in PCB) ended up being as this:

  1. /CS
  2. /RST
  3. D/C (data if one or command if zero)
  4. CLK
  5. DATA IN
  6. Vcc 3.3V
  7. GND

Since this board has a backlight, I also wanted to know where it was connected. It turns out that both backlight LEDs are connected to J1 (the original flat flex connector), so I traced to which pin they were connected.

 


Both leds have their anode tied to Vcc, but their cathodes are in PIN 1 and PIN 8 of the connector J1. Take note of how the numbering works on these kind of connectors.

What’s the Protocol?

I took the same route as the previous hack, dumping some frames of serial data, especially the ones that are sent in the start up of the device, and the ones sent when something gets written in the display.

The first frame contained the init sequence, which seems quite straight-forward:

  1. 0xA2
  2. 0xA1
  3. 0xC8
  4. 0x25
  5. 0x81
  6. 0x1B
  7. 0x2F

I’ve also captured some frames that seems to be writing the screen, and those begun with the same repeating pattern:

  1. 0x40
  2. 0xB0
  3. 0x10
  4. 0x00

Taking into account the datasheet for the module that I’ve found earlier, I saw that these codes match the commands mentioned in it, so it was a jackpot!

So, this GLCD module uses an ST7565P driver, configured to be interfaced via SPI in 8 bits mode.
If you look into the datasheet, you’ll find some things that are missing in the pinout that I’ve found earlier, like CS2, CLS, CL, etc. Besides that, it’s the same.

As a note, if you want to remove the GLCD display from the PCB where it’s soldered in, remember to add the capacitors to the pins 8, 9 and 10, as they were originally connected:
C4 is a bypass cap (pin 6 to ground), C2 is connected between pins 8 and 9, and C3 is connected from pin 10 to ground.

Testing it

 

I decided to use an STM32F407 (discovery kit) to try this GLCD. It was kind of painful since the /SS of the SPI peripherals of said MCU don’t seem to toggle if you use them in hardware mode; in fact, I’ve searched this, and it’s an actual thing with these MCUs. The /SS pin will ONLY get deaserted when the SPI peripheral gets de-inited; DAMN!. So, I ended up using a GPIO controlled by software to toggle the /SS.

Besides this little hiccup, it worked nice!

I haven’t managed to create a library for this GLCD, but its quite straightforward to look at it’s datasheet and figure it out.
However, I’ll copy the code which made the demo work. For now, it’s portable, but take note that you should implement the functions GLCD_SET_RESET, GLCD_SET_DC, GLCD_SET_CS and SPI_TX_one for your platform as follows:

  • GLCD_SET_RESET(r): Sets the pin /RST of the GLCD with the state of the argument r
  • GLCD_SET_DC(dc): Sets the pin D/C of the GLCD with the state of the argument dc
  • GLCD_SET_CS(cs): Sets the pin /CS of the GLCD with the state of the argument cs
  • SPI_TX_one(by): It should assert the pin /CS (setting it to zero), send the byte by via the SPI peripheral and finally, deasserting the pin /CS (setting it to one)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
	GLCD_SET_RESET(1); /* release reset */
 
	GLCD_SET_CS(1); /* not selected */
 
	GLCD_SET_DC(0);	/* D/C = 0 */
	SPI_TX_one(0xA2);	/* LCD Bias setting: 1/9 */
	SPI_TX_one(0xA1);	/* LCD Bias setting: 1/7 */
	SPI_TX_one(0xC0);	/* Common output mode: normal */
	SPI_TX_one(0x25);	/* Voltage regulator: 5 */
	SPI_TX_one(0x81);	/* Electronic volume set (first)     <- this sets the contrast */
	SPI_TX_one(0x1B);	/* Electronic volume set (second) 1B <- this sets the contrast */
	SPI_TX_one(0x2F);	/* Power control set: All things on */
	SPI_TX_one(0xAF);	/* Display ON */
 
	SPI_TX_one(0xA4);	/* Normal display, not testing it */
 
	SPI_TX_one(0x40);	/* Display start line set: 0 */
 
	SPI_TX_one(0xB0);	/* Page Address Set: 0 */
	SPI_TX_one(0x10);	/* Column address set: 0 msb */
	SPI_TX_one(0x00);	/* Column address set: 0 lsb */
 
	for (int x = 0; x < 8; x++)
	{
		GLCD_SET_DC(0);	/* D/C = 0 */
		SPI_TX_one(0xB0 | x);	/* Page Address Set: x */
		SPI_TX_one(0x10);	/* Column address set: 0 msb */
		SPI_TX_one(0x00);	/* Column address set: 0 lsb */
 
		GLCD_SET_DC(1);	/* D/C = 1 */
		for (int i = 0; i < 128; i++)
		{
			SPI_TX_one(i);
			//SPI_TX_one(image[i + (x * 128)]); /* Note: you should specify "image" as a byte array, and you can use the same byte-arrays as the one created for the KS0108 GLCD driver! */
		}
	}

I hope this hack is useful for someone. I have another things coming about an Argentinean 8085 development kit, which I’m currently working on.
Cheers!

Leave a Reply

Your email address will not be published. Required fields are marked *