forum.arduino.cc Open in urlscan Pro
2001:470:1:9a5::141  Public Scan

URL: https://forum.arduino.cc/t/controlling-bmw-e90-instrument-cluster/670728
Submission: On March 03 via api from DE — Scanned from DE

Form analysis 1 forms found in the DOM

POST /login

<form id="hidden-login-form" method="post" action="/login" style="display: none;">
  <input name="username" type="text" id="signin_username">
  <input name="password" type="password" id="signin_password">
  <input name="redirect" type="hidden">
  <input type="submit" id="signin-button" value="Anmelden">
</form>

Text Content

Registrieren Anmelden


CONTROLLING BMW E90 INSTRUMENT CLUSTER

Using Arduino Project Guidance

Terraviper-5 18. August 2020 um 19:11 #1

Hello!

I want to put a BMW E90 instrument cluster into a car that only has digital
display. So I bought one off ebay thinking it would be a fairly straightforward
job. To my mistake, most of people who did this years ago have posted links that
are dead now and they themselves are not available any longer.



1319×400 197 KB



I found the following resources

 * a blog with start CAN message
 * a wiring diagram
 * a forum thread where someone applied power to it (and another)
 * a list of sniffed CAN messages

Several YT videos






I bought a Seeed Can Bus Shield V2.0 and connected it to my Arduino Uno:



and connected CAN-HI pin to supposed CAN-HI pin on the cluster and CAN-LO pin to
CAN-LO of the cluster. I also connected 12V adapter to the cluster (+ to +, - to
-)



490×700 128 KB



the cluster does power on by wiggling the needles a bit and if I press the
button on it, display turns on for about 15 seconds



723×400 62.7 KB



but when I try to use the suggested turn-on CAN message, nothing happens. I
tried both 500KBPS and 100KBPS, but still nothing. This is the code I used:

#include <mcp_can.h>
#include <SPI.h>

/*SAMD core*/
#ifdef ARDUINO_SAMD_VARIANT_COMPLIANCE
#define SERIAL SerialUSB
#else
#define SERIAL Serial
#endif

const int SPI_CS_PIN = 9;

MCP_CAN CAN(SPI_CS_PIN); // Set CS pin

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

    while (CAN_OK != CAN.begin(CAN_100KBPS))
    {
        SERIAL.println("CAN BUS Shield init fail");
        SERIAL.println(" Init CAN BUS Shield again");
        delay(100);
    }
    SERIAL.println("CAN BUS Shield init ok!");
}

byte data[8] = {0, 0, 0, 0, 0, 0, 0, 0};

void loop()
{
    data[0] = 0x45; //0x45;  /Key Status
    data[1] = 0x42; // 0x40;  //Transponder Detected
    data[2] = 0x69; // 0x21;  //Terminal Status
    data[3] = 0x8F; // Steering lock?
    data[4] = 0xE2; //Counter and Checksum

    CAN.sendMsgBuf(0x130, 0, 5, data);
    delay(100); // send data per 100ms
}


It is a direct combination of Seeed’s example and start code from that blog,
where I put in the wake-up message from that guy’s blog, listed above. I checked
the output of CAN shield with an oscilloscope and can confirm that it does look
like something is being sent. Also, Arduino Uno sends me this message via serial

Enter setting mode success 
set rate success!!
Enter Normal Mode Success!!
CAN BUS Shield init ok!


I also tried the read example to see if the cluster sends any messages but I got
nothing back. Im a bit puzzled. Does anybody have any suggestion please? Thank
you!



BMW E90 CAN bus Instrument Cluster

Terraviper-5 12. Dezember 2020 um 17:26 #2

In the time elapsed I have made some progress. Initially I didnt connect the
ground wire to arduino, thats why it didnt work. Here is correct pinout:

1     o o     10
2     o o     11
3     o o     12
4     o o     13
5     o o     14
6 C_H o o     15
7 C_L o o     16
8     o o     17
9 VCC o o GND 18

(Dont forget to connect GND to Arduino!)


I managed to turn the cluster on, turn on the backlights and move the rpm
needle. But I still cant do it consistently and everything in the same program.
I read that cluster is picky about how messages and which messages come and at
what intervals. I try reordering the message sends a bit, putting in delays and
sometimes I manage to move the rpm needle, sometimes the lights turn on, but
cant make it consistently useful. There is information that wake signal should
be sent every 100ms but I cannot make it work even if I send it every 100ms. It
even happened that I put into program message for turning rpm needle, then I
reupload without this message and the rpm needle moves. Maybe there is something
about how Seeed CAN Shield sends messages (buffers etc).

I tested turning blinkers on by sending the command once in setup, but the
cluster was acting as if it was spammed by that same command and showed CAN bus
errors. Im starting to suspect there is something up with my CAN bus shield

If anybody could shed any light onto this I would be very grateful!

Here is the code:

#include <SPI.h>
#include "mcp2515_can.h"

#define lo8(x) (uint8_t)((x)&0xff)
#define hi8(x) (uint8_t)(((x) >> 8) & 0xff)

const int SPI_CS_PIN = 9;
const int CAN_INT_PIN = 2;
mcp2515_can CAN(SPI_CS_PIN); // Set CS pin

void sendIgnitionKeyOn()
{
    uint16_t canId = 0x130;
    uint8_t len = 5;

    uint8_t buf[8] = {0, 0, 0, 0, 0, 0, 0, 0};

    buf[0] = 0x45; // Key Status / T15 ON message
    buf[1] = 0x40; // Transponder Detected
    buf[2] = 0x21; // Terminal Status
    buf[3] = 0x8F; // Steering lock?
    buf[4] = 0xFE; // Counter and Checksum

    CAN.sendMsgBuf(canId, 0, len, buf);
}

void sendRPM(uint16_t rpm)
{
    uint16_t tempRpm = rpm * 4;

    const uint16_t canId = 0x0AA;
    const uint8_t len = 8;

    uint8_t buf[8] = {0xFE, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0xFE, 0x99};

    buf[4] = lo8(tempRpm);
    buf[5] = hi8(tempRpm);

    CAN.sendMsgBuf(canId, 0, len, buf);
}

void sendLightsOn()
{
    const uint16_t canId = 0x21A;
    const uint8_t len = 3;

    uint8_t buf[8] = {0b00000101, 0b00010000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

    CAN.sendMsgBuf(canId, 0, len, buf);
}

void leftBlinkerOn()
{
    const uint16_t canId = 0x1F6;
    const uint8_t len = 2;

    uint8_t buf[8] = {0x91, 0xF2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

    CAN.sendMsgBuf(canId, 0, len, buf);
}

void rightBlinkerOn()
{
    const uint16_t canId = 0x1F6;
    const uint8_t len = 2;

    uint8_t buf[8] = {0xA1, 0xF2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

    CAN.sendMsgBuf(canId, 0, len, buf);
}

void sendFuelLevel(uint16_t litres)
{
    uint16_t canId = 0x349;
    const uint8_t len = 5;

    uint8_t buf[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

    uint16_t sensor1 = litres * 160;
    buf[0] = lo8(sensor1);
    buf[1] = hi8(sensor1);

    uint16_t sensor2 = sensor1;
    buf[2] = lo8(sensor2);
    buf[3] = hi8(sensor2);

    CAN.sendMsgBuf(canId, 0, len, buf);
}

void setup()
{
    while (CAN_OK != CAN.begin(CAN_100KBPS))
    {
        delay(100);
    }

    sendIgnitionKeyOn();
    sendFuelLevel(24);
    sendLightsOn();
    sendRPM(800);
}


List of can commands: CarPC Install




xadonxander 12. Dezember 2020 um 21:37 #3

You should be sending the can bus messages in a loop not in the setup. They are
required to constantly receive the messages. I believe ignition on should be
received about every 100ms and turn signals should be about 800ms.




Terraviper-5 12. Dezember 2020 um 22:28 #4

> xadonxander:
> You should be sending the can bus messages in a loop not in the setup. They
> are required to constantly receive the messages. I believe ignition on should
> be received about every 100ms and turn signals should be about 800ms.

Hello sir!

I’ve tried putting messages into loop but it doesn’t seem to work for me. Maybe
the 0x130 ignition signal should have its counter increased, as it says here:
CAN BUS Codes

Byte 4

xx = 1.4 Second counter

I tried doing this (incrementing those bits every 1400ms) but the cluster then
keeps resetting

For blinkers I did put it in loop:

#include <SPI.h>
#include "mcp2515_can.h"

#define lo8(x) (uint8_t)((x)&0xff)
#define hi8(x) (uint8_t)(((x) >> 8) & 0xff)

const int SPI_CS_PIN = 9;
const int CAN_INT_PIN = 2;
mcp2515_can CAN(SPI_CS_PIN); // Set CS pin

void sendIgnitionKeyOn()
{
    uint16_t canId = 0x130;
    uint8_t len = 5;

    uint8_t buf[8] = {0, 0, 0, 0, 0, 0, 0, 0};

    buf[0] = 0x45; // Key Status / T15 ON message
    buf[1] = 0x40; // Transponder Detected
    buf[2] = 0x21; // Terminal Status
    buf[3] = 0x8F; // Steering lock?
    buf[4] = 0xFE; // Counter and Checksum

    CAN.sendMsgBuf(canId, 0, len, buf);
}

void sendRPM(uint16_t rpm)
{
    uint16_t tempRpm = rpm * 4;

    const uint16_t canId = 0x0AA;
    const uint8_t len = 8;

    uint8_t buf[8] = {0xFE, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0xFE, 0x99};

    buf[4] = lo8(tempRpm);
    buf[5] = hi8(tempRpm);

    CAN.sendMsgBuf(canId, 0, len, buf);
}

void sendLightsOn()
{
    const uint16_t canId = 0x21A;
    const uint8_t len = 3;

    uint8_t buf[8] = {0b00000101, 0b00010000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

    CAN.sendMsgBuf(canId, 0, len, buf);
}

void leftBlinkerOnInitial()
{
    const uint16_t canId = 0x1F6;
    const uint8_t len = 2;

    uint8_t buf[8] = {0x91, 0xF2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

    CAN.sendMsgBuf(canId, 0, len, buf);
}

void rightBlinkerOnInitial()
{
    const uint16_t canId = 0x1F6;
    const uint8_t len = 2;

    uint8_t buf[8] = {0xA1, 0xF2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

    CAN.sendMsgBuf(canId, 0, len, buf);
}

void keepLeftBlinkerOn()
{
    const uint16_t canId = 0x1F6;
    const uint8_t len = 2;

    uint8_t buf[8] = {0x91, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

    CAN.sendMsgBuf(canId, 0, len, buf);
}

void keepRightBlinkerOn()
{
    const uint16_t canId = 0x1F6;
    const uint8_t len = 2;

    uint8_t buf[8] = {0xA1, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

    CAN.sendMsgBuf(canId, 0, len, buf);
}

void sendFuelLevel(uint16_t litres)
{
    uint16_t canId = 0x349;
    const uint8_t len = 5;

    uint8_t buf[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

    uint16_t sensor1 = litres * 160;
    buf[0] = lo8(sensor1);
    buf[1] = hi8(sensor1);

    uint16_t sensor2 = sensor1;
    buf[2] = lo8(sensor2);
    buf[3] = hi8(sensor2);

    CAN.sendMsgBuf(canId, 0, len, buf);
}

uint32_t timestamp100ms = 0;
uint32_t timestamp800ms = 0;
bool firstBlinkerTurnOn = true;

void setup()
{
    while (CAN_OK != CAN.begin(CAN_100KBPS))
    {
        delay(100);
    }
}

void loop()
{
    if (millis() - timestamp100ms > 99)
    {
        sendIgnitionKeyOn();

        timestamp100ms = millis();
    }

    if (millis() - timestamp800ms > 799)
    {
        // Turn blinker on after 30 seconds to avoid kombi
        // missing the initial message when its turning on
        if (millis() > 30000)
        {
            if (firstBlinkerTurnOn == true)
            {
                leftBlinkerOnInitial();

                firstBlinkerTurnOn = false;
            }

            keepLeftBlinkerOn();
        }

        timestamp800ms = millis();
    }
}


and the kombi does turn on after a few seconds, warning lights flash, but then
turn off after about 2 seconds. The screen stays on but nothing else happens (if
I understood correctly on how to use them: CAN BUS Codes)

1F6 2 91 F1 145 241
Left turn signal on (sent following initial 242)
1F6 2 91 F2 145 242
Left turn signal on (sent first, followed by 241)

Im really at a loss I was so happy when they turned on but then I hit a brick
wall




Terraviper-5 13. Dezember 2020 um 20:51 #5

Okay I have found this Arduino forum thread
https://forum.arduino.cc/index.php?topic=569052.0 and basically it sounds
exactly whats happening to me. I didn’t try with the scope, but symptoms sound
similar. So I tried this guy’s solution and switched to this lib he is talking
about. I googled that SPI bandwidth of mcp2515 is 1Mbps, so I adjusted
accordingly. And now I’m at the same spot as this guy: E90 Can bus project (E60,
E65, E87....) - Page 2 The kombi is going through reset sequence all the time
like its missing something

How it looks like: http://shrani.si/f/4/GQ/1TTxeB2f/1/vid20201213212805.gif

Code

#include <CAN.h>

#define lo8(x) (uint8_t)((x)&0xff)
#define hi8(x) (uint8_t)(((x) >> 8) & 0xff)

const uint8_t CS_PIN = 9;
const uint8_t IRQ_PIN = 2;

void sendIgnitionKeyOn()
{
  CAN.beginPacket(0x130);

  CAN.write(0x45);
  CAN.write(0x40);
  CAN.write(0x21);
  CAN.write(0x8F);
  CAN.write(0xFE);

  CAN.endPacket();
}

void sendRPM(uint16_t rpm)
{
  uint16_t tempRpm = rpm * 4;

  CAN.beginPacket(0x0AA);

  CAN.write(0xFE);
  CAN.write(0xFE);
  CAN.write(0xFF);
  CAN.write(0x00);
  CAN.write(lo8(tempRpm));
  CAN.write(hi8(tempRpm));
  CAN.write(0xFE);
  CAN.write(0x99);

  CAN.endPacket();
}

void sendIgnitionStatus()
{
  CAN.beginPacket(0x26E);

  CAN.write(0x40);
  CAN.write(0x40);
  CAN.write(0x7F);
  CAN.write(0x50);
  CAN.write(0xFF);
  CAN.write(0xFF);
  CAN.write(0xFF);
  CAN.write(0xFF);

  CAN.endPacket();
}

void sendFuelLevel(uint16_t litres)
{
  uint16_t sensor = litres * 160;

  CAN.beginPacket(0x349);

  CAN.write(lo8(sensor));
  CAN.write(hi8(sensor));
  CAN.write(lo8(sensor));
  CAN.write(hi8(sensor));
  CAN.write(0x00);

  CAN.endPacket();
}

void sendAirbagSeatbeltCounter()
{
  static uint8_t count = 0x00;

  CAN.beginPacket(0x0D7);

  CAN.write(count);
  CAN.write(0xFF);

  CAN.endPacket();

  count++;
}

void sendABSBrakeCounter2()
{
  CAN.beginPacket(0x19E);

  CAN.write(0x00);
  CAN.write(0xE0);
  CAN.write(0xB3);
  CAN.write(0xFC);
  CAN.write(0xF0);
  CAN.write(0x43);
  CAN.write(0x00);
  CAN.write(0x65);

  CAN.endPacket();
}

void sendABSBrakeCounter1()
{
  static uint8_t count = 0xF0;

  CAN.beginPacket(0x0C0);

  CAN.write(count);
  CAN.write(0xFF);

  CAN.endPacket();

  count++;
  if (count == 0x00)
  {
    count = 0xF0;
  }
}

void seatbeltLight(bool state)
{
  uint8_t thirdBit;

  if (state == false)
  {
    CAN.beginPacket(0x581);
    thirdBit = 0x28;
  }
  else
  {
    CAN.beginPacket(0x394);
    thirdBit = 0x029;
  }

  CAN.write(0x40);
  CAN.write(0x4D);
  CAN.write(0x00);
  CAN.write(thirdBit);
  CAN.write(0xFF);
  CAN.write(0xFF);
  CAN.write(0xFF);
  CAN.write(0xFF);

  CAN.endPacket();
}

void sendSpeed(uint16_t speed)
{
  static uint32_t lastTimeSent = 0;
  static uint16_t lastReading = 0;
  static uint16_t count = 0xF000;

  uint16_t speedValToSend = ((millis() - lastTimeSent) / 50) * speed / 2;
  speedValToSend += lastReading;

  lastReading = speedValToSend;
  lastTimeSent = millis();

  CAN.beginPacket(0x1A6);

  CAN.write(lo8(speedValToSend));
  CAN.write(hi8(speedValToSend));
  CAN.write(lo8(speedValToSend));
  CAN.write(hi8(speedValToSend));
  CAN.write(lo8(speedValToSend));
  CAN.write(hi8(speedValToSend));
  CAN.write(lo8(count));
  CAN.write(hi8(count));

  CAN.endPacket();
}

void sendLightsOff()
{
  CAN.beginPacket(0x21A);

  CAN.write(0b00000000);
  CAN.write(0b00000000);
  CAN.write(0x00);

  CAN.endPacket();
}

uint32_t timestamp100ms = 0;
uint32_t timestamp200ms = 0;

void setup()
{
  Serial.begin(115200);
  while (!Serial)
  {
  };

  CAN.setPins(CS_PIN, IRQ_PIN);
  CAN.setSPIFrequency(1E6);

  while (!CAN.begin(100E3))
  {
    Serial.println("CAN BUS Shield init fail");
    Serial.println(" Init CAN BUS Shield again");
    delay(100);
  }
  Serial.println("CAN BUS Shield init ok!");

  timestamp100ms = millis();
  timestamp200ms = millis();
}

void loop()
{
  if (millis() - timestamp100ms > 99)
  {
    sendIgnitionKeyOn();
    sendRPM(800);
    sendSpeed(0);

    timestamp100ms = millis();
  }

  if (millis() - timestamp200ms > 199)
  {
    sendFuelLevel(24);
    sendIgnitionStatus();
    sendAirbagSeatbeltCounter();
    sendABSBrakeCounter2();
    sendABSBrakeCounter1();
    seatbeltLight(false);
    sendLightsOff();

    timestamp200ms = millis();
  }
}





Terraviper-5 15. Dezember 2020 um 22:50 #6

Found out what problem was under this video

It was the termination resistor (trace marked P1) on Seeed CAN bus shield that
was disrupting communication. When I cut the trace everything worked

More info about E90 cluster control: gitHub link




system geschlossen, 5. Mai 2021 um 19:18 #7



Startseite Kategorien FAQ/Richtlinien Nutzungsbedingungen Datenschutzerklärung

Angetrieben von Discourse, beste Erfahrung mit aktiviertem JavaScript

Zum Hauptinhalt springen
 * Arduino.cc
 * Professional
 * Education
 * Store


IoT Cloud
Web Editor
Manager for Linux
Anmelden


 * Categories
 * Latest
 * About
 * FAQ

RegistrierenAnmelden
 * 
 * 

Custom dashboards, smartphone remote control, data sharing between boards,
remote uploads. Get them (for free) using your forum account!


CONTROLLING BMW E90 INSTRUMENT CLUSTER

Using ArduinoProject Guidance


Du hast 0 Beiträge ausgewählt.

alle auswählen

Auswahlvorgang abbrechen

Aug. 2020
1/7
Aug. 2020

Mai 2021

Terraviper-5
1
Aug. '20


Hello!

I want to put a BMW E90 instrument cluster into a car that only has digital
display. So I bought one off ebay thinking it would be a fairly straightforward
job. To my mistake, most of people who did this years ago have posted links that
are dead now and they themselves are not available any longer.



1319×400 197 KB



I found the following resources

 * a blog 62 with start CAN message
 * a wiring diagram 98
 * a forum thread 39 where someone applied power to it (and another 14)
 * a list of 82 sniffed CAN messages

Several YT videos

E90 cluster being driven by Can bus from an Arduino
BMW E90 KOMBI bench setup. No error lights. No needle skip.
E90 Test Bench LS3
BMW E90 instrument cluster powered on the bench /zalaczenie zegarow

I bought a Seeed Can Bus Shield V2.0 and connected it to my Arduino Uno:



and connected CAN-HI pin to supposed CAN-HI pin on the cluster and CAN-LO pin to
CAN-LO of the cluster. I also connected 12V adapter to the cluster (+ to +, - to
-)



490×700 128 KB



the cluster does power on by wiggling the needles a bit and if I press the
button on it, display turns on for about 15 seconds



723×400 62.7 KB



but when I try to use the suggested turn-on CAN message, nothing happens. I
tried both 500KBPS and 100KBPS, but still nothing. This is the code I used:

#include <mcp_can.h>
#include <SPI.h>

/*SAMD core*/
#ifdef ARDUINO_SAMD_VARIANT_COMPLIANCE
#define SERIAL SerialUSB
#else
#define SERIAL Serial
#endif

const int SPI_CS_PIN = 9;

MCP_CAN CAN(SPI_CS_PIN); // Set CS pin

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

    while (CAN_OK != CAN.begin(CAN_100KBPS))
    {
        SERIAL.println("CAN BUS Shield init fail");
        SERIAL.println(" Init CAN BUS Shield again");
        delay(100);
    }
    SERIAL.println("CAN BUS Shield init ok!");
}

byte data[8] = {0, 0, 0, 0, 0, 0, 0, 0};

void loop()
{
    data[0] = 0x45; //0x45;  /Key Status
    data[1] = 0x42; // 0x40;  //Transponder Detected
    data[2] = 0x69; // 0x21;  //Terminal Status
    data[3] = 0x8F; // Steering lock?
    data[4] = 0xE2; //Counter and Checksum

    CAN.sendMsgBuf(0x130, 0, 5, data);
    delay(100); // send data per 100ms
}


It is a direct combination of Seeed’s example and start code from that blog,
where I put in the wake-up message from that guy’s blog, listed above. I checked
the output of CAN shield with an oscilloscope and can confirm that it does look
like something is being sent. Also, Arduino Uno sends me this message via serial

Enter setting mode success 
set rate success!!
Enter Normal Mode Success!!
CAN BUS Shield init ok!


I also tried the read example to see if the cluster sends any messages but I got
nothing back. Im a bit puzzled. Does anybody have any suggestion please? Thank
you!




 * BMW E90 CAN bus Instrument Cluster5

 * ERSTELLT
   
   Aug. '20

 * LETZTE ANTW.
   
   Mai '21
 * 6
   
   ANTWORTEN

 * 4,4 T.
   
   AUFRUFE

 * 2
   
   BENUTZER

 * 17
   
   LINKS

 * 5
   


4 Monate später
Terraviper-5
Dez. '20


In the time elapsed I have made some progress. Initially I didnt connect the
ground wire to arduino, thats why it didnt work. Here is correct pinout:

1     o o     10
2     o o     11
3     o o     12
4     o o     13
5     o o     14
6 C_H o o     15
7 C_L o o     16
8     o o     17
9 VCC o o GND 18

(Dont forget to connect GND to Arduino!)


I managed to turn the cluster on, turn on the backlights and move the rpm
needle. But I still cant do it consistently and everything in the same program.
I read that cluster is picky about how messages and which messages come and at
what intervals. I try reordering the message sends a bit, putting in delays and
sometimes I manage to move the rpm needle, sometimes the lights turn on, but
cant make it consistently useful. There is information that wake signal should
be sent every 100ms but I cannot make it work even if I send it every 100ms. It
even happened that I put into program message for turning rpm needle, then I
reupload without this message and the rpm needle moves. Maybe there is something
about how Seeed CAN Shield sends messages (buffers etc).

I tested turning blinkers on by sending the command once in setup, but the
cluster was acting as if it was spammed by that same command and showed CAN bus
errors. Im starting to suspect there is something up with my CAN bus shield

If anybody could shed any light onto this I would be very grateful!

Here is the code:

#include <SPI.h>
#include "mcp2515_can.h"

#define lo8(x) (uint8_t)((x)&0xff)
#define hi8(x) (uint8_t)(((x) >> 8) & 0xff)

const int SPI_CS_PIN = 9;
const int CAN_INT_PIN = 2;
mcp2515_can CAN(SPI_CS_PIN); // Set CS pin

void sendIgnitionKeyOn()
{
    uint16_t canId = 0x130;
    uint8_t len = 5;

    uint8_t buf[8] = {0, 0, 0, 0, 0, 0, 0, 0};

    buf[0] = 0x45; // Key Status / T15 ON message
    buf[1] = 0x40; // Transponder Detected
    buf[2] = 0x21; // Terminal Status
    buf[3] = 0x8F; // Steering lock?
    buf[4] = 0xFE; // Counter and Checksum

    CAN.sendMsgBuf(canId, 0, len, buf);
}

void sendRPM(uint16_t rpm)
{
    uint16_t tempRpm = rpm * 4;

    const uint16_t canId = 0x0AA;
    const uint8_t len = 8;

    uint8_t buf[8] = {0xFE, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0xFE, 0x99};

    buf[4] = lo8(tempRpm);
    buf[5] = hi8(tempRpm);

    CAN.sendMsgBuf(canId, 0, len, buf);
}

void sendLightsOn()
{
    const uint16_t canId = 0x21A;
    const uint8_t len = 3;

    uint8_t buf[8] = {0b00000101, 0b00010000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

    CAN.sendMsgBuf(canId, 0, len, buf);
}

void leftBlinkerOn()
{
    const uint16_t canId = 0x1F6;
    const uint8_t len = 2;

    uint8_t buf[8] = {0x91, 0xF2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

    CAN.sendMsgBuf(canId, 0, len, buf);
}

void rightBlinkerOn()
{
    const uint16_t canId = 0x1F6;
    const uint8_t len = 2;

    uint8_t buf[8] = {0xA1, 0xF2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

    CAN.sendMsgBuf(canId, 0, len, buf);
}

void sendFuelLevel(uint16_t litres)
{
    uint16_t canId = 0x349;
    const uint8_t len = 5;

    uint8_t buf[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

    uint16_t sensor1 = litres * 160;
    buf[0] = lo8(sensor1);
    buf[1] = hi8(sensor1);

    uint16_t sensor2 = sensor1;
    buf[2] = lo8(sensor2);
    buf[3] = hi8(sensor2);

    CAN.sendMsgBuf(canId, 0, len, buf);
}

void setup()
{
    while (CAN_OK != CAN.begin(CAN_100KBPS))
    {
        delay(100);
    }

    sendIgnitionKeyOn();
    sendFuelLevel(24);
    sendLightsOn();
    sendRPM(800);
}


List of can commands: CarPC Install 34





xadonxander
Dez. '20


You should be sending the can bus messages in a loop not in the setup. They are
required to constantly receive the messages. I believe ignition on should be
received about every 100ms and turn signals should be about 800ms.





Terraviper-5
Dez. '20


> xadonxander:
> You should be sending the can bus messages in a loop not in the setup. They
> are required to constantly receive the messages. I believe ignition on should
> be received about every 100ms and turn signals should be about 800ms.

Hello sir!

I’ve tried putting messages into loop but it doesn’t seem to work for me. Maybe
the 0x130 ignition signal should have its counter increased, as it says here:
CAN BUS Codes 32

Byte 4

xx = 1.4 Second counter

I tried doing this (incrementing those bits every 1400ms) but the cluster then
keeps resetting

For blinkers I did put it in loop:

#include <SPI.h>
#include "mcp2515_can.h"

#define lo8(x) (uint8_t)((x)&0xff)
#define hi8(x) (uint8_t)(((x) >> 8) & 0xff)

const int SPI_CS_PIN = 9;
const int CAN_INT_PIN = 2;
mcp2515_can CAN(SPI_CS_PIN); // Set CS pin

void sendIgnitionKeyOn()
{
    uint16_t canId = 0x130;
    uint8_t len = 5;

    uint8_t buf[8] = {0, 0, 0, 0, 0, 0, 0, 0};

    buf[0] = 0x45; // Key Status / T15 ON message
    buf[1] = 0x40; // Transponder Detected
    buf[2] = 0x21; // Terminal Status
    buf[3] = 0x8F; // Steering lock?
    buf[4] = 0xFE; // Counter and Checksum

    CAN.sendMsgBuf(canId, 0, len, buf);
}

void sendRPM(uint16_t rpm)
{
    uint16_t tempRpm = rpm * 4;

    const uint16_t canId = 0x0AA;
    const uint8_t len = 8;

    uint8_t buf[8] = {0xFE, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0xFE, 0x99};

    buf[4] = lo8(tempRpm);
    buf[5] = hi8(tempRpm);

    CAN.sendMsgBuf(canId, 0, len, buf);
}

void sendLightsOn()
{
    const uint16_t canId = 0x21A;
    const uint8_t len = 3;

    uint8_t buf[8] = {0b00000101, 0b00010000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

    CAN.sendMsgBuf(canId, 0, len, buf);
}

void leftBlinkerOnInitial()
{
    const uint16_t canId = 0x1F6;
    const uint8_t len = 2;

    uint8_t buf[8] = {0x91, 0xF2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

    CAN.sendMsgBuf(canId, 0, len, buf);
}

void rightBlinkerOnInitial()
{
    const uint16_t canId = 0x1F6;
    const uint8_t len = 2;

    uint8_t buf[8] = {0xA1, 0xF2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

    CAN.sendMsgBuf(canId, 0, len, buf);
}

void keepLeftBlinkerOn()
{
    const uint16_t canId = 0x1F6;
    const uint8_t len = 2;

    uint8_t buf[8] = {0x91, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

    CAN.sendMsgBuf(canId, 0, len, buf);
}

void keepRightBlinkerOn()
{
    const uint16_t canId = 0x1F6;
    const uint8_t len = 2;

    uint8_t buf[8] = {0xA1, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

    CAN.sendMsgBuf(canId, 0, len, buf);
}

void sendFuelLevel(uint16_t litres)
{
    uint16_t canId = 0x349;
    const uint8_t len = 5;

    uint8_t buf[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

    uint16_t sensor1 = litres * 160;
    buf[0] = lo8(sensor1);
    buf[1] = hi8(sensor1);

    uint16_t sensor2 = sensor1;
    buf[2] = lo8(sensor2);
    buf[3] = hi8(sensor2);

    CAN.sendMsgBuf(canId, 0, len, buf);
}

uint32_t timestamp100ms = 0;
uint32_t timestamp800ms = 0;
bool firstBlinkerTurnOn = true;

void setup()
{
    while (CAN_OK != CAN.begin(CAN_100KBPS))
    {
        delay(100);
    }
}

void loop()
{
    if (millis() - timestamp100ms > 99)
    {
        sendIgnitionKeyOn();

        timestamp100ms = millis();
    }

    if (millis() - timestamp800ms > 799)
    {
        // Turn blinker on after 30 seconds to avoid kombi
        // missing the initial message when its turning on
        if (millis() > 30000)
        {
            if (firstBlinkerTurnOn == true)
            {
                leftBlinkerOnInitial();

                firstBlinkerTurnOn = false;
            }

            keepLeftBlinkerOn();
        }

        timestamp800ms = millis();
    }
}


and the kombi does turn on after a few seconds, warning lights flash, but then
turn off after about 2 seconds. The screen stays on but nothing else happens (if
I understood correctly on how to use them: CAN BUS Codes 17)

1F6 2 91 F1 145 241
Left turn signal on (sent following initial 242)
1F6 2 91 F2 145 242
Left turn signal on (sent first, followed by 241)

Im really at a loss I was so happy when they turned on but then I hit a brick
wall





Terraviper-5
Dez. '20


Okay I have found this Arduino forum thread
https://forum.arduino.cc/index.php?topic=569052.0 37 and basically it sounds
exactly whats happening to me. I didn’t try with the scope, but symptoms sound
similar. So I tried this guy’s solution and switched to this lib he is talking
about. I googled that SPI bandwidth of mcp2515 is 1Mbps, so I adjusted
accordingly. And now I’m at the same spot as this guy: E90 Can bus project (E60,
E65, E87....) - Page 2 47 The kombi is going through reset sequence all the time
like its missing something

How it looks like: http://shrani.si/f/4/GQ/1TTxeB2f/1/vid20201213212805.gif 58

Code

#include <CAN.h>

#define lo8(x) (uint8_t)((x)&0xff)
#define hi8(x) (uint8_t)(((x) >> 8) & 0xff)

const uint8_t CS_PIN = 9;
const uint8_t IRQ_PIN = 2;

void sendIgnitionKeyOn()
{
  CAN.beginPacket(0x130);

  CAN.write(0x45);
  CAN.write(0x40);
  CAN.write(0x21);
  CAN.write(0x8F);
  CAN.write(0xFE);

  CAN.endPacket();
}

void sendRPM(uint16_t rpm)
{
  uint16_t tempRpm = rpm * 4;

  CAN.beginPacket(0x0AA);

  CAN.write(0xFE);
  CAN.write(0xFE);
  CAN.write(0xFF);
  CAN.write(0x00);
  CAN.write(lo8(tempRpm));
  CAN.write(hi8(tempRpm));
  CAN.write(0xFE);
  CAN.write(0x99);

  CAN.endPacket();
}

void sendIgnitionStatus()
{
  CAN.beginPacket(0x26E);

  CAN.write(0x40);
  CAN.write(0x40);
  CAN.write(0x7F);
  CAN.write(0x50);
  CAN.write(0xFF);
  CAN.write(0xFF);
  CAN.write(0xFF);
  CAN.write(0xFF);

  CAN.endPacket();
}

void sendFuelLevel(uint16_t litres)
{
  uint16_t sensor = litres * 160;

  CAN.beginPacket(0x349);

  CAN.write(lo8(sensor));
  CAN.write(hi8(sensor));
  CAN.write(lo8(sensor));
  CAN.write(hi8(sensor));
  CAN.write(0x00);

  CAN.endPacket();
}

void sendAirbagSeatbeltCounter()
{
  static uint8_t count = 0x00;

  CAN.beginPacket(0x0D7);

  CAN.write(count);
  CAN.write(0xFF);

  CAN.endPacket();

  count++;
}

void sendABSBrakeCounter2()
{
  CAN.beginPacket(0x19E);

  CAN.write(0x00);
  CAN.write(0xE0);
  CAN.write(0xB3);
  CAN.write(0xFC);
  CAN.write(0xF0);
  CAN.write(0x43);
  CAN.write(0x00);
  CAN.write(0x65);

  CAN.endPacket();
}

void sendABSBrakeCounter1()
{
  static uint8_t count = 0xF0;

  CAN.beginPacket(0x0C0);

  CAN.write(count);
  CAN.write(0xFF);

  CAN.endPacket();

  count++;
  if (count == 0x00)
  {
    count = 0xF0;
  }
}

void seatbeltLight(bool state)
{
  uint8_t thirdBit;

  if (state == false)
  {
    CAN.beginPacket(0x581);
    thirdBit = 0x28;
  }
  else
  {
    CAN.beginPacket(0x394);
    thirdBit = 0x029;
  }

  CAN.write(0x40);
  CAN.write(0x4D);
  CAN.write(0x00);
  CAN.write(thirdBit);
  CAN.write(0xFF);
  CAN.write(0xFF);
  CAN.write(0xFF);
  CAN.write(0xFF);

  CAN.endPacket();
}

void sendSpeed(uint16_t speed)
{
  static uint32_t lastTimeSent = 0;
  static uint16_t lastReading = 0;
  static uint16_t count = 0xF000;

  uint16_t speedValToSend = ((millis() - lastTimeSent) / 50) * speed / 2;
  speedValToSend += lastReading;

  lastReading = speedValToSend;
  lastTimeSent = millis();

  CAN.beginPacket(0x1A6);

  CAN.write(lo8(speedValToSend));
  CAN.write(hi8(speedValToSend));
  CAN.write(lo8(speedValToSend));
  CAN.write(hi8(speedValToSend));
  CAN.write(lo8(speedValToSend));
  CAN.write(hi8(speedValToSend));
  CAN.write(lo8(count));
  CAN.write(hi8(count));

  CAN.endPacket();
}

void sendLightsOff()
{
  CAN.beginPacket(0x21A);

  CAN.write(0b00000000);
  CAN.write(0b00000000);
  CAN.write(0x00);

  CAN.endPacket();
}

uint32_t timestamp100ms = 0;
uint32_t timestamp200ms = 0;

void setup()
{
  Serial.begin(115200);
  while (!Serial)
  {
  };

  CAN.setPins(CS_PIN, IRQ_PIN);
  CAN.setSPIFrequency(1E6);

  while (!CAN.begin(100E3))
  {
    Serial.println("CAN BUS Shield init fail");
    Serial.println(" Init CAN BUS Shield again");
    delay(100);
  }
  Serial.println("CAN BUS Shield init ok!");

  timestamp100ms = millis();
  timestamp200ms = millis();
}

void loop()
{
  if (millis() - timestamp100ms > 99)
  {
    sendIgnitionKeyOn();
    sendRPM(800);
    sendSpeed(0);

    timestamp100ms = millis();
  }

  if (millis() - timestamp200ms > 199)
  {
    sendFuelLevel(24);
    sendIgnitionStatus();
    sendAirbagSeatbeltCounter();
    sendABSBrakeCounter2();
    sendABSBrakeCounter1();
    seatbeltLight(false);
    sendLightsOff();

    timestamp200ms = millis();
  }
}






Terraviper-5
Dez. '20


Found out what problem was under this 61video

It was the termination resistor (trace marked P1) on Seeed CAN bus shield that
was disrupting communication. When I cut the trace everything worked

More info about E90 cluster control: gitHub link 138





5 Monate später

geschlossen, am 5. Mai '21




Antworten



VORGESCHLAGENE THEMEN

Thema Antworten Aufrufe Aktivität

Pcf problem with extra inputs
Project Guidance
15 140 26. Jan.

Check Short Between Two Points
Project Guidance
8 95 23. Jan.

Hitec HS-311 servo noise
Project Guidance
3 114 Okt. '21

NEED HELP with. New Smart little turtle robot v2.0
Project Guidance
17 339 Nov. '21

Feasibility for PS2/NES adapter (power requirements)
Project Guidance
3 74 26 d


MÖCHTEST DU MEHR LESEN? ENTDECKE ANDERE THEMEN IN PROJECT GUIDANCE ODER AKTUELLE
THEMEN ANZEIGEN.


[DE.SHARE.TOPIC]



Teilen



Back to top
 * Help Center
 * Contact Us
 * Trademark & Copyright
 * Brand Guidelines
 * Distributors
 * Careers

FOLLOW US

 * 
 * 
 * 
 * 
 * 
 * 

© 2020 Arduino
 * Careers
 * Terms of Service
 * Privacy Policy
 * Security
 * Cookie Settings



Invalid date Invalid date




We use cookies 🍪
Our websites use cookies (also from third parties) for functional and analytical
purposes, and to show you personalised advertisement. You can adjust this in
Cookie Settings or learn more by reading our cookie policy.
Learn more and customize
ONLY REQUIREDACCEPT ALL