Hello all! This is the first post of this Blog. I’ll be posting about hacking and re-using various electronic devices, which might be obsolete, or maybe no information is available.
A friend of mine gave me an HP 3550 with an unfixeable error in the formatter board. So, it was time to tear it apart. I’ve salvaged some parts, including the display and its buttons.
That board had an unknown IC which seems to be driving the display controller, reading the key states, and driving 3 leds. That IC was the BU6740AK.
The quest for info about that IC
Doing a quick Google search, I’ve found that is a custom IC and that 2 people tried to reverse-engineer the protocol which uses.
The first page that I saw was about other HP printer which used the same IC, but I saw a lot of hints to take into account when trying to understand how this IC works. First of all, it seems to be just a simple SPI IO expander, even if some commands seems to be related to the display, it’s a matter of turning on and off some pins that are related to the display.
The second page talked about hacking the same board that I have, but unfortunately, the chap that wrote the article didn’t managed to finish his investigation.
Reverse engineering it: Pinout
So I went to my friends house, which happens to have a nice oscilloscope (4 channels, with digital decode stuff) to probe this thing.
I connected the original motherboard of the printer to the display, and hooked the 4 probes of the scope in some wires of this board. I could get the meaning of all the signals, so a pin-out was devised.
2: Vcc 3.3V
3: MISO (data out from the BU6740AK)
4: MOSI (data in to the BU6740AK)
5: SCK (clock in)
Note: the SPI works with MSB first, Mode 0 (logical 0 on idle clock and idle data), and 16 bits per transfer.
Reverse engineering it: Protocol
Initialization of the display
Since the motherboard of the printer sent some init commands, and characters, we had some information to work with.
14 commands were found to be sent always when the device powers up, so I assumed they’re init things:
Even if I don’t know what those commands mean, they seem to work (keep reading for some tests!).
After that, the motherboard started sending periodically some things, which I thought were related to polling the keys.
The first code was 0xFA00, and it went down until 0xF000. The BU6740AK did answer with the state of the keys only when 0xF800 and 0xF700 was sent.
When the thing sent 0xF800, the IC answered with the state of the keys: UP, BACK, DOWN, OK, HELP (corresponding to bits 4 thru 0 of the answer).
For the case of 0xF700, the IC answered with the state of the keys: MENU, STOP (corresponding to bits 7 and 6 of the answer).
It seems to be completely necessary to send the codes from 0xFA00 to 0xF000, even if the data readed back is not used.
Another interesting command is the one which sets the leds state. It’s a single command, which combines the 3 leds in it.
0x90X0, where X can be 0, 1, 2, 3, 4, 5, 6, 7 (each bit of that nibble sets a LED).
However, I thought this IC has more outputs that the ones used for the leds. After a lot of fiddling, this theory was confirmed.
Take a look at that picture of the IC, where I marked the number of some output pins. In fact, pin 12, pin 14, pin 15, pin 16 and pin 17 can be used as outputs if one modifies the previous command:
0x90XY, where X is the same as before, but the bits of Y means which pin (of the mentioned) are turned on or off.
So, I analyzed the LSB bits of the command and monitored the pins of the IC, which leads to this table of bit-to-pins correspondance:
- bit 0 controls Pin 14, push-pull output
- bit 1 controls Pin 15, push-pull output
- bit 2 controls Pin 16, push-pull output
- bit 3 controls Pin 17, push-pull output
- bit 4 controls one led (didn’t measured which one)
- bit 5 controls one led (didn’t measured which one)
- bit 6 controls one led (didn’t measured which one)
- bit 7 controls Pin 12, but this output is an open-collector (not push pull)
Data write to the display
This was the hardest part, and the most interesting as well. This display is a GLCD (which means each of its pixel can be accessed, in some way or another), so no “raw” text should be seen in the commands.
After some fiddling and head-scratching, I found out that the display expects data in a slighty different way of normal GLCDs, so, the data sent to it should write a column, and each byte increments the row number, but not the column position.
As you can see in the picture, the display accepts 8 bits worth of “columns” per each write. To fill the entire first column (i.e. 8 pixels for each row of the 32 available), you’ll need to send 32 commands.
Each commands low order bits (LSB 0 thru 7) are accomodated in the screen as this picture shows.
So, the motherboard did sent some commands which includes some kind of mode-set and the column and row selected, and after that, data:
- 0x600X, where X means the starting column
- 0x60CY, where Y means the starting row
- 0x60PP, where PP means the column data (8 bits)
- 0x60PP, where PP means the column data (8 bits) and so on
It seems that is not mandatory to fill the 32 rows each time.
Bonus: Arduino Library and example
I’ve created a small Arduino library.
NOTE!: PLEASE USE A 3.3V ARDUINO, or add a 1K resistor between MOSI (of the Arduino) and the BU6740AK serial data input, between SS (of the Arduino) and /CS of the BU6740 and between CLK (of the Arduino) and serial clock input of the BU6740; Vcc of the mentioned IC should be 3.3V always, don’t exceed this as you will destroy it.
This library allows to read the keyboard status, setting the LEDs (and outputs), and drive the display.
A brief explanation of these methods:
- Init(SS_pin, speed): Inits the SPI peripheral and the BU6740AK. Set the SS_pin number accordingly to what pin you’re using as SS (this pin should be connected to the /CS of the BU6740). Speed is measured in Hz. I’ve tested it with 4500000 withouth problems
- ClearScreen(): Fills the screen with the logical value 0, clearing the screen
- GetKeyboard(): Polls the key status and puts the result in the structure “KBState“. That structure has an item per each button, those are: Back, Down, Up, Help, Menu, Stop, Tick
- SetLeds(leds): Sets the LEDs (and the outputs as well). The value of leds should match the bits as I discussed earlier in the Leds sub-section
- SetRow(row): Sets the beginning row for the next write command of data. This parameter can go from 0 to 31
- SetColumn(col): Sets the beginning column for the next write command of data. This parameter can go from 0 to 19
- SendRows(row_data*, count): Sends rows bits, where row_data is the pointer of the row data bits, and count is the count of rows
Here is the project zipped (SPISlave.ino and BU6740AK.cpp and BU6740AK.h):
Note: Connect MOSI, CLK, MISO of the arduino to MOSI, CLK, MISO of the board, and SS to /CS. Remember that if you have a 5V Arduino you’ll need to add some resistors between the arduino and this thing (except for MISO), and of course a 3.3V power supply for ir.
Well, that’s all for this post. I hope you find this usefull, as it took a lot of work (not only the code, but this post as well).
I’ll add another post tomorrow, regarding another GLCD of another HP printer!