Teensy 3.1 and CAN Bus

I've been watching this with some interest. Excuse the user name, I'm a noob NOT a CAN expert. I have been playing with an Uno and sparkfun CANBUS shield plugged into my Ducati motorbike for a while and now want to scale down the hardware and use my Teensy 3.1. Am i right in thinking I just need an MCP2551 transceiver between the Teensy CANRX/TX and the CANH/L? Once I get the hardware made I'll gladly help test.
 
Probably you already know this, you need to have a terminating resistor between CANH and CANL that go to the bus.

Wire the Teensy to TXD and RXD on the transceiver.

That is a 5V part but will accept the TX from the 3.3V Teensy 3.1 CPU alright. So you need +5 for the transceiver VDD and of course connect the common of the Teensy to VSS on that part.
 
Folks using CAN:

I had a request issue on the GitHub repo to add documentation for CAN transceiver choices. Please if you are using the Teensy3.1 with CAN post here the part that is known to work, or start an issue on the repo identifying the part. There is a bullet list to collect them in the README.

What I am using is Texas Instrument SN65HVD232QDQ1
 
Please if you are using the Teensy3.1 with CAN post here the part that is known to work

I've been succesfully using
TI SN65HVD230D (3.3V)
TI SN65HVD232D (3.3V)
NXP TJA1050T (5V)

All at 1Mbps.

P.S. For one of my projects I've made a small CAN transceiver shield that fits underneath the Teensy board and has CAN, Serial and power pins broken out. It also has 3.3V regulator built in so it can power your Teensy as well.

can_shield.jpg
 
Last edited:
I've made a small CAN transceiver shield that fits underneath the Teensy board and has CAN, Serial and power pins broken out.
Looks pretty darn nice! I used a bare Arduino protoshield PCB that has a SOIC 8 footprint in the corner. Put Teensy in the prototyping area along with a few other things, and a whole lot of nothing. When I can stick with thru-hole I like these guys:
http://www.adafruit.com/products/723
 
Warnings during compilation

Just FYI noticed some warning when compiling the FlexCAN library. Added them on Github (#3 and #4)
 
Help..! I've wired my 3.1 upto a MCP2551 transceiver (and SD card and BT transmitter) but my Motorbike just throws a "CAN ERROR" when I turn it on. Does the flexCAN library send anything into the bus during READs, e.g. some sort of receipt/acknowledgement? With the UNO/sparkfun CANBUS shield I had it set to "listen only".

As far as I know I've wired it all up correctly;

TX on MCP2551 (1) to TX on Teensy (3) - edited
RX on MCP2551 (4) to RX on Teensy (4) - edited

I've then wired up the MCP2551 as per the sparkfun CANBUS shield with a couple of 100 ohm resistors and 560pf capacitors (I've actually used 470pf as I didn't have 560) between CANH/L and GND. I've also connected RS (pin 8 on the MCP2551) to GND via a 4.7k resistor as per sparkfun shield. I've just realised I have NOT added the 0.1uf cap between VCC and GND as per sparkfun shield.

Originally I did accidently manage to connect CANH/L the wrong way round but have since corrected (could this have wrecked the MCP2551 ?).

Any thoughts, I could happily listen into the bus with the UNO/Sparkfun shield?
 
Last edited:
As per datasheet the pins of the chip are named
1 TXD Transmit Data Input
4 RXD Receive Data Output

So you should swap them in your setup (4-4, 1-3).

I know, it is misleading, I almost did my PCBs wrong because of that.
 
I can't even write it down correctly ! I have got them as per your reply, I changed them round but hadn't updated my diagram.

Any more ideas?
 
I can't even write it down correctly ! I have got them as per your reply, I changed them round but hadn't updated my diagram.

Any more ideas?

If you believe your connections are OK (I assume you have GNDs connected as well) then I think you need to come up with a bit more details of the whole setup you are using, the sketch the you have on Teensy etc.

Your motorbike may expect some communication and throws an error if it is not happening. Check what Teensy reads from the bus when you connect to the motorbike.
 
More detail.

I take +12v, GND, CANH and L from the bike. I have a cheap ebay voltage regulator between the 12v/GND from the bike and the teensy's Vin and the MCP2551 supplying 5v. This is built into a lead and is the same lead I used with the UNO/sparkfun shield.

The sketch is just a modified version of the example from the library. This was just to make sure I could read something/anything, but as I say the bike throws an error. I assume the error is either a hardware issue (don't think it is), or the teensy is sending something into the bus that the bike doesn't recognise.


Code:
// -------------------------------------------------------------
// CANtest for Teensy 3.1
// by teachop
//
// This test is talking to a single other echo-node on the bus.
// 6 frames are transmitted and rx frames are counted.
// Tx and rx are done in a way to force some driver buffering.
// Serial is used to print the ongoing status.
//

#include <Metro.h>
#include <FlexCAN.h>

Metro sysTimer = Metro(1);// milliseconds
Metro pauseLed = Metro(500);// milliseconds
Metro runningLed = Metro(100);// milliseconds

boolean toggle = LOW;
int led = 13;
FlexCAN CANbus(500000);
static CAN_message_t msg,rxmsg;
static uint8_t hex[17] = "0123456789abcdef";

int txCount,rxCount;
unsigned int txTimer,rxTimer;


// -------------------------------------------------------------
static void hexDump(uint8_t dumpLen, uint8_t *bytePtr)
{
  uint8_t working;
  while( dumpLen-- ) {
    working = *bytePtr++;
    Serial.write( hex[ working>>4 ] );
    Serial.write( hex[ working&15 ] );
  }
  Serial.write('\r');
  Serial.write('\n');
}


// -------------------------------------------------------------
void setup(void)
{
  Serial.begin(57600);
  CANbus.begin();
  pinMode(led, OUTPUT);
  digitalWrite(led, 1);

  delay(1000);
  Serial.println(F("Hello Teensy 3.1 CAN Test."));

  sysTimer.reset();
}


// -------------------------------------------------------------
void loop(void){
 
   while (!CANbus.available()){
     if (pauseLed.check() ==1){
       digitalWrite(led, toggle); 
       toggle = !toggle; 
     }  
   } 

    if (runningLed.check() ==1){
       digitalWrite(led, toggle); 
       toggle = !toggle; 
    }  
  
  // service software timers based on Metro tick
  if ( sysTimer.check() ) {
    if ( txTimer ) {
      --txTimer;
    }
    if ( rxTimer ) {
      --rxTimer;
    }
  }

  // if not time-delayed, read CAN messages and print 1st byte
  if ( !rxTimer ) {
    while ( CANbus.read(rxmsg) ) {
      hexDump( sizeof(rxmsg), (uint8_t *)&rxmsg );
      Serial.write(rxmsg.buf[0]);
      rxCount++;
    }
  }


}
 
The sketch is just a modified version of the example from the library. This was just to make sure I could read something/anything, but as I say the bike throws an error.

So what does the Teensy read (forget the bike error for now)?

BTW, what is your motorbike CAN bus speed? In the sketch you use 500kbps.
 
Maybe something on the TXD (CPU side) while the Teensy is booting? If it is, and it is from a floating line (not driven by Teensy), a pull-up resistor on the CPU CAN TXD would eliminate that worry.
 
Maybe something on the TXD (CPU side) while the Teensy is booting? If it is, and it is from a floating line (not driven by Teensy), a pull-up resistor on the CPU CAN TXD would eliminate that worry.
Looks to be a pull-up built into that transceiver so never mind...
 
The bus on the bike is 500kbps.
Think I've found the likely cause. There were a couple of traces on the strip board that weren't fully cut. One on the CAN line ! Will test again in the morning. Good job CAN is fault tolerant.
 
I was looking at the prototype of the adapter with room for a DB9. is the intention to support a single CAN bus at at time or all the data lines that normally is routed from OBDII to the DB9:
CAN High J-2284 6
CAN Low J-2284 14
ISO 9141-2 K Line 7
ISO 9141-2 L Line 15
J2850 BUS- 10
J2850 BUS+ 2
 
Logging to the SD card now. Managing to write approx 550 messages a second. Not sure if im capturing all the messages, any idea how i can work out if im missing any?

Might think about having a board made up now as my current strip board solution looks a bit Heath Robinson. Still smaller than my Uno plus sparkfun shield which makes mounting on the bike much easier.

Thanks for all the work people have done on the Library.
 
So the bike appears to generate 590 messages a second if I write a sketch that just counts the number of reads that are possible every second. There seems to be almost no variation from 590 per second either. I seem to only be logging between 450-490 to the SD card (with quiet a bit of variability) with my sketch that writes each message individually after it is read (using SD.h). I'm construct the message into a string like this "25142,110,FF,FF,FF,FF,FF,FF,FF,FF" and write it after every read. Am I hitting the speed limit of the SD card? I've seen talk of needing to write 512 bytes each time to maximise performance of SD card writting, buffering until I amass enough data to write.

Any ideas? Apologies if I'm going off topic.

Code:
// -------------------------------------------------------------
// based on CANtest for Teensy 3.1 example by teachop
//


#include <Metro.h>
#include <FlexCAN.h>
#include <SPI.h>
#include <SD.h>       /* Library from Adafruit.com */

Metro pauseLed = Metro(1000);// milliseconds
unsigned long time;  //used for time stamp
boolean toggleP = LOW;
FlexCAN CANbus(500000);
static CAN_message_t msg,rxmsg;

Sd2Card card;
SdVolume volume;
SdFile root;
SdFile file;

#define SCK_PIN   13  //Clock pin
#define MISO_PIN  12  //Mater in Slave output
#define MOSI_PIN  11  //Master out Slave input
#define SD_PIN    10  //pin for SD card control
//#define led       13

// -------------------------------------------------------------
void setup(void)
{

  Serial.begin(57600);
  Serial1.begin(57600);
  
  CANbus.begin();
  //pinMode(led, OUTPUT);
  pinMode(10, OUTPUT);
  //digitalWrite(led, 1);

  delay(10000);
  Serial.println(F("Hello Teensy 3.1 CAN Test."));
  Serial1.println(F("Serial1 - Hello Teensy 3.1 CAN Test."));
  
 
 //************************* SD CARD SETUP *******************
  // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
  // breadboards.  use SPI_FULL_SPEED for better performance.
  if (!card.init(SPI_FULL_SPEED,SD_PIN)) {
    Serial1.println("ERROR: card.init failed");
  }

  // initialize a FAT volume
  if (!volume.init(&card)) {
    Serial.println("ERROR: volume.init failed");
  }
  
  // open the root directory
  if (!root.openRoot(&volume)) {
    Serial.println("ERROR: openRoot failed");
  }
}


// -------------------------------------------------------------

void loop()
{
  if (!CANbus.available()) {
    Serial1.println("Can bus not available.  Check connections");
  }
  
  while(!CANbus.available()) {
       if (pauseLed.check() ==1){
         //digitalWrite(led, toggleP); 
         toggleP = !toggleP; 
         Serial.println("CAN not available");
         Serial1.println("Serial1 - CAN not available");
       }
  } //waiting for Canbus to be connected
  
  Serial1.println("Can Bus Connected and available");   //only comes out of the above loop if CAN is available
  
  // create a new file
  char name[] = "CANlog00.CSV";
  for (uint8_t i = 0; i < 100; i++) {
    name[6] = i/10 + '0';
    name[7] = i%10 + '0';
    if (file.open(&root, name, O_CREAT | O_EXCL | O_WRITE)) break;
  }
  
  if (!file.isOpen()) {
    Serial.println("file.created");
  }
  Serial1.print("Writing to: ");
  Serial1.println(name);
  file.println("seconds,milliSec, ID, B0, B1, B2, B3, B4, B5, B6, B7"); //, B0(DEC), B1(DEC), B2(DEC), B3(DEC), B4(DEC), B5(DEC), B6(DEC), B7(DEC)");
  //file.println(buffer1);
  //file.println();  
  Serial1.println("Header written to SD Card");  
 
  CAN_Capture();

}//end loop 
 
 
void CAN_Capture(){
  Serial1.println("CAN_Capture loop");  
   while(1){                 //stay within this loop unless forced out
    //if (CANbus.available()) {   //is the CAN available?      assume it is or we wouldn't have got this far.
     if (CANbus.read(rxmsg)){    //while messages are available perform the following
        String CANStr(""); 
        time = millis();  //capture time when message was recieved 
        CANStr +=String(int(time/1000)); 
        CANStr += (",");
        CANStr +=String(time); 
        CANStr += (",");
        CANStr += String(rxmsg.id,HEX); 
        for (int i=0; i < 8; i++) {     
          CANStr += (",") ;
          CANStr += String(rxmsg.buf[i],HEX);
        }

        file.println(CANStr);    //print the CAN message to the file that should already be open
      }
   
     if (rxmsg.id == 0x100){ 
         if (rxmsg.buf[2] == 0x8){  //look for an OFF on the start switch and then stop the logging
         file.close();
         //Serial1.print(name);
         Serial1.println("file closed");
         delay(2000);
            while(1){     //loop until you see the bike turned ON again, then force out of this loop
              //Serial1.println("Waiting for bike to be turned on again");  
              if (CANbus.read(rxmsg)){
                if (rxmsg.id == 0x100 and rxmsg.buf[2] ==0x28){  //look for an ON on the start switch and start logging if it isn't already
                   Serial1.print("id: ");
                   Serial1.print(rxmsg.id);
                   Serial1.print(", byte2: ");
                   Serial1.print(rxmsg.buf[2]);
                   Serial1.println(" detected, about to restart caputure");
                   return;
                }
              } 
            }//end while after capture finishes
         }
    } 
         
  //}
  }
  }
 
This library works really well, I'm using it in my project without any issue. One thing that would be great is being able to specify an interrupt handler where the CAN message could be received in real time instead of having to do polling with the read() function. Any chance this is in the plan teachop ? :)

Thanks for the great library btw!
 
This library works really well, I'm using it in my project without any issue. One thing that would be great is being able to specify an interrupt handler where the CAN message could be received in real time instead of having to do polling with the read() function. Any chance this is in the plan teachop ? :)

Thanks for the great library btw!

That's definitely something I want to add if someone doesn't do it before. I'm busy with other things but if it's not there by the end of June I'll work on it.
 
That's definitely something I want to add if someone doesn't do it before. I'm busy with other things but if it's not there by the end of June I'll work on it.
That is a good idea. I will work on incorporating an IRQ into the driver this weekend. JeanBelanger your help would be much appreciated as it has been already!
 
That is a good idea. I will work on incorporating an IRQ into the driver this weekend. JeanBelanger your help would be much appreciated as it has been already!

Would be good if you find a way to make it configurable. Defining a fixed interrupt vector in the library may make it incompatible with other libraries.
 
Back
Top