Pages: [1] 2   Go Down
Author Topic: CAN Shield  (Read 26192 times)
0 Members and 2 Guests are viewing this topic.
0
Offline Offline
Jr. Member
**
Karma: 1
Posts: 91
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Well, here's my first *complete* project for the Arduino.  (Never really complete, are they.)



Now I understand that there are a few CAN implementations out there, but the more the merrier, right? smiley

This one uses the MCP2515/MCP2551 chips like most of them do. It has a switchable CS pin so that you can use other SPI shields with it that might have hardwired D10 as CS.  It has a switch to draw power from the CAN Bus if desired, if you wanted to add a WiFi or Bluetooth shield for example.  And for newbies like me it's an entirely through hole design making it an easy DIY project. smiley

I've also written a library that's a complete implementation of the MCP2515 SPI command set.  It doesn't yet have any wrappers for filters or masks, but these are all accessible through the read and write commands.  I have a simple Init function that takes a bus speed and clock frequency and calculates out all the necessary bit timing parameters, which makes it pretty straightforward to setup and use.

Now all I need is something to connect it to ...... smiley-grin  (I actually have a need for this in another project that has been temporarily sidelined.)
Logged

Melbourne, Australia
Offline Offline
Full Member
***
Karma: 1
Posts: 226
Cyborg-in-progress
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Now all I need is something to connect it to

You didn't mention if you're wanting to use this for an automotive project, but if you are then something that might be useful for development is a mOByDic 1610:

http://www.ozenelektronik.com/?s=products2&group=eobd-obdii-ecu-simulators

Developing against an ECU is no fun if you have to sit in the garage with your laptop while you're coding! I've spent way too long out in the driveway with a lappie and a long extension cable. Much nicer to be able to sit at your bench and twiddle the knobs to simulate different behavior.
--
Jon
Vehicle Telemetry Platform: www.practicalarduino.com/projects/vehicle-telemetry-platform
Logged

0
Offline Offline
Jr. Member
**
Karma: 1
Posts: 91
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

It's actually going to be used to interface to an Electric Vehicle controller, so no OBD-II needed.  Of course, it's a proprietry system that I've got to hack, so we'll see how that goes.  :smiley  Should be fun though. smiley-grin
« Last Edit: November 08, 2010, 11:59:43 pm by DaveAK » Logged

0
Offline Offline
Jr. Member
**
Karma: 1
Posts: 91
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Here's the library code:

MCP2515.h

Code:
/*
  MCP2515.h - Library for Microchip MCP2515 CAN Controller
  
  Author: David Harding
  
  Created: 11/08/2010
  
  For further information see:
  
  http://ww1.microchip.com/downloads/en/DeviceDoc/21801e.pdf
  http://en.wikipedia.org/wiki/CAN_bus
*/

#ifndef MCP2515_h
#define MCP2515_h

#include "WProgram.h"
#include "MCP2515_defs.h"

class MCP2515
{
  public:
      // Constructor defining which pins to use for CS and INT
    MCP2515(byte CS_Pin, byte INT_Pin);
      
      // Overloaded initialization function
      int Init(int baud, byte freq);
      int Init(int baud, byte freq, byte sjw);
      
      // Basic MCP2515 SPI Command Set
    void Reset();
    byte Read(byte address);
    void Read(byte address, byte data[], byte bytes);
      Frame ReadBuffer(byte buffer);
      void Write(byte address, byte data);
      void Write(byte address, byte data[], byte bytes);
      void LoadBuffer(byte buffer, Frame message);
      void SendBuffer(byte buffers);
      byte Status();
      byte RXStatus();
      void BitModify(byte address, byte mask, byte data);

      // Extra functions
      bool Interrupt(); // Expose state of INT pin
      bool Mode(byte mode); // Returns TRUE if mode change successful
      
  private:
      bool _init(int baud, byte freq, byte sjw, bool autoBaud);
    // Pin variables
      byte _CS;
      byte _INT;
};

#endif

MCP2515_defs.h

Code:
/*
  MCP2515_defs.h - Library for Microchip MCP2515 CAN Controller
  
  Author: David Harding
  
  Created: 11/08/2010
  
  For further information see:
  
  http://ww1.microchip.com/downloads/en/DeviceDoc/21801e.pdf
  http://en.wikipedia.org/wiki/CAN_bus
*/

#ifndef MCP2515_defs_h
#define MCP2515_defs_h

#include "WProgram.h"

typedef struct
{
      unsigned long id;      // EID if ide set, SID otherwise
      byte srr;                  // Standard Frame Remote Transmit Request
      byte rtr;                  // Remote Transmission Request
      byte ide;                  // Extended ID flag
      byte dlc;                  // Number of data bytes
      byte data[8];            // Data bytes
} Frame;
      

// MCP2515 SPI Commands
#define CAN_RESET       0xC0
#define CAN_READ        0x03
#define CAN_WRITE       0x02
#define CAN_RTS         0x80
#define CAN_STATUS      0xA0
#define CAN_BIT_MODIFY  0x05  
#define CAN_RX_STATUS   0xB0
#define CAN_READ_BUFFER 0x90
#define CAN_LOAD_BUFFER 0X40  

// Register Bit Masks
// CANSTAT
#define MODE_CONFIG            0x80
#define MODE_LISTEN            0x60
#define MODE_LOOPBACK      0x40
#define MODE_SLEEP            0x20
#define MODE_NORMAL            0x00
// CANINTF
#define RX0IF                  0x01
#define RX1IF                  0x02
#define TX0IF                  0x04
#define TX1IF                  0x08
#define TX2IF                  0x10
#define ERRIF                  0x20
#define WAKIF                  0x40
#define MERRF                  0x80

// Configuration Registers
#define CANSTAT         0x0E
#define CANCTRL         0x0F
#define BFPCTRL         0x0C
#define TEC             0x1C
#define REC             0x1D
#define CNF3            0x28
#define CNF2            0x29
#define CNF1            0x2A
#define CANINTE         0x2B
#define CANINTF         0x2C
#define EFLG            0x2D
#define TXRTSCTRL       0x0D

// TX Buffer 0
#define TXB0CTRL        0x30
#define TXB0SIDH        0x31
#define TXB0SIDL        0x32
#define TXB0EID8        0x33
#define TXB0EID0        0x34
#define TXB0DLC         0x35
#define TXB0D0          0x36
#define TXB0D1          0x37
#define TXB0D2          0x38
#define TXB0D3          0x39
#define TXB0D4          0x3A
#define TXB0D5          0x3B
#define TXB0D6          0x3C
#define TXB0D7          0x3D
                        
// TX Buffer 1
#define TXB1CTRL        0x40
#define TXB1SIDH        0x41
#define TXB1SIDL        0x42
#define TXB1EID8        0x43
#define TXB1EID0        0x44
#define TXB1DLC         0x45
#define TXB1D0          0x46
#define TXB1D1          0x47
#define TXB1D2          0x48
#define TXB1D3          0x49
#define TXB1D4          0x4A
#define TXB1D5          0x4B
#define TXB1D6          0x4C
#define TXB1D7          0x4D

// TX Buffer 2
#define TXB2CTRL        0x50
#define TXB2SIDH        0x51
#define TXB2SIDL        0x52
#define TXB2EID8        0x53
#define TXB2EID0        0x54
#define TXB2DLC         0x55
#define TXB2D0          0x56
#define TXB2D1          0x57
#define TXB2D2          0x58
#define TXB2D3          0x59
#define TXB2D4          0x5A
#define TXB2D5          0x5B
#define TXB2D6          0x5C
#define TXB2D7          0x5D
                        
// RX Buffer 0
#define RXB0CTRL        0x60
#define RXB0SIDH        0x61
#define RXB0SIDL        0x62
#define RXB0EID8        0x63
#define RXB0EID0        0x64
#define RXB0DLC         0x65
#define RXB0D0          0x66
#define RXB0D1          0x67
#define RXB0D2          0x68
#define RXB0D3          0x69
#define RXB0D4          0x6A
#define RXB0D5          0x6B
#define RXB0D6          0x6C
#define RXB0D7          0x6D
                        
// RX Buffer 1
#define RXB1CTRL        0x70
#define RXB1SIDH        0x71
#define RXB1SIDL        0x72
#define RXB1EID8        0x73
#define RXB1EID0        0x74
#define RXB1DLC         0x75
#define RXB1D0          0x76
#define RXB1D1          0x77
#define RXB1D2          0x78
#define RXB1D3          0x79
#define RXB1D4          0x7A
#define RXB1D5          0x7B
#define RXB1D6          0x7C
#define RXB1D7          0x7D

// Buffer Bit Masks
#define RXB0            0x00
#define RXB1            0x02
#define TXB0            0x01
#define TXB1            0x02
#define TXB2            0x04
#define TXB_ALL                  TXB0 | TXB1 | TXB2

#endif

Continued next post ...
Logged

0
Offline Offline
Jr. Member
**
Karma: 1
Posts: 91
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

MCP2515.cpp

Code:
/*
  MCP2515.cpp - Library for Microchip MCP2515 CAN Controller
  
  Author: David Harding
  
  Created: 11/08/2010
  
  For further information see:
  
  http://ww1.microchip.com/downloads/en/DeviceDoc/21801e.pdf
  http://en.wikipedia.org/wiki/CAN_bus
*/

#include "WProgram.h"
#include "SPI.h"
#include "MCP2515.h"
#include "MCP2515_defs.h"

MCP2515::MCP2515(byte CS_Pin, byte INT_Pin) {
  pinMode(CS_Pin, OUTPUT);
  digitalWrite(CS_Pin,HIGH);

  pinMode(INT_Pin,INPUT);
  digitalWrite(INT_Pin,HIGH);
  
  _CS = CS_Pin;
  _INT = INT_Pin;
}

/*
  Initialize MCP2515
  
  int CAN_Bus_Speed = transfer speed in kbps
  int Freq = MCP2515 oscillator frequency in MHz
  int SJW = Synchronization Jump Width Length bits - 1 to 4 (see data sheet)
  
  returns baud rate set
  
  Sending a bus speed of 0 kbps initiates AutoBaud and returns zero if no
  baud rate could be determined.  There must be two other active nodes on the bus!
*/
int MCP2515::Init(int CAN_Bus_Speed, byte Freq) {
  if(CAN_Bus_Speed>0) {
    if(_init(CAN_Bus_Speed, Freq, 1, false)) return CAN_Bus_Speed;
  } else {
      int i=0;
      byte interruptFlags = 0;
      for(i=5; i<1000; i=i+5) {
        if(_init(i, Freq, 1, true)) {
            // check for bus activity
            Write(CANINTF,0);
            delay(500); // need the bus to be communicating within this time frame
            if(Interrupt()) {
              // determine which interrupt flags have been set
              interruptFlags = Read(CANINTF);
              if(!(interruptFlags & MERRF)) {
                // to get here we must have received something without errors
                Mode(MODE_NORMAL);
                  return i;
              }
            }
        }
      }
  }
  return 0;
}

int MCP2515::Init(int CAN_Bus_Speed, byte Freq, byte SJW) {
  if(SJW < 1) SJW = 1;
  if(SJW > 4) SJW = 4;
  if(CAN_Bus_Speed>0) {
    if(_init(CAN_Bus_Speed, Freq, SJW, false)) return CAN_Bus_Speed;
  } else {
      int i=0;
      byte interruptFlags = 0;
      for(i=5; i<1000; i=i+5) {
        if(_init(i, Freq, SJW, true)) {
            // check for bus activity
            Write(CANINTF,0);
            delay(500); // need the bus to be communicating within this time frame
            if(Interrupt()) {
              // determine which interrupt flags have been set
              interruptFlags = Read(CANINTF);
              if(!(interruptFlags & MERRF)) {
                // to get here we must have received something without errors
                Mode(MODE_NORMAL);
                  return i;
              }
            }
        }
      }
  }
  return 0;
}

bool MCP2515::_init(int CAN_Bus_Speed, byte Freq, byte SJW, bool autoBaud) {
  
  // Reset MCP2515 which puts it in configuration mode
  Reset();
  
  // Calculate bit timing registers
  byte BRP;
  float TQ;
  byte BT;
  float tempBT;

  float NBT = 1.0 / (float)CAN_Bus_Speed * 1000.0; // Nominal Bit Time
  for(BRP=0;BRP<8;BRP++) {
    TQ = 2.0 * (float)(BRP + 1) / (float)Freq;
    tempBT = NBT / TQ;
      if(tempBT<=25) {
        BT = (int)tempBT;
        if(tempBT-BT==0) break;
      }
  }
  
  byte SPT = (0.7 * BT); // Sample point
  byte PRSEG = (SPT - 1) / 2;
  byte PHSEG1 = SPT - PRSEG - 1;
  byte PHSEG2 = BT - PHSEG1 - PRSEG - 1;

  // Programming requirements
  if(PRSEG + PHSEG1 < PHSEG2) return false;
  if(PHSEG2 <= SJW) return false;
  
  byte BTLMODE = 1;
  byte SAM = 0;
  
  // Set registers
  byte data = (((SJW-1) << 6) | BRP);
  Write(CNF1, data);
  Write(CNF2, ((BTLMODE << 7) | (SAM << 6) | ((PHSEG1-1) << 3) | (PRSEG-1)));
  Write(CNF3, (B10000000 | (PHSEG2-1)));
  Write(TXRTSCTRL,0);
  
  if(!autoBaud) {
    // Return to Normal mode
      if(!Mode(MODE_NORMAL)) return false;
  } else {
    // Set to Listen Only mode
      if(!Mode(MODE_LISTEN)) return false;
  }
  // Enable all interupts
  Write(CANINTE,255);
  
  // Test that we can read back from the MCP2515 what we wrote to it
  byte rtn = Read(CNF1);
  return (rtn==data);
}

void MCP2515::Reset() {
  digitalWrite(_CS,LOW);
  SPI.transfer(CAN_RESET);
  digitalWrite(_CS,HIGH);
}

byte MCP2515::Read(byte address) {
  digitalWrite(_CS,LOW);
  SPI.transfer(CAN_READ);
  SPI.transfer(address);
  byte data = SPI.transfer(0x00);
  digitalWrite(_CS,HIGH);
  return data;
}

void MCP2515::Read(byte address, byte data[], byte bytes) {
  // allows for sequential reading of registers starting at address - see data sheet
  byte i;
  digitalWrite(_CS,LOW);
  SPI.transfer(CAN_READ);
  SPI.transfer(address);
  for(i=0;i<bytes;i++) {
    data[i] = SPI.transfer(0x00);
  }
  digitalWrite(_CS,HIGH);
}

Frame MCP2515::ReadBuffer(byte buffer) {
 
  // Reads an entire RX buffer.
  // buffer should be either RXB0 or RXB1
  
  Frame message;
  
  digitalWrite(_CS,LOW);
  SPI.transfer(CAN_READ_BUFFER | (buffer<<1));
  byte byte1 = SPI.transfer(0x00); // RXBnSIDH
  byte byte2 = SPI.transfer(0x00); // RXBnSIDL
  byte byte3 = SPI.transfer(0x00); // RXBnEID8
  byte byte4 = SPI.transfer(0x00); // RXBnEID0
  byte byte5 = SPI.transfer(0x00); // RXBnDLC

  message.srr=(byte2 & B00010000);
  message.ide=(byte2 & B00001000);

  if(message.ide) {
    message.id = (byte1>>3);
    message.id = (message.id<<8) | ((byte1<<5) | ((byte2>>5)<<2) | (byte2 & B00000011));
    message.id = (message.id<<8) | byte3;
    message.id = (message.id<<8) | byte4;
  } else {
    message.id = ((byte1>>5)<<8) | ((byte1<<3) | (byte2>>5));
  }

  message.rtr=(byte5 & B01000000);
  message.dlc = (byte5 & B00001111);  // Number of data bytes
  for(int i=0;i<message.dlc;i++) {
    message.data[i] = SPI.transfer(0x00);
  }
  digitalWrite(_CS,HIGH);

  return message;
}

void MCP2515::Write(byte address, byte data) {
  digitalWrite(_CS,LOW);
  SPI.transfer(CAN_WRITE);
  SPI.transfer(address);
  SPI.transfer(data);
  digitalWrite(_CS,HIGH);
}

void MCP2515::Write(byte address, byte data[], byte bytes) {
  // allows for sequential writing of registers starting at address - see data sheet
  byte i;
  digitalWrite(_CS,LOW);
  SPI.transfer(CAN_WRITE);
  SPI.transfer(address);
  for(i=0;i<bytes;i++) {
    SPI.transfer(data[i]);
  }
  digitalWrite(_CS,HIGH);
}

void MCP2515::SendBuffer(byte buffers) {
  // buffers should be any combination of TXB0, TXB1, TXB2 ORed together, or TXB_ALL
  digitalWrite(_CS,LOW);
  SPI.transfer(CAN_RTS | buffers);
  digitalWrite(_CS,HIGH);
}

void MCP2515::LoadBuffer(byte buffer, Frame message) {
 
  // buffer should be one of TXB0, TXB1 or TXB2
  if(buffer==TXB0) buffer = 0;

  byte byte1=0; // TXBnSIDH
  byte byte2=0; // TXBnSIDL
  byte byte3=0; // TXBnEID8
  byte byte4=0; // TXBnEID0
  byte byte5=0; // TXBnDLC

  if(message.ide) {
    byte1 = byte((message.id<<3)>>24); // 8 MSBits of SID
      byte2 = byte((message.id<<11)>>24) & B11100000; // 3 LSBits of SID
      byte2 = byte2 | byte((message.id<<14)>>30); // 2 MSBits of EID
      byte2 = byte2 | B00001000; // EXIDE
    byte3 = byte((message.id<<16)>>24); // EID Bits 15-8
    byte4 = byte((message.id<<24)>>24); // EID Bits 7-0
  } else {
    byte1 = byte((message.id<<21)>>24); // 8 MSBits of SID
      byte2 = byte((message.id<<29)>>24) & B11100000; // 3 LSBits of SID
    byte3 = 0; // TXBnEID8
    byte4 = 0; // TXBnEID0
  }
  byte5 = message.dlc;
  if(message.rtr) {
    byte5 = byte5 | B01000000;
  }
  
  digitalWrite(_CS,LOW);
  SPI.transfer(CAN_LOAD_BUFFER | buffer);  
  SPI.transfer(byte1);
  SPI.transfer(byte2);
  SPI.transfer(byte3);
  SPI.transfer(byte4);
  SPI.transfer(byte5);
 
  for(int i=0;i<message.dlc;i++) {
    SPI.transfer(message.data[i]);
  }
  digitalWrite(_CS,HIGH);
}

byte MCP2515::Status() {
  digitalWrite(_CS,LOW);
  SPI.transfer(CAN_STATUS);
  byte data = SPI.transfer(0x00);
  digitalWrite(_CS,HIGH);
  return data;
  /*
  bit 7 - CANINTF.TX2IF
  bit 6 - TXB2CNTRL.TXREQ
  bit 5 - CANINTF.TX1IF
  bit 4 - TXB1CNTRL.TXREQ
  bit 3 - CANINTF.TX0IF
  bit 2 - TXB0CNTRL.TXREQ
  bit 1 - CANINTFL.RX1IF
  bit 0 - CANINTF.RX0IF
  */
}

byte MCP2515::RXStatus() {
  digitalWrite(_CS,LOW);
  SPI.transfer(CAN_RX_STATUS);
  byte data = SPI.transfer(0x00);
  digitalWrite(_CS,HIGH);
  return data;
  /*
  bit 7 - CANINTF.RX1IF
  bit 6 - CANINTF.RX0IF
  bit 5 -
  bit 4 - RXBnSIDL.EIDE
  bit 3 - RXBnDLC.RTR
  bit 2 | 1 | 0 | Filter Match
  ------|---|---|-------------
      0 | 0 | 0 | RXF0
        0 | 0 | 1 | RXF1
        0 | 1 | 0 | RXF2
        0 | 1 | 1 | RXF3
        1 | 0 | 0 | RXF4
        1 | 0 | 1 | RXF5
        1 | 1 | 0 | RXF0 (rollover to RXB1)
        1 | 1 | 1 | RXF1 (rollover to RXB1)
  */
}

void MCP2515::BitModify(byte address, byte mask, byte data) {
  // see data sheet for explanation
  digitalWrite(_CS,LOW);
  SPI.transfer(CAN_BIT_MODIFY);
  SPI.transfer(address);
  SPI.transfer(mask);
  SPI.transfer(data);
  digitalWrite(_CS,HIGH);
}

bool MCP2515::Interrupt() {
  return (digitalRead(_INT)==LOW);
}

bool MCP2515::Mode(byte mode) {
  /*
  mode can be one of the following:
  MODE_CONFIG
  MODE_LISTEN
  MODE_LOOPBACK
  MODE_SLEEP
  MODE_NORMAL
  */
  BitModify(CANCTRL, B11100000, mode);
  delay(10); // allow for any transmissions to complete
  byte data = Read(CANSTAT); // check mode has been set
  return ((data & mode)==mode);
}
Logged

0
Offline Offline
Jr. Member
**
Karma: 1
Posts: 91
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

keywords.txt

Code:
#######################################
# Syntax Coloring Map MCP2515
#######################################

#######################################
# Datatypes (KEYWORD1)
#######################################

MCP2515      KEYWORD1

#######################################
# Methods and Functions (KEYWORD2)
#######################################
Init      KEYWORD2
Reset      KEYWORD2
Read      KEYWORD2
ReadBuffer      KEYWORD2
Write      KEYWORD2
LoadBuffer      KEYWORD2
SendBuffer      KEYWORD2
Status      KEYWORD2
RXStatus      KEYWORD2
BitModify      KEYWORD2
Interrupt      KEYWORD2

#######################################
# Constants (LITERAL1)
#######################################
CAN_RESET      LITERAL1
CAN_READ      LITERAL1
CAN_WRITE      LITERAL1
CAN_RTS      LITERAL1
CAN_STATUS      LITERAL1
CAN_BIT_MODIFY      LITERAL1
CAN_RX_STATUS      LITERAL1
CAN_READ_BUFFER      LITERAL1
CAN_LOAD_BUFFER      LITERAL1

RXB0      LITERAL1
RXB1      LITERAL1
TXB0      LITERAL1
TXB1      LITERAL1
TXB2      LITERAL1
TXB_ALL      LITERAL1

MODE_CONFIG      LITERAL1
MODE_LISTEN      LITERAL1
MODE_LOOPBACK      LITERAL1
MODE_SLEEP      LITERAL1
MODE_NORMAL      LITERAL1

RX0IF      LITERAL1
RX1IF      LITERAL1
TX0IF      LITERAL1
TX1IF      LITERAL1
TX2IF      LITERAL1
ERRIF      LITERAL1
WAKIF      LITERAL1
MERRF      LITERAL1

CANTest.pde

Code:
/*
  MCP2515 CAN Interface Using SPI
  
  Author: David Harding
  
  Created: 11/08/2010
  
  For further information see:
  
  http://ww1.microchip.com/downloads/en/DeviceDoc/21801e.pdf
  http://en.wikipedia.org/wiki/CAN_bus
  The MCP2515 Library files also contain important information
  
  This sketch shows the most basic of steps to send and receive CAN messages.
  
  It has been tested with a Microchip MCP2515DM-BM Demo Board, which consists of two identical
  boards that pass messages between each other.  There is a connector available so that another
  CAN device can be connected to the bus.  Using this I was able to read the messages passed
  between the two boards, and also introduce my own messages to the bus, which are then displayed
  by the software supplied with the demo kit.
  
  NOTE!!!  If you use this sketch to test on a live system I suggest that you comment out the
  send messages lines unless you are certain that they will have no detrimental effect!  
*/

#include <SPI.h> // Arduino SPI Library
#include <MCP2515.h>

// Pin definitions specific to how the MCP2515 is wired up.
#define CS_PIN    10
#define INT_PIN    6

// Create CAN object with pins as defined
MCP2515 CAN(CS_PIN, INT_PIN);

void setup() {
  Serial.begin(115200);
  
  Serial.println("Initializing ...");

  // Set up SPI Communication
  // dataMode can be SPI_MODE0 or SPI_MODE3 only for MCP2515
  SPI.setClockDivider(SPI_CLOCK_DIV2);
  SPI.setDataMode(SPI_MODE0);
  SPI.setBitOrder(MSBFIRST);
  SPI.begin();
  
  // Initialise MCP2515 CAN controller at the specified speed and clock frequency
  // In this case 125kbps with a 16MHz oscillator
  // (Note:  This is the oscillator attached to the MCP2515, not the Arduino oscillaltor)
  int baudRate=CAN.Init(125,16);
  if(baudRate>0) {
    Serial.println("MCP2515 Init OK ...");
    Serial.print("Baud Rate (kbps): ");
    Serial.println(baudRate,DEC);
  } else {
    Serial.println("MCP2515 Init Failed ...");
  }

  Serial.println("Ready ...");
}

byte i=0;

// CAN message frame (actually just the parts that are exposed by the MCP2515 RX/TX buffers)
Frame message;

void loop() {
  
  message.id = 0;
  
  // This implementation utilizes the MCP2515 INT pin to flag received messages or other events
  if(CAN.Interrupt()) {
    // determine which interrupt flags have been set
    byte interruptFlags = CAN.Read(CANINTF);
    
    if(interruptFlags & RX0IF) {
      // read from RX buffer 0
      message = CAN.ReadBuffer(RXB0);
    }
    if(interruptFlags & RX1IF) {
      // read from RX buffer 1
      message = CAN.ReadBuffer(RXB1);
      // (this is poor code as clearly if two messages are received then the second will overwrite the first)
    }
    if(interruptFlags & TX0IF) {
      // TX buffer 0 sent
    }
    if(interruptFlags & TX1IF) {
      // TX buffer 1 sent
    }
    if(interruptFlags & TX2IF) {
      // TX buffer 2 sent
    }
    if(interruptFlags & ERRIF) {
      // error handling code
    }
    if(interruptFlags & MERRF) {
      // error handling code
      // if TXBnCTRL.TXERR set then transmission error
      // if message is lost TXBnCTRL.MLOA will be set
    }
  }
  
  if(message.id>0) {
    // Print message
    Serial.print("ID: ");
    Serial.println(message.id,HEX);
    Serial.print("Extended: ");
    if(message.ide) {
      Serial.println("Yes");
    } else {
      Serial.println("No");
    }
    Serial.print("DLC: ");
    Serial.println(message.dlc,DEC);
    for(i=0;i<message.dlc;i++) {
      Serial.print(message.data[i],HEX);
      Serial.print(" ");
    }
    Serial.println();

    // Send out a return message for each one received
    // Simply increment message id and data bytes to show proper transmission
    // Note:  Please see explanation at top of sketch.  You might want to comment this out!
    message.id++;
    for(i=0;i<message.dlc;i++) {
      message.data[i]++;
    }
    CAN.LoadBuffer(TXB0, message);
    CAN.SendBuffer(TXB0);
  }
}
Logged

0
Offline Offline
Jr. Member
**
Karma: 1
Posts: 91
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The above is the latest revision of my code.  I've added in an AutoBaud rate feature that works, but is a little clunky code wise.  It requires that there are at least two active nodes on the bus, (not including the one you're using), and they must send messages at least every half second.  It starts at a baud rate of 5kbps and goes up in increments of 5kbps until it reaches 1000kbps, (max rate for CAN V2.0B).  This means that it could take nearly two minutes to detect the baud rate being used by the bus.

It does have a simple to use initialization routine though that simply requires a baud rate, (zero for AutoBaud), and a clock frequency, (frequency of MCP2515 oscillator, not Arduino).  It then calculates out the proper bit timing for you.

Any comments or suggestions on the code would be welcome.  Right now I'm waiting for a version 1.1 PCB, but I have the v1.0 shield pictured up and running just fine connected to SepEx motor controller at 125kbps.  It happily streams data all day long.  If the code doesn't work for you I'd be interested to know so that I can make it more universal.
« Last Edit: December 10, 2010, 12:03:33 am by DaveAK » Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 2
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Im trying to make my own CAN shield and eventually an complete unit with atmega mcu and can controller and tranceiver.

I have a working beta version of the hardware, and got the canbus working with the library from: www.kreatives-chaos.com/artikel/universelle-can-bibliothek

But as soon as i try to add a filter it all goes badly. either no message gets through or all messages gets through.
This is my filter code:

Code:
       // create a new filter for receiving messages
        can_filter_t filter = {
                .id = 0x1ff,
                .mask = 0x7ff,
                .flags = {
                        .rtr = 0,
                        .extended = 0
                }
        };

        can_set_filter(0, &filter);

        can_init(BITRATE_1_MBPS);

This is done in the init part of the program,
Is anything else needed to activate the filters ?

the sending-part of my program that sends the message looks like this:

Code:
               can_t msg;
                msg.id = 0x7FF;
                msg.flags.rtr = 0;
                msg.flags.extended = 0;
                msg.length = 4;
                msg.data[0] = 0xde;
                msg.data[1] = 0xad;
                msg.data[2] = 0xbe;
                msg.data[3] = 0xef;
                can_send_message(&msg);

This message is still received, even though the id = 0x1ff should ignore it in the filter as i understand it.
« Last Edit: December 15, 2010, 04:36:07 pm by Riiiis » Logged

0
Offline Offline
Jr. Member
**
Karma: 1
Posts: 91
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

From what I can gather from a quick glance at the data sheet and your code the filter works on the first two data bytes of a standard frame, not the message ID.  I think you're trying to filter on the message ID, but you're using a standard frame, so this won't work.

If you use an extended frame then the mask applies to the full 29 bit ID field.

The mask you have requires an exact match between the message ID and the filter - i.e. only one specific message ID will be received.  I think your test code is correct, (i.e. you're right and the message should be rejected), but again, it comes down to using a standard ID instead of an extended ID.

See figure 4-4 on page 32 of the MCP2515 datasheet.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 4
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Would you be willing to share your schematic and/or eagle files? I'm trying to start up a similar project, and could use a decent reference.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 2
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

My prototype is a small (2,5 x 5 cm) shield for the arduino, which just fits the mcp2515 and a can tranceiver (both can be sampled from TI afair). All is done with smd components and pinheaders through hole, as i think thats easiest. The shield's size makes all the analog and half of the digital i/o pins available when the shield is on.

I can upload the eagle files if you want
« Last Edit: December 17, 2010, 09:47:05 am by Riiiis » Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 5
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello RiiiisDK! I would be very interessted in seeing your design.
I am searching especially for a small desing  for an Arduino Mini pro project.

cheers,
Michael
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 5
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello!
I get a lot of errors when trying to compile Dave AKs Code:

Code:
C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp: In member function 'void MCP2515::Reset()':

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:153: error: expected unqualified-id before '.' token

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp: In member function 'byte MCP2515::Read(byte)':

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:159: error: expected unqualified-id before '.' token

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:160: error: expected unqualified-id before '.' token

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:161: error: expected primary-expression before '.' token

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp: In member function 'void MCP2515::Read(byte, byte*, byte)':

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:170: error: expected unqualified-id before '.' token

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:171: error: expected unqualified-id before '.' token

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:173: error: expected primary-expression before '.' token

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp: In member function 'Frame MCP2515::ReadBuffer(byte)':

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:186: error: expected unqualified-id before '.' token

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:187: error: expected primary-expression before '.' token

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:188: error: expected primary-expression before '.' token

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:189: error: expected primary-expression before '.' token

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:190: error: expected primary-expression before '.' token

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:191: error: expected primary-expression before '.' token

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:208: error: expected primary-expression before '.' token

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp: In member function 'void MCP2515::Write(byte, byte)':

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:217: error: expected unqualified-id before '.' token

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:218: error: expected unqualified-id before '.' token

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:219: error: expected unqualified-id before '.' token

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp: In member function 'void MCP2515::Write(byte, byte*, byte)':

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:227: error: expected unqualified-id before '.' token

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:228: error: expected unqualified-id before '.' token

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:230: error: expected unqualified-id before '.' token

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp: In member function 'void MCP2515::SendBuffer(byte)':

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:238: error: expected unqualified-id before '.' token

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp: In member function 'void MCP2515::LoadBuffer(byte, Frame)':

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:272: error: expected unqualified-id before '.' token

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:273: error: expected unqualified-id before '.' token

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:274: error: expected unqualified-id before '.' token

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:275: error: expected unqualified-id before '.' token

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:276: error: expected unqualified-id before '.' token

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:277: error: expected unqualified-id before '.' token

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:280: error: expected unqualified-id before '.' token

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp: In member function 'byte MCP2515::Status()':

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:287: error: expected unqualified-id before '.' token

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:288: error: expected primary-expression before '.' token

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp: In member function 'byte MCP2515::RXStatus()':

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:305: error: expected unqualified-id before '.' token

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:306: error: expected primary-expression before '.' token

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp: In member function 'void MCP2515::BitModify(byte, byte, byte)':

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:331: error: expected unqualified-id before '.' token

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:332: error: expected unqualified-id before '.' token

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:333: error: expected unqualified-id before '.' token

C:\Dokumente und Einstellungen\WW\Desktop\[PROJEKTE]\arduino-0018\libraries\MCP2515\MCP2515.cpp:334: error: expected unqualified-id before '.' token

Any ideas where to look at?
Would it be possible to post the code in file form?


Regards,
Michael
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 5
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

hi.
Seems to work on Arduino 0021.
Sorry for the confusion, I would be intressted in dem SMT design thought.
Thanks a lot to all for all the effort.

regards,
Michael
Logged

0
Offline Offline
Full Member
***
Karma: 0
Posts: 106
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You are so right the projects never end.
I'll have to email that to a few people make there days as great as mine also great job.





      MakerMann
Logged

Pages: [1] 2   Go Up
Jump to: