GTR Forum banner

DIY CAN Bus multi-gauge for Link ECU

1 reading
37K views 72 replies 13 participants last post by  Torques  
#1 · (Edited)
Since I got the Link G4+ I have been looking at display options using CAN Bus.

Currently I am experimenting with an Atmel microcontroller/Arduino CAN signal reciever/processor, and an Adafruit OLED display, looks promising so far. Just mocking things up at this stage, but the OLED is a nice size to replace one of the stock submeters on the main dashboard. The idea is that there will be a momentary switch to allow you to cycle through different layouts , for my purposes AFR and Boost on the same gauge is really handy.

Total cost so far ÂŁ70 ish

 
#4 ·
I did a lot of searching for options. With arduino there is so much variety its hard to find exactly what you need for your prpject. The main board could have been standard Arduino with a dedicated separate canbus board, the display could be monochrome oled, lcd, segment led or tft even touch screens can be had for fairly sensible money.

The key is finding things that are well supported with demo projects with working code to base a project on. I am a software dev by trade but the coding required to interface with a display from scratch is beyond me.

The display is faulty (a couple of dodgy columns of pixels) so needs to go back at some point but it works for now. The graphics library I am using to draw to the oled isn't great, the font is too clunky, there is another I am going to try though, but hey clunky is retro.

The mechanics are easy enough, 8 wires to solder joining the display to the controller, decent soldering gear needed as its all tiny. Two more wires for power, two for CAN. Plug in the laptop, hack some code based on the free samples and upload it to the board.

The time goes into reading up so its the right wires you solder and the right code you write!

I havent yet tried to get the actual CAN communications working and i know that can be a pain, but Link have some info in the help files on PC Link and again I have sample projects to hack.

Figuring out how to fit the thing nicely into the clocks is another job, and I seem to have a mental block about that kind of thing. Hot glue and trim tape....

There's a mix of "must haves" and "nice to haves" floating around in my head atm, so I'm going to try to narrow down the essentials otherwise I'll never finish the thing.
 
#8 ·
There are two sides to it, the electronics and comms stuff is something a IT network engineer type would pick that up easy, on the other hand the code is C++, someone that has never written code before could get bogged down trying to do anything more meaningful than flashing a LED, the community and resources are out there to help but there is a learning curve but if you have the time to pick apart a bunch of examples you would pick up the basics.

I remember maplin/radio shack electronic project kits from the 80's. I could never make the circuits work, really put me off electronics for a long time. But this microcontroller based stuff is great, as it really simplifies the electrical and leaves you just connecting modules where someone with a degree in EE has done the hard work of figuring how to make everything talk to each other and you are just doing plumbing.

I've just been back out in the garage :) messing around with power supplies. In the video above its powered via the 5v on the usb lead from the lappy. In the car i planned to power via the 12v that comes off the obd/can. The arduino has a tiny regulator on the specs rated for 5-16v. Turns out it gets red hot running 12v so I'll need to add a power supply board of some variety, maybe just a 5v regulator chip as I have one lying around.

Lol soldering, I know my limitations, the stuff you need to work on for this is all through hole so not too bad if you are used to that sort of thing. Sometimes I think i've cracked it and others the solder just won't go where you want it, its all in the prep and keeping everything clean i think.
 
#10 ·
Alex will you actually be able to read any of the information which comes up easily? I only ask because I have to incline my head to read those gauges which makes it hard to see the ones at the top of the dash whilst driving quickly. For me it's not a problem as I rarely want to know what the front torque or voltage is.

If you are showing boost info might it be too low down to be able to see when you need it?

On another hand to cycle through through the information you could wire up those 'radio' buttons on the dash - I've been trying to think of a use for them for ages!
 
#15 ·
Good point I'll check, but my seat is incredibly low so I suspect it is pretty much in eye-line, certainly better than the standard triple gauge location which is where the gauge I have been using was sited. If visibility was an issue the water temp would be another candidate to replace since it's total BS anyway. But of course you could locate anywhere you wanted.

Genius idea to use the radio buttons! I'll definitely look into that.
 
#11 · (Edited)
That's really neat!. Looking to get into the whole Aurdino/Rasp Pi stuff myself at some point. Wanted to make myself a very basic F/R brake temp gauge with a pair of thermocouples, a controller and a 2-line LCD/OLED display. Will get round to it at some point I presume!!
Out of interest, is it the Adafruit 1.5" colour display you have used??

Good luck with the project.... Looking great so far!!



TT
 
#12 ·
That's really neat!. Looking to get into the whole Aurdino/Rasp Pi stuff myself at some point. Wanted to make myself a very basic F/R brake temp gauge with a pair of thermocouples, a controller and a 2-line LCD/OLED display. Will get round to it at some point I presume!!
Out of interest, is it the Adafruit 1.5" colour display you have used??

Good luck with the project.... Looking great so far!!

TT
A brake temp gauge sounds a great project.

The two components I am using are:
Leonardo CAN BUS board | L-CANBUS | HobbyTronics

And:
https://learn.adafruit.com/adafruit-1-5-color-oled-breakout-board/overview

Not necessarily the cheapest or best available but just what I settled on.
 
#18 ·
Some progress to report. I've been on a serious learning curve!

I have live data coming out of the Link G4+ and being displayed on the OLED screen. I have some basic C++ hex data translation to brush up on but the data is there.

When I have got everything working properly, I'll post code and wiring diagrams. In the meantime here are some observations that will only really be interesting to someone trying to build a similar CAN bus display.

1)CAN bus while incredibly simple and robust in theory, turns out to be fragile and fussy in practice (for the average non-electronic engineering graduate).

2)The little ATMEL microcontrollers used in most Arduinos are at the edge of their performance capabilities with this sort of real time datastream and the load needs to be managed carefully. For this reason the more powerful Arduino Due might be a good bet (it looks like a decent CAN bus library exists for the Due).

3)The CAN transceiver and CAN controller are discrete chips (MCP 2551, MCP 2515 respectively) that together consume and present the CAN bus data in a way the Arduino can query. You can buy a standard Arduino microcontroller board and a separate CAN bus "shield" or "break out board" which contains the MCP2551/2515 ready to connect up, or you could make your own "break out board" by buying the two chips and follow their data sheet to wire up the small number of components needed to make them work. The board I chose is unusually in that it combines the arduino and mcp 2551/2515 on one PCB. Either way though the mcp2551/2515 will require well written code to wrap up their functionality; this is fairly time consuming and specialist work, luckily the wonder of the Arduino community is that open source code in the form of "libraries" are available so that a normal human being can interact with them using just a couple of lines of code. The downside of being open source is that the libraries can vary in quality and completeness. Similarly the open source libraries are available that wrap up the functionality of the OLED display (SSD1351 in this case) allowing simple text and graphics to be displayed using a small amount of code.

4)As a parallel project I have got the Link G4+ and my Race Technology logger talking over CAN. This provides a template datastream to work with; which is really handy, however they default to a 1Mb/s baud rate (the "carrier frequency") and 100Hz update rate (how often new values are put out on the bus). Arduino/MCP2551/2515 hardware seems to freeze up above 125Kb/s baud rate. Luckily the Link ECU has two CAN bus outputs, so one can run at 1Mb/s for the logger, and the other are 125Kb/s for the gauge display(s).

5)As a desktop software developer my instinct was to use interrupts to capture and process the arrival of each CAN message BUT it turns out that the rate at which the interrupt fires (~400Hz or every 2.5ms for the 4 CAN "frames") combined with the time time it takes the processor to write values to the display mean the whole things crashes instantly. Instead you simply let the CAN controller manage its small rotating buffer of incoming CAN messages, and pick them up in the main "process loop" on the Arduino when it has the time, if you miss some it doesn't matter; the update rate will still be fine for a value displayed on a gauge (not so good if you are building an engine management system or ABS system). There were many hours of head scratching and tech support emails exchanged before I figured this out.

6)The wiring and soldering involved is very simple and, thanks to the wiring diagrams and sample code supplied, doesn't require specialist knowledge to get something generic working. But to troubleshoot any meaningful application you really need to understand what makes that sample code work and how that relates to the wiring connections you have made.
 
#19 ·
Interesting observations there Alex. Very useful indeed...


Good work so far and good luck getting over the final hurdle to completion!!



TT
 
#22 · (Edited)
All that's left for my primary goal is to wire up the voltage regulator and mount everything in the place of the factory awd gauge.

For the future it would be fairly easy to add a momentary switch to allow you to cycle through pairs of values being sent by the link. There are better graphics libraries with less blocky fonts which i could try, but i like the retro feel tbh.

A whole new project would be something that reads steering position sensor (the stock sensor is a rotary encoder and there are libraries to read these), brake pressures (simple 0-5v), ATTESA pressure (i have a 0-5v sensor fitted) and sends them out on the can bus for the data logger and ecu to see.

The code is a hacky mess but here it is atm:

The oled connects to the SPI header as per the instructions, just need a couple of other connections. I'll post up some wiring diags later.

The function that loads the gtr image is copied from the adafruit examples.

This needs the link's can port set to use the Dash2pro output stream, set to 125kbps and 100hz iirc. Then just plumb can h/l to the Leonardo Can bus board.

The image gtr.bmp is a 128x128 24bit image stored on the sd card.

The can mask and filter will pick up all the 15 values sent across the 4 frames that the dash2pro config is setup to transmit. I only read lambda which i translate to afr and mgp.

Code:
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1351.h>
#include <SD.h>
#include <mcp_can.h>
#include <SPI.h>

//CAN config
unsigned int rxId;
unsigned char rxLen = 0;
unsigned char rxBuf[8];
volatile unsigned char canData = 0;
int led = 23;
int boostvalue_li = 0;
float afrvalue_f = 0;
MCP_CAN CAN0(17);                                 // Set CS to pin 17

//OLED display config
// If we are using the hardware SPI interface, these are the pins (for future ref)
#define sclk 13
#define mosi 11
#define OLED_CS   5
#define rst  6
#define dc   4

// Color definitions
#define BLACK           0x0000
#define RED             0xF800
#define GREEN           0x07E0
#define YELLOW          0xFFE0  
#define WHITE           0xFFFF

// to draw images from the SD card, we will share the hardware SPI interface
Adafruit_SSD1351 tft = Adafruit_SSD1351(OLED_CS, dc, rst);

//chip select for sd card
#define SD_CS 10
File bmpFile;
int bmpWidth, bmpHeight;
uint8_t bmpDepth, bmpImageoffset;

void setup()
{
  pinMode(led, OUTPUT);

  Serial.begin(9600);
  delay(5000);
  int serialattempt = 0;
//  while (!Serial && serialattempt<10) {
//    delay(1000);
//    serialattempt++; // wait 10 secs for serial port to connect. Needed for Leonardo only
//  }
  Serial.println("Serial port up!");
  
  initOLED();
  
  delay(1000);

  drawGTRlogo();
  
  //show logo for2 secs and then wipe screen
  delay(2000);  

  tft.fillScreen(BLACK);
  drawboostlabel(WHITE);
  drawafrlabel(WHITE);

   //initialise CAN bus
   //keep retrying indefinitley
   while(CAN_OK!=CAN0.begin(CAN_125KBPS))
   {
     //Serial.println("CAN init failed - retry..");
     delay(100);
   }
   
   // *********************************************************		
   // Bytes 1 and 2 of mask/filter apply to CAN ID
   CAN0.init_Mask(0, 0, 0xFFFC); // 0b1111 1111 1111 1100   
   CAN0.init_Filt(0, 0, 0x3E8); // 0b0000 0011 1110 1000 - canid1000 (16bit (motorola) rpm, 16bit (motorola)boostpresoffset -100,8bit water temp,8bit post IC temp, 8bit battery volts,8bit oil tmep
   CAN0.init_Filt(1, 0, 0xFFFF); // 1111 1111 1111 1111 - FAIL
   //CAN0.init_Filt(1, 0, 0x3EA); // 0b0000 0011 1110 1000 - canid1002 (16bit (motorola) lambda x1000)
   CAN0.init_Mask(1, 0, 0xFFFF); // 1111 1111 1111 1111
   CAN0.init_Filt(2, 0, 0x0001); // 0000 0000 0000 0001 - FAIL
   CAN0.init_Filt(3, 0, 0x0001); // 0000 0000 0000 0001 - FAIL
   CAN0.init_Filt(4, 0, 0x0001); // 0000 0000 0000 0001 - FAIL 
   CAN0.init_Filt(5, 0, 0x0001); // 0000 0000 0000 0001 - FAIL  
}

void loop()
{
   if(CAN_MSGAVAIL == CAN0.checkReceive())   // check if data waiting
   {
      //Serial.println("CAN");
      CAN0.readMsgBuf(&rxLen, rxBuf);            // Read data: len = data length, buf = data byte(s)
      rxId = CAN0.getCanId();                    // Get message ID
      
      //if canid 1000 read byte numbers as follows
      //0,1 rpm, 2,3 boost, 4 water temp, 5 IC temp, 6 bat volt, 
      if(rxId==1000)
      {
        //offset is -100 to give kPa
        boostvalue_li=word(rxBuf[2],rxBuf[3]);
        boostvalue_li=boostvalue_li-100;
        drawboostvalue(boostvalue_li);
        Serial.print(word(rxBuf[2],rxBuf[3]),HEX);
        Serial.print(" kpa");
        Serial.println(boostvalue_li);
      }

      //if canid 1002 read byte
      //1,2 lambda
      if(rxId==1002)
      {
        drawafrvalue(word(rxBuf[0],rxBuf[1]));
//        Serial.print(" afr");
//        Serial.println(afrvalue_i);
      }
   }
   else
   {
        //drawboostvalue(0);
        //drawafrvalue(147);
//        Serial.println("noCAN");
   }
}

void drawboostlabel(uint16_t color){
  tft.setCursor(0, 5);
  tft.setTextColor(color);  
  tft.setTextSize(2);
  tft.println("kPa");
}

void drawafrlabel(uint16_t color){
  tft.setCursor(0, 69);
  tft.setTextColor(color);  
  tft.setTextSize(2);
  tft.println("AFR");  
}

void drawafrvalue(word afrvalue){
  afrvalue_f=afrvalue; //div by 1000 to give lambda then *14.68 for AFR
  afrvalue_f=(afrvalue_f/1000)*14.7;
  tft.setCursor(0, 85);
  tft.setTextColor(GREEN,BLACK);  
  if (afrvalue_f >13.0) {
    tft.setTextColor(YELLOW,BLACK);      
  }
  if (afrvalue_f >14.0) {
    tft.setTextColor(RED,BLACK);      
  }
  tft.setTextSize(4);
  tft.println(afrvalue_f);  
}

void drawboostvalue(int boostvalue){
  tft.setCursor(0, 23);
  tft.setTextColor(WHITE,BLACK);  
  if (boostvalue >80) {
    tft.setTextColor(GREEN,BLACK);      
  }
  if (boostvalue >160) {
    tft.setTextColor(YELLOW,BLACK);      
  }
  if (boostvalue >200) {
    tft.setTextColor(RED,BLACK);      
  }
  tft.setTextSize(4);
  tft.println(boostvalue);      
}

#define BUFFPIXEL 20

void bmpDraw(char *filename, uint8_t x, uint8_t y) {

  File     bmpFile;
  int      bmpWidth, bmpHeight;   // W+H in pixels
  uint8_t  bmpDepth;              // Bit depth (currently must be 24)
  uint32_t bmpImageoffset;        // Start of image data in file
  uint32_t rowSize;               // Not always = bmpWidth; may have padding
  uint8_t  sdbuffer[3*BUFFPIXEL]; // pixel buffer (R+G+B per pixel)
  uint8_t  buffidx = sizeof(sdbuffer); // Current position in sdbuffer
  boolean  goodBmp = false;       // Set to true on valid header parse
  boolean  flip    = true;        // BMP is stored bottom-to-top
  int      w, h, row, col;
  uint8_t  r, g, b;
  uint32_t pos = 0, startTime = millis();

  if((x >= tft.width()) || (y >= tft.height())) return;

  // Open requested file on SD card
  if ((bmpFile = SD.open(filename)) == NULL) {
    //Serial.print("File not found");
    return;
  }

  // Parse BMP header
  if(read16(bmpFile) == 0x4D42) { // BMP signature
    Serial.print("File size: "); Serial.println(read32(bmpFile));
    (void)read32(bmpFile); // Read & ignore creator bytes
    bmpImageoffset = read32(bmpFile); // Start of image data
    Serial.print("Image Offset: "); Serial.println(bmpImageoffset, DEC);
    // Read DIB header
    Serial.print("Header size: "); Serial.println(read32(bmpFile));
    bmpWidth  = read32(bmpFile);
    bmpHeight = read32(bmpFile);
    if(read16(bmpFile) == 1) { // # planes -- must be '1'
      bmpDepth = read16(bmpFile); // bits per pixel
      Serial.print("Bit Depth: "); Serial.println(bmpDepth);
      if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed
        goodBmp = true; // Supported BMP format -- proceed!
        // BMP rows are padded (if needed) to 4-byte boundary
        rowSize = (bmpWidth * 3 + 3) & ~3;

        // If bmpHeight is negative, image is in top-down order.
        // This is not canon but has been observed in the wild.
        if(bmpHeight < 0) {
          bmpHeight = -bmpHeight;
          flip      = false;
        }

        // Crop area to be loaded
        w = bmpWidth;
        h = bmpHeight;
        if((x+w-1) >= tft.width())  w = tft.width()  - x;
        if((y+h-1) >= tft.height()) h = tft.height() - y;

        for (row=0; row<h; row++) { // For each scanline...
          tft.goTo(x, y+row);

          // Seek to start of scan line.  It might seem labor-
          // intensive to be doing this on every line, but this
          // method covers a lot of gritty details like cropping
          // and scanline padding.  Also, the seek only takes
          // place if the file position actually needs to change
          // (avoids a lot of cluster math in SD library).
          if(flip) // Bitmap is stored bottom-to-top order (normal BMP)
            pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
          else     // Bitmap is stored top-to-bottom
            pos = bmpImageoffset + row * rowSize;
          if(bmpFile.position() != pos) { // Need seek?
            bmpFile.seek(pos);
            buffidx = sizeof(sdbuffer); // Force buffer reload
          }

          // optimize by setting pins now
          for (col=0; col<w; col++) { // For each pixel...
            // Time to read more pixel data?
            if (buffidx >= sizeof(sdbuffer)) { // Indeed
              bmpFile.read(sdbuffer, sizeof(sdbuffer));
              buffidx = 0; // Set index to beginning
            }

            // Convert pixel from BMP to TFT format, push to display
            b = sdbuffer[buffidx++];
            g = sdbuffer[buffidx++];
            r = sdbuffer[buffidx++];

            tft.drawPixel(x+col, y+row, tft.Color565(r,g,b));
            // optimized!
            //tft.pushColor(tft.Color565(r,g,b));
          } // end pixel
        } // end scanline
        Serial.print("Loaded in ");
        Serial.print(millis() - startTime);
        Serial.println(" ms");
      } // end goodBmp
    }
  }

  bmpFile.close();
  if(!goodBmp) Serial.println("BMP format not recognized.");
}

uint16_t read16(File f) {
  uint16_t result;
  ((uint8_t *)&result)[0] = f.read(); // LSB
  ((uint8_t *)&result)[1] = f.read(); // MSB
  return result;
}

uint32_t read32(File f) {
  uint32_t result;
  ((uint8_t *)&result)[0] = f.read(); // LSB
  ((uint8_t *)&result)[1] = f.read();
  ((uint8_t *)&result)[2] = f.read();
  ((uint8_t *)&result)[3] = f.read(); // MSB
  return result;
}

void initOLED()
{
    // initialize the OLED
  pinMode(OLED_CS, OUTPUT);
  digitalWrite(OLED_CS, HIGH);     
  Serial.println("init OLED");  
  tft.begin();  
  tft.fillScreen(BLACK);
}

void drawGTRlogo()
{
  // initialize the SD
  //Serial.print("Initializing SD card...");
  if (!SD.begin(SD_CS)) {
    return;
  }
  bmpDraw("gtr.bmp", 0, 0);
}
 
#25 · (Edited)
More progress on Sunday. Figured out the mounting details in my spare instrument cluster; a few pcb sandoffs a couple of extra holes drilled. Also made up a little voltage regulator breakout board and found a place for it in the cluster. Pucker automotive grade chip, with protection against reverse polarity, voltage spikes and noise. Getting closer to completion, I'd like to figure out a better bezel but the leathercloth is ok for now.

Image


Image


Image
 
#30 ·
More progress on Sunday. Figured out the mounting details in my spare instrument cluster; a few pcb sandoffs a couple of extra holes drilled. Also made up a little voltage regulator breakout board and found a place for it in the cluster. Pucker automotive grade chip, with protection against reverse polarity, voltage spikes and noise. Getting closer to completion, I'd like to figure out a better bezel but the leathercloth is ok for now.

Image


Image


Image
Maybe these will work?
 
#27 ·
weird I can see those pics ok, they are from google so the urls are a bit different, I'm using chrome on my mobile, may be try a different browser. Can anyone else see them?

I used standard Amp connectors with crimp terminals, you can by them fairly cheap on ebay. If you need to connect to the big OBD11 port then the connectors ready for soldering can also be had on ebay. Being that have a link g4+ it has a header on the board tht link supply a breakout lead for that you can wire up as you need.

I have recently bought a teensy 3.2, which has a good bit more grunt than the leonardo, and comes with a can controlled built in, you still need a mcp2551 transciever but the, I've also picked up some switec stepper motors that are widely used in modern dashboards, my plan is to replace the inards of the stock oil pressure/temp and water temp gauges with more accurate ones, with the added benifit of min/max peak hold functions.
 
#28 ·
Cheers Alex, think the pictures are private or something? Just tried them in a different browser and the same thing happen?

Thanks for the info, its this that I want to take of the header from the board then solder to my female ODB2.

Cable (CANPCB) - ECU Cables - Link Engine Management

I'm also wondering if it would be possible to split the Can H/L signal wires and send the data to a custom gauge (similar to yours) and to my new ODB2 Bluetooth setup for connection to dash commander.
 
#29 ·
Dur oh yeah, I just tried IE and pasted in the imge urls it's asking me to sign in to google plus, I'll host them somewhere else.

That connector with the round plug on the end isn't necessary you just need the PCB header and the bare leads on the other end, it's a 5 pin JST header I think, Abbey sorted me out with it once I explained what I needed.

The nice thing about the g4+ is that it actually has 2 CAN outputs so you can use from for proper ODB11 with the standard pin out and connector for things like odb Bluetooth tools, and the other for pure CAN bus - just CAN h/l.
 
#31 ·
Image


Here's the teensy 3.2 and the stepper with the gauge unit for one of the stock gauges for scale, a 8 pin DIP mcp2551 and a little 5v regulator which will drive both happily from the cars 12v. The teensy is small, like 0.5"x1.5", and yet twice the memory and power for the arduino leonardo!

I also think I figured out why the leocan board wouldn't read at 1mb/s. The mcp2551 transceiver has a "slope control" input which is wired through a 4.7k resistor on the leo can (and on most of the schematics you see for the mcp2551 tbh), the bigger the resistor the more gentle the slope on the up and down parts of the "square" wave, more gentle slope = less EM noise, but for full speed I've seen a few people suggest you need to earth this input to get really rapid slope, otherwise the can box on the other end of the line gets board of waiting and thinks you aren't responding and turns off. Not tried it yet....
 
#32 · (Edited)
Hey Alex

Any updates?

you've inspired me to have a little play myself :) so I've ordered a few bits :)

Ordered one of these

CAN-Bus Breakout Board [CANBUS-BRK] - ÂŁ12.10 : SK Pang Electronics, Arduino, Sparkfun, GPS, GSM

Going to rig it up with a oled display and an Arduino uno for now.

Just looking at your code when you declare can0 you use pin 17, on an uno would you connect it to tx and rx I.e pin 0,1 from the break out to those pins on the uno? Can therefore would the declaration be can(0)? Sorry not read all of library yet.

Thanks Alex
 
#33 ·
That breakout board only has a mcp2551 transciever. So that will work with arm micros because it needs the built in can controller that comes on board the arm micros. The uno has a atmel micro which means you also need a mcp2515 can controller. Skpang do a combine transciever and controller board intended for atmel arduinos Arduino CAN-Bus Shield with uSD Card Holder [AR-CANBUS] - ÂŁ18.00 : SK Pang Electronics, Arduino, Sparkfun, GPS, GSM

The pin 17 is the "chip select" (aka cs) pin that instructs the mcp2515 controller to expect instructions from the micro (any digital pin will work in theory but the leocan board has this hard wired to pin 17) the comms then happen over SPI (mosi,miso) pins. You can run multiple slaves on SPI "bus" so each slave has a "chip select" pin that tells it your are talking to it and not other slaves.

The breakout board you linked to only has the mcp2551 chip which has raw can rx/tx pins which need to go into can rx/tx pins on the arm micro (or a mcp2515 controller).
 
#34 ·
Thanks Alex, i looked at one of those but though i might struggle to rig up a oled display.

Looking at your project if I went with this instead:-

Leonardo CAN BUS board | L-CANBUS | HobbyTronics

do you think I could drive this as well?

OLED Graphic Display 128x64 Blue on Black 0.96in | OLED128-64 | HobbyTronics

Can't find much on the web in regards to the wiring of them and which pins to use. The coding looks quite straight forward using the SSD1306, SPI and mcp_can.

I'm rusty with the hardware side!

Sorry for the questions

Cheers!
 
#35 ·
Those would work fine together. They list the connections on the product page for the display so you should be ok with that. The hardware side of things is much simpler than it seems once you figure out how the various inputs and outputs are labelled (inconsistently).

That leocan board really needs a separate power regulator (just a simple three pin chip) is you are going to run it off 12v or the tiny onboard regulator gets super hot as its having to drive the arduino and the display.

I found the leocan could not read the can bus at 1mb/s. I have a theory that this is due to the way they designed the board and i think there is a little mod that can be done to give full 1mb/s which the mcp2551/2515 are rated for.