Edu Garcia

Quirky Nimbus Hacking (part 2)

May 19, 2014 | 2 Minute Read

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

Tags: hacking nimbus quirky