Technical Stilo B-CAN signals to Instrument Cluster

Currently reading:
Technical Stilo B-CAN signals to Instrument Cluster

esko

New member
Joined
May 13, 2015
Messages
12
Points
2
Hello!

I'm in the process of making a desktop clock out of a Stilo instrument cluster using the Arduino microcontroller. So the speedometer would show the hours (times ten) and tachometer the minutes.

I've done my research. Downloaded and studied eLearn, googled and read forum posts for days, experimented with the actual hardware.

I've successfully connected my micro to a Stilo instrument cluster, which i bought separately (I don't own a Stilo myself). I can send codes to it, light up the high beam indicator or move the fuel cage for example. But I'm unable to clear some error lights and messages, mainly about the airbags.

Therefore my question. Does anybody know which signals the Body Computer sends to the Instrument Panel on car startup, so the panel would know all systems are OK? Or maybe someone who owns a Stilo can record some B-CAN traffic for me to study?

Thank you in advance and also thanks to everybody whose previous postings on this forum and elsewhere have already helped me much. Yellowstilo among others.

I'm willing to share my results in case my project succeeds.

With Best Regards
Esko
Estonia
 
Unforunately now I seem to have bricked the instrument cluster...

I was trying to set the time using code 6D7 like discussed here:
/stilo/174029-stilo-can-bus-question.html#post1874159

I managed to set the time to 00:00 and the numbers became steady (instead of blinking). But as I tried with current time something went wrong. The LCD backlight went off, the cluster no more beeps on startup (but still lights up warning lights) and most importantly, communication over CAN between the cluster and the micro has stopped.

I'm guessing I might have accidentally used code 6E7 insead of 6D7 and messed up some settings really bad. Is there any way to reset the instrument cluster or clear it's memory? I have already tried keeping it unpowered for more than an hour, but this obviously only resets the time as the cluster has persistent memory.

There is of course the possibility of the cluster being broken, as I bought it for 10 cents in unknown condition. Either way it would be sad to see my project stall. But eventually I might step on another cluster at a reasonably price.
 
when you did not tamper with the wiring during your experiments you probably did not brick the unit by sending a wrong command, the cluster probably broke down by itself as this is rather common on Stilo clusters.
I can repair it for you but i guess it will be more economic to search for another instrument cluster.
 
i just double-checked , 6E7 would be the command to send the vehicle setup from the Connect Nav+ to the other CAN nodes so theoretically that might have corrupted your instrument cluster.(but random breakdown is still a plausible cause...)
 
Really interesting topic since I am fiddling things with Arduino too. I haven't had the chance to look into the CAN BUS info but will do very soon.
Keeping a close eye on this topic, and hopefully you will sort it out and why not post some pictures :D

All the best!
 
Update: I rechecked everything and things seem a bit more hopeful again.
CAN communication is back, must have been loose wiring.
LCD backlight is still off. But I managed to turn on the backlight for the gauges, which I was previously unable to (can give an explanation why if anyone interested). Actually, this situation suits my purposes very well, as the brightly lit LCD would have been a distraction anyway.
I removed both parts of the housing from the cluster and noticed that the beeping is still there, only very quiet. This is also more than fine with me. If, in the future I decide to add a alarm function to the clock by using the roger beep, I will just have to turn the volume up beforehand and down again afterwards.
Now to the worse part. Although I can send some signals again (for example bulb failure, city mode), the cluster seems to ignore others (for example directional lights indicator which I had previously used for confirming the operational state of the microprocessor).
I will check everything once again and post an update.
 
Nice to hear from a person with similar interests :)
I am only just beginning experimenting with the Arduino. In fact, this here is my first project.
I was planning on writing a summary at the end in case I succeed. Still, I can share information and take pictures earlier. Just specify please, what exactly would you be interested in. The pin-out, powering, connecting, messages, state of the display, etc.
By the way, I'm using this board for connecting:
http://www.ittgroup.ee/en/mikrokontrollerite-arendusplaadid/545-avr-tlcd-128can.html
It's compatible with Arduino Due and the CAN-bus shield from Seeed Studio, but is somewhat cheaper and much more compact than the combination of these. Disclaimer: I am proud to say this product has been developed and manufactured in my country, but I am in no way connected to the company that did it and i paid full retail price for the product.
 
Quick update: I've had some success. I can control the indicators for fog lights (but still neither directional lights nor high beams). And also set the fuel gage again. The trick here seems to be that you have to send it with the other data that uses the same code (not in a separate message).
Will post more when I figure things out more clearly.
 
Update: Some more good news. Managed to get the speedometer working using code 2A0.
Used a combination of posts and also some trial and error:

  • 13 bit integer like mentioned here: http://www.canhack.de/viewtopic.php?t=28#365
  • But 4 data-bytes in the message instead of 5 (removed the first one), like mentioned here: http://www.canhack.de/viewtopic.php?t=28#126
  • For some reason the correct factor for my cluster seems to be 0.10625, not 0,0625
Here's my test code, which increases the speed by 5 km/h once a second and falls back to zero at 220 where the scale on my speedometer ends. You may use it freely in any way :)

Code:
// demo: CAN-BUS Shield, send data
#include <mcp_can.h>
#include <SPI.h>

int iteration = 1;
int speed = 0;
union {
    short value;
    struct {
        unsigned short low : 8;
        unsigned short high : 5;
    } bytes;
} speedData;

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

void setup()
{
    Serial.begin(115200);

START_INIT:

    if(CAN_OK == CAN.begin(CAN_50KBPS))                   // init can bus : baudrate = 50k
    {
        Serial.println("CAN BUS Shield init ok!");
    }
    else
    {
        Serial.println("CAN BUS Shield init fail");
        Serial.println("Init CAN BUS Shield again");
        delay(100);
        goto START_INIT;
    }
}

void loop()
{
    if (iteration == 10) {
      if (speed == 220) {
        speed = 0;
      }
      else {
        speed += 5;
      }
      Serial.println(speed);
      speedData.value = speed / 0.10625;
      iteration = 1;
    }
    // send data:  id = 0x20a, standrad flame, data len = 4, stmp: data buf
    unsigned char stmp[4] = {speedData.bytes.high, speedData.bytes.low, 00, 00};
    CAN.sendMsgBuf(0x2a0, 0, 4, stmp);
    iteration++;
    delay(100);                       // send data per 100ms
}

/*********************************************************************************************************
  END FILE
*********************************************************************************************************/
Note: I'm sending data every 100 ms, because sometimes the speedometer stays where it last was even without new data, but other times goes back to zero after what i presume is 100 ms.
 
Update: Got the tachometer and the temperature gauge working. The trick here is again to send all the parameters in a single message, not separately. Took a example from the first line here: https://www.fiatforum.com/stilo/174029-stilo-can-bus-question.html?p=1874182
This also cleared some of the warning lights.
 
Quick update: I can now set the time. Was previously trying with decimal values, but actually needed hex.
 
Quick update: I can now set the time. Was previously trying with decimal values, but actually needed hex.

That is, the values must be written in hex so that they seem to be in decimal. In other words, they will be human readable without conversion.
 
Hello!
Nice to hear you managed to get the cluster working again!
Untill next week I am caught up with a big project, but after that I will get into this subject much deeper and start fiddling with it.
Keep up the good work!
 
Hello!
Nice to hear you managed to get the cluster working again!
Untill next week I am caught up with a big project, but after that I will get into this subject much deeper and start fiddling with it.
Keep up the good work!
Thanks for the support! Let us know of your accomplishments and any troubles.
 
I finished the project.

Here's the full code. As before, you can freely use it for any purpose.
Code:
#include <mcp_can.h>
#include <SPI.h>

#define INSTRUMENT_LIGHTING_ON 0x08

#define MEAN_WATER_TEMPERATURE 130
#define WATER_TEMPERATURE_DELTA 20

#define ENGINE_SPEED_FACTOR 32
#define VEHICLE_SPEED_FACTOR 0.10625

#define SEND_INTERVAL 1000

#define HOURS_BUTTON 3 // #2 is taken by CAN-BUS shield
#define MINUTES_BUTTON 4

struct {
    struct {
        int hours;
        int minutes;
        int seconds;
        int day;
        int month;
        int year;
    } timeData;
} dataIn;

struct {
    int fuelLevel;
    int rpm;
    union {
        short value;
        struct {
            unsigned short low : 8;
            unsigned short high : 5;
        } bytes;
    } speedData;
    int waterTemperature;
} dataOut;

unsigned long previousSendTime;
int previousMinutes;
int waterTemperatureDelta = WATER_TEMPERATURE_DELTA;

int hoursButtonState = HIGH;
int hoursButtonLastState = HIGH;

int minutesButtonState = HIGH;
int minutesButtonLastState = HIGH;

void sendData(int id, int len, ...) {
    va_list args;
    va_start(args, len);
    unsigned char data[len];
    for (int i = 0; i < len; i++) {
        data[i] = va_arg(args, int);
    }
    va_end(args);
    CAN.sendMsgBuf(id, 0, len, data);
}

int fromPseudoHex(int val) {
    return String(val, HEX).toInt();
}

int toPseudoHex(int val) {
    return strtoul(&String(val)[0], 0, 16);
}

MCP_CAN CAN(10);

void setup() {
    Serial.begin(115200);

START_INIT:

    if (CAN_OK == CAN.begin(CAN_50KBPS)) {
        Serial.println("CAN BUS Shield init ok!");
    }
    else {
        Serial.println("CAN BUS Shield init fail");
        Serial.println("Init CAN BUS Shield again");
        delay(100);
        goto START_INIT;
    }
    
    pinMode(HOURS_BUTTON, INPUT);
    digitalWrite(HOURS_BUTTON, HIGH); // inverted logic in order to use internal pull-up resistors
    
    pinMode(MINUTES_BUTTON, INPUT);
    digitalWrite(MINUTES_BUTTON, HIGH);
}

void loop() {
    unsigned long elapsedTime = millis() - previousSendTime;
    
    hoursButtonState = digitalRead(HOURS_BUTTON);
    minutesButtonState = digitalRead(MINUTES_BUTTON);
    
    unsigned char hoursButtonPressed = (LOW == hoursButtonState && hoursButtonLastState != hoursButtonState);
    unsigned char minutesButtonPressed = (LOW == minutesButtonState && minutesButtonLastState != minutesButtonState);
    
    if (hoursButtonPressed || minutesButtonPressed) {
        if (hoursButtonPressed) {
            dataIn.timeData.hours++;
            if (23 < dataIn.timeData.hours) {
                dataIn.timeData.hours = 0;
            }
        }

        if (minutesButtonPressed) {
            dataIn.timeData.minutes++;
            if (59 < dataIn.timeData.minutes) {
                dataIn.timeData.minutes = 0;
            }
        }
        
        sendData(0x6d7, 6,
            toPseudoHex(dataIn.timeData.hours),
            toPseudoHex(dataIn.timeData.minutes),
            0x01, 0x01, 0x20, 0x01 // 01.01.2001
        );
    }
    hoursButtonLastState = hoursButtonState;
    minutesButtonLastState = minutesButtonState;
    
    if (CAN_MSGAVAIL == CAN.checkReceive()) {
        int id = CAN.getCanId();
        unsigned char len;
        unsigned char data[9];
        CAN.readMsgBuf(&len, data);

        switch (id) {
            case 0x3c3: {
                switch (len) {
                    case 6: {
//                        Serial.println("receiving data");
                        dataIn.timeData.hours = fromPseudoHex(data[0]);
                        dataIn.timeData.minutes = fromPseudoHex(data[1]);
                        dataIn.timeData.day = fromPseudoHex(data[2]);
                        dataIn.timeData.month = fromPseudoHex(data[3]);
                        dataIn.timeData.year = 1000 * fromPseudoHex(data[4]) + fromPseudoHex(data[5]);
                    }
                }
            }
        }
    }
    
    if (SEND_INTERVAL > elapsedTime) {
        return;
    }
//    Serial.println("sending data");
    
    waterTemperatureDelta *= -1;
    
    if (dataIn.timeData.minutes != previousMinutes) {
        dataIn.timeData.seconds = 0;
    }
    else {
        dataIn.timeData.seconds++;
    }
                        
    dataOut.fuelLevel = 100 * (60 - dataIn.timeData.seconds) / 60;
    dataOut.rpm = 100 * dataIn.timeData.minutes / ENGINE_SPEED_FACTOR;
    dataOut.speedData.value = 10 * (dataIn.timeData.hours + (float)dataIn.timeData.minutes / 60) / VEHICLE_SPEED_FACTOR;
    dataOut.waterTemperature = MEAN_WATER_TEMPERATURE + waterTemperatureDelta;

//    sendData(0x6e7, 5, 0x92, 0x32, 0x05, 0x50, 0x03); // settings
//    sendData(0x6e7, 5, 0x00, 0x00, 0x00, 0x00, 0x00); // settings

    sendData(0x180, 6,
        00, 00, 00, 00, 00, 00
    );

    sendData(0x281, 8,
        00, 00, 00, dataOut.waterTemperature, 00, 00, dataOut.rpm, 00
    );

/*
    sendData(0x286, 8,
        00, 00, dataOut.speedData.bytes.high, dataOut.speedData.bytes.low, 00, 00, 00, 00
    );
*/

    sendData(0x2a0, 4,
        dataOut.speedData.bytes.high, dataOut.speedData.bytes.low, 00, 00
    );
    
    sendData(0x380, 8,
        INSTRUMENT_LIGHTING_ON, 00, 00, 00, 00, dataOut.fuelLevel, 00, 00
    );
    
    previousSendTime = millis();
    previousMinutes = dataIn.timeData.minutes;
}
And here's the video of the clock in action. You can faintly hear the ticking ;-)
[ame]http://youtu.be/yxl7wD1D-C0[/ame]

I donated the clock to a local car museum, so if you happen to Estonia and would like to see it in real life, you may pay them a visit :)
http://automuuseum.ee/en/
 
Awesome, now I have a starting point!
And very nice of you for donating it!
 
How original and inventive. Wish I was this creative!
Thank!
Also, being creative is not the only way to achieve great results. For example, you could recreate someones previous project with a better finish or more features. Or even mix several ideas from different sources into something unique.
 
Hi guys, can you help me? I own Fiat Grande Punto and using arduino uno with CAN-Bus shield connected to B-CAN to do some stuff like obtaining CAN messages with pressed button on steering wheel and sending IR signal to my LG card audio which has not CAN BUS connection. The other stuff is obtaining rpm value and depending on its value to display programmed value on my LED strip. It's working now, but I want to implement another stuff like displaying my custom text on dashboard screen. I have found one guy message on canhack.de - which had mentioned 2 CAN message IDs. Unfortunately I cannot paste here URL for some reasons, so I will post here this guy's text:

Hello,
Sorry for the english but i don't know the german language.
Does anyone have logs of the B-Can from a grande punto or even bravo with blue & me? I am exploring the dashboard screen and since my car does not have blue & me i don't have data about how this system writes on the screen.
Now i can only write "pretending" that the data is rds information coming from the radio.. I use these ids: 0A114005: XX XX XX XX XX XX where the first byte is the source of the radio (Radio fm, Radio am, Cd, mp3, etc...), next bytes in asosiation with the first contain information about the source that is playing (track nubmer, pause, etc..). Next id i use is 0A194005:XX XX XX XX XX XX XX. Six first bytes contain the rds text string and are the same as in stilo, seventh byte enables or disables the text string... if it is 80 no string shows on screen, if 0 string is displayed.
Also any other information about ids and data of the canbus of Grande punto would be great


Also he mentioned that structure of messages is similar to Stilo, I think this guy kept in mind another topic from canhack.de connected to Stilo CAN messages sctructure

I have tried to send CAN message and got "NO CD" text at first and then when tried another variant got "Searching". My question is - have you played with custom text on dash screen? Can you explain the format of messages?
 
Hi there!
I'm working on an abarth cluster, to get it work with JTD engine. With your code I get an error but I couldn't find out what is the problem. Please could you help me?

131N_vtelen.png
 
Last edited:
Back
Top