Reverse engineering the RX-8’s instrument cluster, part one

In order to see how easy it would be to mess around with this car’s on-board systems, I figured the easiest and cheapest way would be to buy an old instrument cluster from eBay and see what I could get it to do.
In reasonably short order (two evenings after work) I managed to get most of the major functions working. All of the stuff you’re about to read was performed without access to an actual vehicle, just to its instrument panel and the internet πŸ˜‰

So, before we get started, here’s a video to see what can be done with about 8 hours of poking around:

The RX-8 is reasonably simple from an electrical system point of view in that it only has a single, high-speed CAN bus that links most of the major vehicle subsystems together. There are many other good references that explan exactly what CAN bus is and exactly how it works, so I’ll simply summarise it here.

Typically, the CAN bus comprises of a twisted-pair of wires, terminated at each end by a 120Ξ© resistor. It’s a differential bus (i.e. each signal has a “mirror” of it on the second wire) and also not ground-referenced, meaning it can put up with a reasonable amount of disparity between the ground potentials of different nodes. This tends to make it quite robust and hence well suited for the nightmare of an electrical environment present in a car.

The CAN bus is literally that – a common data channel to which all participating nodes can listen simultaneously whilst one of the nodes talks. This also means that it inherently a broadcast arrangement – anything that any one node says can be heard by any of the other nodes on the bus. As such, all you need to do to “talk to” a CAN device is send data to the bus that the particular device is listening for, such as vehicle road speed or engine temperature. If you can compose a valid message and transmit it, there’s a fair likelihood you’ll get the device to respond. In the case of an instrument panel, this response is usually visual in that a warning indicator will light up or a gauge move.

In order to play this game, some hardware is needed that can take the messages you want to send to the bus and turn them into the actual electrical impluses required. As ever, the most convenient and accessible way of doing this for me was with the ubiquitous Arduino microcontroller board and a CAN bus interface shield (in Arduino parlance, a shield is an add-on board that matches the Arduino’s footprint and stacks on to the pin headears either side of the board, making it very easy to use).

The total bill of materials for this exercise is as follows:

  • RX-8 instrument cluster (eBay, Β£15 for mine)
  • Arduino Uno (SKPang, Β£23.88)
  • SparkFun CAN bus shield for Arduino (SKPang, Β£36)
  • Arduino development environment, available for Mac, Linux and Windows (free, downloadable from the Arduino web site)
  • Cory J. Fowler’s MCP2515 Arduino library, which does all of the hard work with respect to talking to the CAN bus (free from GitHub)
  • One 120Ξ© resistor to terminate the Arduino end of the CAN bus (the instrument panel has a 120Ξ© resistor already in it)
  • Female DB9 connector to hook up to the CAN shield
  • 12v power supply to power the instrument cluster
  • USB cable to connect your computer to the Arduino
  • Miscellaneous wire, soldering tools etc.

Given the amount of stuff I had knocking around already, all I needed to buy was the CAN shield and the instrument cluster, coming to about Β£60 delivered.

The Mazda RX-8 wiring diagrams are available as part of the car’s service manual, located here,Β and the section relating to the instrument cluster is on page 28 of chapter 13. This allows you to locate the five most interesting pins: Ground, constant 12v, switched 12v, and the two CAN bus pins. All of these are located on the ‘A’ (smaller) connector.

As I didn’t have a proper wiring loom available, I simply cut away the socket shroud and soldered wires for power, ground and CAN directly to the pins of the connector, however if you’re working with an instrument cluster from your own vehicle I’d strongly recommend using connectors of some sort, even if they just push over the pins, so that you can re-use the cluster in your car again!

Applying power to the constant 12v input causes the cluster to initialise by sweeping all of the analogue gauges to find their zero positions. If you apply 12v to the switched input, the cluster will then illuminate white as it is when you turn on the car’s ignition.

It’s important to note at this stage that there are many indicators that come on of their own accord. Some, such as the fuel low or SRS warning lights, are looking for an input on a dedicated wire. Others, such as the ABS, water low, low oil pressure, charge and check engine lights appear as the instrument cluster’s microcontroller isn’t hearing anything on the CAN bus from the ECUs responsible for them, so it fails ‘safe’ by informing the driver there is an error with those systems.

Hook up the CAN shield to the CAN bus pins on the instrument panel, and it’s ready to talk.

I wrote some simple code to ‘fuzz’ the Β instrument panel. CAN messages, in their most common form, comprise of an address, a message type, a length field and one or more bytes of data. From information I’d found on this site, CAN message identifier 0x201 looked interesting, so I set all the bits in the 8-byte data payload high. This resulted in the rev counter going full scale, so we had a winner πŸ™‚

To cut a long story short, a couple of hours noodling around with this produced the following abysmal example of how not to code, but nonetheless it worked well enough to make the YouTube video that probably brought you to this blog entry πŸ™‚ It’s being re-written to use a timer interrupt routine to handle the CAN traffic rather than having the periodicity of the CAN messages determined by how often the control loop cycles; nonetheless it should get you started on talking to CAN devices:


38 thoughts on “Reverse engineering the RX-8’s instrument cluster, part one

  1. Miroslav

    Hello. Nice job Sir, it actually helped me a lot to get involved with the problem. I’m in the same pickle right now, having spare RX-8 instrument panel on my desk analyzing CAN readouts. I successfully control temp gauge, RPM meter and speed at the LCD, but I have troubles with all MIL symbols and oil gauge. As far as I examined, oil gauge has only two positions – no oil pressure and some oil pressure. Am I correct?
    My second question is – if you power up the gauges, does any MIL except SRS and water temp (merry-go-round) come up? Mine don’t:
    Is this standard behavior, do I have to light them up first with CANBus? Thanks, Miroslav

  2. Harry Post author

    Hi Miroslav,

    Glad this helped πŸ™‚

    You are quite right: the oil pressure gauge is braindamaged and would, in my opinion, be better served with a light! There is nothing but an on/off pressure sensor on the engine and hence the gauge is coded to read either “nothing” or “just over half”. Really annoys me! Also, the temp gauge plays a similar game: once it’s up to temperature, reasonably large variations won’t move the needle. This was done so as not to scare the customer by seeing the needle move under normal conditions. Great, except that it gives you no warning of impending doom due to overheating. Nice one, Mazda…

    On mine, the SRS and Check Engine lights come on pretty much straight away. They’re closely followed by ABS, EPS and brake warning lights, then the fuel low warning, then about four seconds after that the low water (it’s not temperature as far as I can tell – it is triggered by a ‘water level low’ sensor in the engine coolant expansion tank), oil and charge lights come on.

    To extinguish those lights (and keep them extinguished) you have to keep firing the relevant PIDs over CAN otherwise the instrument cluster assumes an error and lights up the PIDs.

    In my crap bit of code it loops round, shooting these values continually at the instrument cluster. In the video, you can see the cluster initialise. When the backlight comes on is when power is applied with no CAN traffic. Only when the rev counter starts moving is the Arduino sending traffic to the cluster over CAN.

    With the dashboard disconnected, it will light up like a pinball machine as the error lights “fail safe” – i.e. they tell you there’s a problem as they’re not hearing the appropriate ECUs (ABS, PCM etc) talk to the cluster. If you’re not seeing that I’m going to guess there may be something wrong with your cluster, although seeing as I’ve only done this with mine, I can’t say for sure.

    Hope that helps!

  3. Kyle

    Hoping you may be able to help. I’ve been researching the RX8 Instrument Cluster and came across your article. I have a Series 1 RX8 and have been trying to swap in the Series 2 instrument cluster. The only problem I’ve encountered so far is that I haven’t been able to edit the odometer on the Series 2 Cluster to match my car and I don’t want to swap it without the correct mileage. So far I’ve been able to take the data off the EEPROM Chip that stores the mileage but have had no success decoding it. I have a .bin file, but cannot decode the hexidecimal code. If you could offer any insight here that would be great!

    So now onto my question, by feeding the cluster data through CAN have you been able to get the speedometer working to the point where the odometer counts mileage as well? If so, I would be able to do the same and increase the mileage on my series 2 cluster to the correct mileage.

    Your help is much appreciated
    Thanks Kyle

  4. Beastie Boy

    We are building a Time Attack RX-8 with an REW swap and a Syvecs ECU. We are not going to use the OEM ECU at all but we want to retain the OEM Steering controller. Fortunately I found your site. From what I know the steering controller needs revs and vehicle speed through CAN/BUS messages in order to work and alter the sensitivity. Both the instrument panel and the steering use the HS-CAN and I think if those signals work with the instrument panel then the steering can work as well and by changing the speed input we will be able to change the amount of power steering assist.
    When we used your code with the library you have here we had error messages with the CAN. We did some minor changes to the code and now it drives the instrument panel without any error codes, and I have uploaded it here.

    Thank you very much for putting all the info


    SoftwareSerial sLCD = SoftwareSerial(3, 6); /* Serial LCD is connected on pin 14 (Analog input 0) */
    #define COMMAND 0xFE
    #define CLEAR 0x01
    #define LINE0 0x80
    #define LINE1 0xC0

    /* Define Joystick connection */
    #define UP A1
    #define RIGHT A2
    #define DOWN A3
    #define CLICK A4
    #define LEFT A5

    #define CANint 2
    #define LED2 8
    #define LED3 7

    #define NOP __asm__ (“nop\n\t”)

    MCP_CAN CAN0(10); // Set CS to pin 10

    void setup() {

    sLCD.print(“RX-8 CAN control”);

    Serial.println(“Setup pins”);
    pinMode(LED2, OUTPUT);
    pinMode(LED3, OUTPUT);
    pinMode(CANint, INPUT);

    Serial.println(“Enable pullups”);
    digitalWrite(LED2, LOW);
    digitalWrite(UP, HIGH); /* Enable internal pull-ups */
    digitalWrite(DOWN, HIGH);
    digitalWrite(LEFT, HIGH);
    digitalWrite(RIGHT, HIGH);
    digitalWrite(CLICK, HIGH);

    Serial.println(“CAN init:”);
    if (CAN0.begin(CAN_500KBPS) == CAN_OK) {
    } else {
    Serial.println(“fail :-(“);
    while (1) {
    Serial.print(“Zzz… “);
    // Debug: iu

    Serial.println(“Good to go!”);

    unsigned char stmp[8] = {0, 0, 0, 0, 0, 0, 0, 0};
    unsigned char otmp[8] = {255,255,255,255,255,255,255,255};
    unsigned char statusPCM[8] = {125,0,0,0,156,0,0,0};
    unsigned char statusMIL[8] = {140,0,0,0,0,0,0,0};
    unsigned char statusDSC[8] = {0,0,0,0,0,0,0,0};
    char message[17];

    unsigned int i=0;
    unsigned int j=0;
    unsigned int pid=0;

    void loop() {
    if(digitalRead(UP)==0) {
    Serial.println(“PID cycling”);
    for (pid=0x4B0;pid 120) {
    switch (j) {
    case (5):
    clearAndPrint(” oil pressure”);
    case (6):
    clearAndPrint(“No oil pressure”);
    case (7):
    clearAndPrint(” oil pressure”);
    case (8):
    clearAndPrint(“Low water MIL”);
    case (9):
    clearAndPrint(“Oil presure MIL”);
    case (10):
    clearAndPrint(“Bat charge MIL”);
    case (11):
    clearAndPrint(“Check engine MIL”);
    case (12):
    clearAndPrint(“Check engine -_-“);
    case (13):
    clearAndPrint(“Speedo ramp”);
    case (15):
    clearAndPrint(“ETC Disabled”);
    case (16):
    clearAndPrint(“ETC Active -_-_-“);
    case (17):
    clearAndPrint(“Brake fail MIL”);
    case (18):
    clearAndPrint(“ABS MIL”);
    case (19):
    clearAndPrint(“DSC off”);
    case (20):
    case (21):
    sLCD.print(“RX-8 CAN control”);

    if(digitalRead(LEFT)==0) {
    Serial.println(“Left: RPM sweep”);
    for (i=0;i<129;i++) {
    for (j=0;j<10;j++){
    CAN0.sendMsgBuf(0x201, 0, 8, stmp);

    if(digitalRead(RIGHT)==0) {
    Serial.println("Right: Fuel sweep");
    for (j=5;j<8;j++) {
    for (i=0;i<256;i++) {
    Serial.print("Byte ");
    Serial.print(" bits ");
    Serial.print(i, BIN);
    Serial.print(" value ");
    CAN0.sendMsgBuf(0x212, 0, 8, stmp);

    void clearLCD(void) {

    void clearAndPrint(String text) {

  5. Daz

    Not as technically minded as you guys so please forgive me. This might sound like a daft question but in your honest opinion do you think its possible for an auto electrician to make the rx8 cluster work in a toyota mrs kit car in on with.Im about to start fabricating the dash hence my question, would i be able to use the cars original sensors etc that send a signal to the original cluster or is it more complicated than that.
    Your help with this matter would be most appreciated.
    Many thanks

  6. Harry Post author

    Hi Kyle,
    Not fiddled around with the odometer yet, however there’s usually some negotiation that goes on between the ECU and the instrument cluster to ensure that you’re not trying to ‘clock’ the car, i.e. roll back the odometer. I’ve been recording all the CAN data generated by the car for the last couple of months as I’m going to have to synthesise it when the ECU gets swapped out, so once I’ve analysed these data dumps I might be able to spot the messages that make the odo do its thing. I’ll add another post if / when I manage it, but Real Life has got in the way a bit at the moment!

  7. Harry Post author

    Hi Beastie Boy!
    You’re very welcome, and thanks for the corrections – I’ll edit the main post to reflect these and try it all again in the not-too-distant future. As an aside, by replaying the speed data into the CANbus, the EPS did indeed suddenly come to life with the stock ECU disconnected, so I reckon you’ll be good to go with that πŸ™‚

  8. Harry Post author

    Hi Daz,

    I think the MRS is CAN-based, so you might be lucky in that the major instruments (speed, RPM) might “just work”… Certain things like the headlight telltales, fuel gauge etc. are all old-school direct wire stuff, so they can be made to work easily enough. The trick to getting everything else working would be to have a CAN translator, i.e. have the car’s high-speed CAN with the Toyota dialect data on it being read by a microcontroller that could then turn it into the dialect (Ford / Mazda) that the RX-8’s dash can read.

    The actual code and hardware to do it wouldn’t be that difficult, but building the translation matrix that turns one dialect to another is where the time goes. There are similar products around, but they’re both expensive and generally suited to a single application. I’d quite like to make a CAN Babelfish, so to speak, that could be loaded with dictionaries for the source and target dialects and do the translation for any application. That might be a way off yet, though, as my day job is keeping me way too busy right now!

  9. Giannis


    I’m trying to communicate with an RX8 cluster using an arduino UNO and the CAN-BUS shield from elecfreaks but with no result till now. Can you please confirm if my pins are correct? 1L=CANH and 1J=CANL? Also the 12v power supply i’m using has output of just 1 amp, is it sufficient? The dials indeed do the sweep-test when i plug it in. Sorry for the newbie questions..

  10. Harry Post author

    On my first attempt even though I was convinced I had the CAN L and H lines the right way around, they were reversed. Swapping them over fixed it for me – might be worth a shot πŸ™‚

  11. Giannis

    Thanks for replying Harry. I’ve already tried the swap, no result. On the shield when the cluster is connected the Rx light stays constantly on and in arduino’s serial monitor the can fails to initialize, so I’m starting to think that the shield is defective. πŸ™

  12. Harry Post author

    Only other thing I can think of is the termination of the CAN bus – there are resistors built in to the cluster, but it’s worth metering out both the adaptor and cluster ends just to make sure the term resistors are at sensible values…

  13. Noah

    I’m considering trying to hook an Acura TSX instrument cluster to my 1996 Acura NSX. I realize this doesnt just go together, but can you point me in the right direction on trying to start this project? – Thanks

  14. Harry Post author

    Hi Noah,
    I’m afraid I know the square-root of naff-all about the NSX, so take all of this with a pinch of salt πŸ™‚
    Working from first principles, do a like-for-like comparison. You’re working with the same vendor for starters so that’s usually a massive help. How close are the cars age-wise? The closer the better as manufacturers did tend to share DNA between their models, especially give or take a couple of calendar years (90s Toyotas especially are great for this!). If both vehicles have a CAN-driven instrument cluster, there is a possibility that it may “just work” – try plugging the cluster’s CAN wires into the OBDII socket on the NSX and see what lights up :-D.
    If the TSX is CAN-driven and the NSX on a legacy wires-only cluster, you’ve got your work cut out for you as you’ll need to digitise all of the analogue signals the car brings to the cluster, take the digitised data and encode them as CAN messages using some flavour of microcontroller, and then send them to the TSX cluster via a CAN bus controller.
    This is really generic information as I have no experience beyond this with the vehicles you’re working with. AFAIK the TSX is known over here as the Honda Accord: I think they were full CAN bus from around 2004-ish, but again that’s based on a few minutes rummaging around on the internet.
    Hope that helps!

  15. JamesB

    Hi Harry,

    have you had any success with the odometer reading yet? I’ve got everything sorted out, but the reading is not increasing, even though the speed indicator is working!

    Many thanks mate,

  16. Harry Post author

    Hi James,
    OK, I think the odo reading is in lockstep with the ECU somehow. Either there is a secondary “add a distance unit” PID that I haven’t decoded yet or there are bidirectional comms between the cluster and the ECU, allowing the ECU to send absolute values to the cluster for display without “clocking” the car. Either way I’ve not deciphered them yet, but I’ll post it here as soon as I do!

  17. Jeff

    Hey all, thought I might muddy the waters a bit on the odometer situation. When I was with Case IH, I did a lot of work diagnosing their precision farming and autoguidance stuff. Everything on their tractors was CAN-based. I recall something about a kind of “voting” procedure, in which each controller on the network would submit the values for a given parameter that it thought was correct. This was used a kind of error-checking/diagnostic system, as well as a tamper resistance “feature.” Not sure if that’s helpful, but it may at least start you on a previously-unconsidered path to the answer . . . .

    Harry, awesome job! Thanks for doing this. I can’t keep myself from “tweaking” my own car. As such, I just bought an RX8 cluster off eBay to try to patch into my car. This blog will go a long way to help me in my quest! If I might encourage you to keep tinkering, you’ll have my support! Thanks again!

  18. Jason

    Hello Harry,

    You mentioned you got the EPS working after sending speed and rpm to the CAN bus. I’ve just finished my swap and have got all the data going into the RX8 CAN system, but my EPS will not come alive. Was there anything you did other than send the speed and RPM?

    I know the RX8 has a steering angle sensor reset which I’ve tried a few times but I’m not sure if that will do anything with the PCM removed…


  19. Harry Post author

    Hi Jason,
    I replayed pretty much everything to get the dash to shut up about systems it no longer had, such as battery charge, oil pressure and so on. If I recall, it needed to see good oil pressure before the EPS ECU went out of “start” to “running” mode; if I find my original notes I’ll let you know what they say πŸ˜›

  20. Jason

    That would be incredibly appreciated. I am currently sending all the OK signals but the EPS light stays on and the system does not start. I’m even signalling the EPS warning off but the BCM is kicking it back on haha.

  21. Harry Post author

    Note to self: write better code comments!
    “EPS ECU is being a bastard. PCM sends something to wake it up, but can’t find it specifically. Spamming random data to 0x200 and 0x202 appears to do it, but haven’t figured exactly what sequence does what yet. Until then, shoutAtEPS() created in intialise routine to do this (//FIXME!) – takes way longer than it should, but does actually work.”
    That’s not very helpful – sorry, but it’s all I have for the moment…

  22. Jason

    haha okay, fair enough. Do you have a copy of the latest code you used with the random data? Maybe some bread crumbs might lead to some breakthrough haha.

  23. Jason

    That’s understandable. Thanks for the previous insight then. I will have to do a little bit of tweaking and playing now.

  24. XDX

    For mazda RX8 EV conversion CAN signals to be sent by ECU. Original ECU must be removed

    201 38 A8 FF FF 3A 2B C8 81 // 0,1 bytes RPM; 4 – Speed (26=0;3F=65; 4F=106; 5F=147; 6F=189)

    420 6B 23 C7 00 00 00 61 81 // 0 byte Temp (non linear) (5B-0%; 60-10%; 68-25%; 98=50%; 9E-75%; A4=100%) Fault codes: 01-ok; 00 error: 4 byte: Oil pressure, 5 Check engine, 6 battery charge

    215 02 2D 02 2D 02 2A 06 81 // Some ECU status

    231 0F 00 FF FF 02 2D 06 81 // Some ECU status

    240 04 00 28 00 02 37 06 81 // Some ECU status

    250 00 00 CF 87 7F 83 00 00 // Some ECU status

    200 00 00 FF FF 00 32 06 81 // EPS doesn’t work without this

    202 89 89 89 19 34 1F C8 FF // EPS doesn’t work without this

  25. Jeff


    I’m doing a Ls2 to Rx8 swap.

    Is there a way to get the engine to talk to the rx8, cluster, abs etc?

  26. Harry Post author

    That’s awesome, and cheers for sharing πŸ™‚ A couple of those fill in a blank or two here and there πŸ™‚

  27. Harry Post author

    The short answer is “yes”, the longer one adds “but you’ll need to translate or create CAN messages that other systems on the car expect to receive, and comprehend or respond to messages that other CAN systems broadcast”…

  28. Jon


    Thanks for all your work on this. I’m about to begin an engine swap on a 2006 RX8 which I recently acquired for the princely sum of Β£300 with a (very) blown engine. Prior to buying the car I had the plan of using two arduinos each with a canbus tranceiver and linked to each other via serial to re-transmit engine data from the new engine to the other components but thanks to the information I found here I plan to (hopefully) install canbus enabled megasquirt and generate as much of the data as possible direct from it.

    Clearly I’ve still got a lot of things to work out to get everything to behave – I’ll add anything new here if I work it out!

  29. S.

    What would you see if you hook up the logic analyzer to the tx pin of 2515 without connecting the dashboard? The thing is I get something not really expected from the stm board, which should act as the ECU for the dashboard. But I don’t have the dashboard.
    the setup is as following:
    stm32f4-tja1050(with termination R) =>CAN BUS <=mcp2551-mcp2515-mega8
    the side with mega is a receiver, the stm32 side is a transmitter.
    here's the image I get on the rx pin of mcp2515 of the receiver
    the wierd part is that I only get this when the receiver is set to listen-only mode. when the receiver is in the normal mode, I can see nothing, whereas in the listen-only mode i get 15 various bytes of data with CANID set to 0xff

  30. Joakim

    Hello. Is it possible to have the Arduino to transmit speed from a gps source? I have mounted a rx8 engine and cluster to a 1980 Mazda 626. And i’m not using the abs unit. Rpm, oil, water and that stuff works. But the speedometer is dead. I don’t care if the odometer works or not, as long as speed is ok. Thanks

  31. Harry Post author

    It’s possible, but I wouldn’t recommend it – there’s often quite a latency between GPS speed and actual road speed. Did the RX-8 ECU hook up OK to the gearbox speed sensor? Might be worth pulling the sensor from the RX-8 box and giving that a try…

  32. S.

    Looking for part II!
    Is there a chance to feed separate values from two different devices? Say, RPM from one device, speed and trip meter from another one?

  33. Harry Post author

    Is there a chance to feed separate values from two different devices? Say, RPM from one device, speed and trip meter from another one?

    Yes, absolutely – CANbus is indeed a bus, so any device can throw PIDs on to it. If your instrument cluster, display or whatever just passively listens for PIDs (which most do) then whatever broadcasts the PID for, say, speed has it displayed.

Leave a Reply

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