forum.arduino.cc Open in urlscan Pro
2602:fd3f:1:ff02::4b  Public Scan

URL: https://forum.arduino.cc/t/controlling-bmw-e90-instrument-cluster/670728/5
Submission: On April 27 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

Arduino Forum


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!

1 „Gefällt mir“

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 CAN line doesn't update: MCP2515,
mcp_can.h - Networking, Protocols, and Devices - Arduino Forum 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




CONTROLLING BMW E90 INSTRUMENT CLUSTER

Using ArduinoProject Guidance
Anmelden
 * 
 * 

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
5/7
Dez. 2020

Mai 2021

Terraviper-5
1
Aug. '20post #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 191 with start CAN message
 * a wiring diagram 303
 * a forum thread 98 where someone applied power to it (and another 37)
 * a list of 296 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!


1

 * BMW E90 CAN bus Instrument Cluster12

 * ERSTELLT
   
   Aug. '20

 * LETZTE ANTW.
   
   Mai '21
 * 6
   
   ANTWORTEN

 * 10,3 T.
   
   AUFRUFE

 * 2
   
   BENUTZER

 * 1
   
   „GEFÄLLT MIR“

 * 17
   
   LINKS

 * 5
   


4 Monate später
Terraviper-5
Dez. '20post #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 79





xadonxander
Dez. '20post #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
Dez. '20post #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 67

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 37)

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. '20post #5


Okay I have found this Arduino forum thread CAN line doesn't update: MCP2515,
mcp_can.h - Networking, Protocols, and Devices - Arduino Forum 68 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 105 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 144

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. '20post #6


Found out what problem was under this 149video

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 393





5 Monate später

Geschlossen, am 5. Mai '21





Antworten



VORGESCHLAGENE THEMEN

Thema Antworten Aufrufe Aktivität

WiFi controller
Project Guidance
15 117 2. Jan.

Difference between atmega16u2-uno-wifi-r3 and Arduino UNO wifi rev2
Project Guidance
3 159 Dez. '22

Controlling a motor using a 12V line , and using arduino to vary resistance
Project Guidance
7 110 Dez. '22

Uploading code through a 1/4" Male Audio Jack via Serial
Project Guidance
12 184 Nov. '22

Passing time from main to class by pointer as reference
Project Guidance
3 118 8. Feb.


WILLST DU MEHR LESEN? DURCHSTÖBERE ANDERE THEMEN IN PROJECT GUIDANCE ODER SIEH
DIR DIE AKTUELLEN THEMEN AN.

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