Quirky Nimbus Hacking (part 2)
Details, details
The main point missing from my previous post was how to send anything to the gauges or the displays (well, and to the flash memory, but you'll have to dig up the datasheet for that one, it's very well explained).
Some people wanted a few more details about my previous experiment (Quirky Nimbus Hacking), so here they are:
Following protocol
Before starting, if you don't know what I2C is, better check it out first. I'll wait.
The imp communicates with the PIC using I2C as I already mentioned. Then in turn the PIC communicates with the displays and gauges, using also I2C. I haven't checked the displays reference number, nor did I dump the PIC, but if anyone does any of those things (or both), please let me know, I'm curious :D.
Sending data
The communication happens at 400Khz.
Displays
There are two register per display, one for controlling and another for data purposes.
Kind/Display | 0 | 1 | 2 | 3 |
---|---|---|---|---|
Control | 0x74 | 0x7C | 0x78 | 0x70 |
Data | 0x76 | 0x7E | 0x7A | 0x72 |
Initialization is needed before you can use the displays. Unfortunately, I haven't dump the PIC code, so I don't know what this initialization is exactly doing. For now, I just blindly call this (pseudocode):
// `disp` is my I2C object, configured using the pins from my previous post
for (CTL in [0x74, 0x7C, 0x78, 0x70]) {
disp.write(CTL, "\xE2");
disp.write(CTL, "\x20");
disp.write(CTL, "\xC0");
disp.write(CTL, "\x8D");
disp.write(CTL, "\xEB");
disp.write(CTL, "\x81\x30");
disp.write(CTL, "\xB5");
disp.write(CTL, "\xA1");
disp.write(CTL, "\x31");
disp.write(CTL, "\x46");
disp.write(CTL, "\x2D");
disp.write(CTL, "\x85");
disp.write(CTL, "\xF2\x00");
disp.write(CTL, "\xF3\x07");
disp.write(CTL, "\x90");
disp.write(CTL, "\xAF");
disp.write(CTL, "\x40");
}
After initialization, to show anything on a display:
disp.write(CTL, "\xB0");
disp.write(CTL, "\x10");
disp.write(CTL, "\x00");
disp.write(DATA, data);
...with data
being a 41 bytes long array (because our displays are 41x7 pixels). Each byte of the array draws one column of pixels on the display, starting from the left. So 0x7F
will draw a full row of pixels.
Gauges
Gauges don't need any kind of initialization before using, but there is a subregister to affect every gauge that the original firmware uses as such. Also, there is only one I2C register to manage them: 0x4A
.
The I2C packets are in the format:
[register] [subregister] [2 byte gauge value]
...and the subregisters are
Kind/Gauge | 0 | 1 | 2 | 3 | All |
---|---|---|---|---|---|
0xC8 | 0xE8 | 0xA8 | 0x88 | 0x0F |
...so:
disp.write(0x4A, 0xE88000);
...will put the second gauge at the middle point.
Final words
I hope I haven't confused anyone with all those details. I also expect the information to be correct, although I wrote most of it by memory, so some things might not be fully correct.
Anyway, if you still have any doubts, you know where to reach me!
Happy hacking :D