Another fork of FlexCAN

What sort of functions are you looking for specifically? Would it be helpful to have a function that takes a byte and bit and returns that bit? Or, a byte and a bit range and returns the value (shifted to be based at 0)? Or, maybe even treating the 8 bytes within a CAN frame as a 64 bit value? What is bit 43? What is bit 10? What value is formed by bits 13-16? Problems become apparent if you want to get a value from within the CAN data which is longer than 8 bits. Then endian issues come in and it gets messy. I can write all those functions (and, in fact pretty much have in SavvyCAN) but I'd need to know what kind of stuff would be helpful to you and others.

I don't think this is a necessary idea. As Bitwise operations are not CAN-specific and I am not a fan of bloated libraries. Not that this would add much, but there is a point of diminishing returns. Eventually, you end up with a giant library that has tens of functions that should really be in their own class rather than serving no purpose except to specific users.

Learning bitwise operations is always handy and really isn't that difficult. The macros are already there for bitRead/bitWrite/bitSet/bitClear. What else would be necessary?

I have been using this library and it's simply fantastic. It works well and serves its intended purpose.
 
Yeah, bitwise functionality almost certainly doesn't belong in a CAN library but I could write some simple routines and make a header or something that people could download separately. But, you're also right, it's good experience to do this yourself so that you understand what is going on. Anyone who gets heavily into CAN is going to need to learn about bits and bytes and how it all lines up and works.
 
I am really struggling with the filters and masks.

The ObjectOrientedCANExtendedIDs.ino example sets filters for mailboxes 4 though to 15, but doesn't do anything with the mask for those mailboxes. If the default mask is 0, surely any filters that are set do nothing?
I am playing with the code but can't seem to get any logical behaviour.
I'm also not sure why all 16 mailboxes should be set, as I thought the last two default as TX boxes and masks and filters do not apply to TX?
If I set all 16 mailboxes to filter an ID I get no messages, if I set .ext to 0 I get all 6 Id's that are on my bus.

Is there any example for setting of mailbox masks and the default mask? I have tried for a few hours and just can seem to get them to do anything!
An example of some mailboxes filtering for specific 11-bit ID's, some mailboxes filtering for specific 29-bit ID's, and some mailboxes filtering for a small range of ID's would really really help.

Any pointers really appreciated.

Darcy.
 
A little more persistence and I have some working filters. The extended ID example filters are filtering out the 11-bit ID's, and when the individual masks are set, I am getting 29-bit ID's messages into their specific higher mailboxes.

On another note:
Something I have noticed with some small Chinese transceiver break-outs on E-bay is multiple sellers have put the resistors in the wrong place, swapping the 10kohm (labelled 103) and termination 120 ohm (labelled 121). I have re-worked a pair that I got, but it is a real PITA! So my advice is study the picture carefully ensuring the resistor labelled 121 is nearest the CAN+ and CAN- through-holes. They should still work as supplied but you will need to add a termination (if you haven't got them elsewhere on your bus) and the slew-rate will be in un-controlled mode which may not be desirable.

Darcy.
 
Is there any example for setting of mailbox masks and the default mask? I have tried for a few hours and just can seem to get them to do anything!
An example of some mailboxes filtering for specific 11-bit ID's, some mailboxes filtering for specific 29-bit ID's, and some mailboxes filtering for a small range of ID's would really really help.
....
A little more persistence and I have some working filters. The extended ID example filters are filtering out the 11-bit ID's, and when the individual masks are set, I am getting 29-bit ID's messages into their specific higher mailboxes.

Any chance you could turn this into a self-contained example and contribute it to the library? I'm sure it would really help others who try to do the same later.
 
Hi! Great library. It has worked very well on teensy 3.2 and I like that I don't need to do any polling. Just got a teensy 3.6 and got it working very fast and was able to do a successful BUS splitting having the teensy act as a bridge and change messages, calculate new CRC values and send them out in realtime in a 50% saturated 1000000bps Can BUS. Amazing!

Only small question. I wasn't able to figure out what is the correct command for starting CAN0, with alternate pins on the teensy 3.6. Tried different pins , but was unsuccessful.
 
OK, here is my contained example of Filters, masks and Mailboxes. It may be flawed, I have no experience of CAN, or programming code, and my process is cut, paste, test, Does it work? If the answer is no, I apply more wine, and try again....

I had real problems mixing standard and extended ID masks, and my solution was to throw some bit-shifting in randomly, 16 bits kind-of worked sometimes. 18bits seemed like a sensible number to try...
I have tried to document it to a point that it would be useful to somebody (dumb) like myself.

I'm not totally happy with it as an example of mailbox use, I really need to apply it now to my project to learn how to utilize it better in the real world, but for now it works!

Code:
 * Object Oriented CAN example for Teensy 3.6 with Dual CAN buses 
 * By Collin Kidder. Based upon the work of Pawelsky and Teachop
 * 
 * Both buses are set to 1 Mbits to show things with a full speed bus.
 * The reception of frames in this example is done via callbacks
 * to an object rather than polling. Frames are delivered as they come in.
 * 
 * This example sets mailbox Masks and Filters to recieve specific individual 
 * message ID's and ranges of message ID's for both 11-bit and 29-bit message ID's
 * 
 * The second CAN port (CAN1) sends many messages:- some we want, and some we do not want.
 * Messages that we want to recieve are loaded with data bytes that just re-states the ID,
 * whereas the messages we do not want are loaded with a 9 9 9 9 9 9 9 9 message to help spot
 * these unwanted messages if they somehow get through the masks and filters and are accidentally 
 * received.
 * 
 * The following message ID's are sent on the Bus, unwanted messages are highlighted thus: ***
 * 0xF003D0
 * 0xF003C6
 * 0xF003D9
 * 0xF003B6 ***
 * 0xF003E9 ***
 * 0x2      ***
 * 0x3      ***
 * 0x4      ***
 * 0x5
 * 0x6      ***
 * 0x7      ***
 * 0x8      ***
 * 0x13
 * 0x14
 * 0x15
 * 0x16
 * 0x113
 * 0x114
 * 0x115
 * 0x116
 * 
 */

#include <FlexCAN.h>

#ifndef __MK66FX1M0__
  #error "Teensy 3.6 with dual CAN bus is required to run this example"
#endif

static CAN_message_t msg0,msg1;

elapsedMillis RXtimer;
elapsedMillis LEDtimer;
uint32_t RXCount = 0;
boolean displayCAN = true;
const uint8_t redLEDpin = 13;
boolean redLEDstate;

class CANClass : public CANListener 
{
public:
   void printFrame(CAN_message_t &frame, int mailbox);
   void gotFrame(CAN_message_t &frame, int mailbox); //overrides the parent version so we can actually do something
};

void CANClass::printFrame(CAN_message_t &frame, int mailbox)
{
  if(displayCAN){
   Serial.print(mailbox);
   Serial.print(" ID: ");
   Serial.print(frame.id, HEX);
   Serial.print(" Data: ");
   for (int c = 0; c < frame.len; c++) 
   {
      Serial.print(frame.buf[c], HEX);
      Serial.write(' ');
   }
   Serial.println();
  }
   RXCount++;
 
}

void CANClass::gotFrame(CAN_message_t &frame, int mailbox)
{
    printFrame(frame, mailbox);
}

CANClass CANClass0;
CANClass CANClass1;

// -------------------------------------------------------------
void setup(void)
{
  delay(1000);
  Serial.println(F("Hello Teensy 3.6 dual CAN Test With Objects."));
  pinMode(redLEDpin,OUTPUT);

 CAN_filter_t defaultMask_1;
 defaultMask_1.rtr=0;
 defaultMask_1.ext=0;
// defaultMask_1.id=0x7FF;
 defaultMask_1.id=0;
  delay(1000);
  
  Can0.begin(1000000,defaultMask_1);  
  Can1.begin(1000000,defaultMask_1);
  Can0.attachObj(&CANClass0);
//  Can1.attachObj(&CANClass1);


/////////////////////////////////////////
////////MASK AND FILTER SETTING//////////

// First we set mailboxes 0 through to 4 to use the standard ID blocking Mask & filter, 
// this checks all ID bits match the filter for the very last Standard ID.    
  CAN_filter_t allBlockStandardFilter;
  allBlockStandardFilter.id=0x7FF;
  allBlockStandardFilter.ext=0;
  allBlockStandardFilter.rtr=0;
  for (uint8_t filterNum = 0; filterNum < 5;filterNum++){
  Can0.setMask(0x7FF<<18,filterNum);   // bit shifting the mask 18 bit positions from standard 11bit to extended 29bit position
  Can0.setFilter(allBlockStandardFilter,filterNum); 
  }

  CAN_filter_t mailbox_Filter;

// MAILBOX 0
  Can0.setMask(0x7F0<<18,0);   // Bit-shifting 18 bits left, mask is checking for a match of all but the last 4 bits.
  mailbox_Filter.id=0x010;     // Filter is looking for zeros in the first 3 bits, ones in the next 4 bits, and the final
  mailbox_Filter.ext=0;        // 4 bits, while declared zeros by this filter, are just ignored by the mask.
  mailbox_Filter.rtr=0;        // Mailbox will recieve ID's 0x010 though 0x01F, or as decimals 16 through 31
  Can0.setFilter(mailbox_Filter,0); 

// MAILBOX 1  
  Can0.setMask(0x7F0<<18,1);   // Duplicate of previous mailbox, this helps capture messages from multiple ID's as a
  mailbox_Filter.id=0x010;     // single mailbox can appear to 'miss' messages if we do not collect them quickly in our code
  mailbox_Filter.ext=0;        // before they get over-written with the next accepted message into that mailbox
  mailbox_Filter.rtr=0;
  Can0.setFilter(mailbox_Filter,1); 
  
// MAILBOX 2
  Can0.setMask(0x700<<18,2);    // bit shifting 18 bits left, mask is checking for a match of the first 3 bits.
  mailbox_Filter.id=0x100;      // Filter is looking for 001 as the first 3 bits, the rest of the ID is masked so remaining
  mailbox_Filter.ext=0;         // 8 bits of the ID can be anything.
  mailbox_Filter.rtr=0;         // Mailbox will recieve ID's 0x100 though 0x1FF, or as decimals 256 through 511
  Can0.setFilter(mailbox_Filter,2);   
  
// MAILBOX 3
  Can0.setMask(0x700<<18,3);    // Duplicate of previous mailbox.
  mailbox_Filter.id=0x100;      
  mailbox_Filter.ext=0;
  mailbox_Filter.rtr=0;
  Can0.setFilter(mailbox_Filter,3);   

// MAILBOX 4
  Can0.setMask(0x7FF<<18,4);    // bit shifting 18 bits left, mask is checking for a match of all 11 bits.
  mailbox_Filter.id=0x005;      // Filter is looking for 0x05, so with a 'full match' requirement defined by the mask,
  mailbox_Filter.ext=0;         // this will be the only ID received in this mailbox.
  mailbox_Filter.rtr=0;
  Can0.setFilter(mailbox_Filter,4);   
    

// now we initially block the rest of the mailboxes to check all ID bits with a full mask
// and a filter for the very last extended ID.  
  CAN_filter_t allBlockExtendedFilter;
  allBlockExtendedFilter.id=0x1FFFFFFF;
  allBlockExtendedFilter.ext=1;                    // Notice: Extended bit is toggled to 1 (was 0 for Standard)
  allBlockExtendedFilter.rtr=0;
  for (uint8_t filterNum = 5; filterNum < 16;filterNum++){
  Can0.setMask(0x1FFFFFFF,filterNum);              // Notice: no bit-shifting for 29-bit Extended ID's!
  Can0.setFilter(allBlockExtendedFilter,filterNum); 
  }

// Now we open up mailboxes 5-9 for the Extended 29bit ID messages we want to receive    

// MAILBOX 5  
  Can0.setMask(0x1FFFFFE0,5);     // No bit-shifting, Mask is hiding the last 5 bits, (or checking the first 24 bits)
  mailbox_Filter.id=0xF003C0;     // Filter is looking for 1111000000000011110 as the first 24 bits of the ID.
  mailbox_Filter.ext=1;           // Message ID's 0xF003C0 through 0xF003DF will be acccepted. (DEC:15729600 to 15729631)
  mailbox_Filter.rtr=0;
  Can0.setFilter(mailbox_Filter,5); 

// MAILBOX 6
  Can0.setMask(0x1FFFFFE0,6);     // Duplicate of previous mailbox to ensure no 'lost' messages
  mailbox_Filter.id=0xF003C0;
  mailbox_Filter.ext=1;
  mailbox_Filter.rtr=0;
  Can0.setFilter(mailbox_Filter,6);

// MAILBOX 7
  Can0.setMask(0x1FFFFFFF,7);     // Mask is 'exposing' all bits to the filter, so an exact match is required in order
  mailbox_Filter.id=0xF014DF;     // for acceptance. Message ID 0xF014DF (Dec: 15733983) will be the only message received.
  mailbox_Filter.ext=1;
  mailbox_Filter.rtr=0;
  Can0.setFilter(mailbox_Filter,7);
  
// MAILBOX 8                      // This is example of an incorrectly set filter
  Can0.setMask(0x1FFFFF00,8);     // Mask is exposing all but the last 8 bits to the filter
  mailbox_Filter.id=0x10;         // Filter is defining: 1000 0000 as last 8 bits, but the mask is ignoring these 8-bits!
  mailbox_Filter.ext=1;           // The first 21 bits of the ID must still be zeros, but as .ext=1 is defining this filter
  mailbox_Filter.rtr=0;           // as EXTENDED ID, filter must be 0x800 (Dec=2048) or greater to be valid.
  Can0.setFilter(mailbox_Filter,8);

// MAILBOX 9
  Can0.setMask(0x1FFFFF00,9);     // Mask is exposing all but the last 8 bits to the filter
  mailbox_Filter.id=0xA00;        // Filter is looking for 1010 in bits 9 through 12, zero's in the higher bits, and anything
  mailbox_Filter.ext=1;           // in the lower bits.
  mailbox_Filter.rtr=0;           // This mailbox will accept ID's 0xA00 through 0xAFF (Dec: 2560 through 2815)
  Can0.setFilter(mailbox_Filter,9);
///////// END OF FILTER AND MASK SETUP //////////
/////////////////////////////////////////////////


// now we attach the mailbox handler routine for all 16 mailboxes  
  for (uint8_t filterNum = 0; filterNum < 16;filterNum++){
     CANClass0.attachMBHandler(filterNum);
     CANClass1.attachMBHandler(filterNum);
  }
  //CANClass0.attachGeneralHandler();
  //CANClass1.attachGeneralHandler();

}

// -------------------------------------------------------------
void loop(void)
{  
  if (RXtimer > 10000){
    Serial.println("Total Received Messages in 10 Sec:");
    Serial.println(RXCount);
    RXtimer = 0;
    RXCount=0;
    displayCAN = !displayCAN;
  }
  if (LEDtimer >250){
    LEDtimer = 0;
    redLEDstate = !redLEDstate;
    digitalWrite(redLEDpin, redLEDstate);
  }

/**************** Code for sending messages out from CAN1 **************/
      msg1.buf[0] = 0;
      msg1.buf[1] = 0;
      msg1.buf[2] = 15;
      msg1.buf[3] = 0;
      msg1.buf[4] = 0;
      msg1.buf[5] = 3;
      msg1.buf[6] = 13;
      msg1.buf[7] = 0;
      msg1.ext = 1;
      msg1.id = 0xF003D0;
      msg1.len = 8;   
      Can1.write(msg1);
 delay(2);     
      msg1.buf[0] = 0;
      msg1.buf[1] = 0;
      msg1.buf[2] = 15;
      msg1.buf[3] = 0;
      msg1.buf[4] = 0;
      msg1.buf[5] = 3;
      msg1.buf[6] = 12;
      msg1.buf[7] = 6;
      msg1.ext = 1;
      msg1.id = 0xF003C6;   
      msg1.len = 8; 
      Can1.write(msg1);
delay(2);     
      msg1.buf[0] = 0;
      msg1.buf[1] = 0;
      msg1.buf[2] = 15;
      msg1.buf[3] = 0;
      msg1.buf[4] = 0;
      msg1.buf[5] = 3;
      msg1.buf[6] = 13;
      msg1.buf[7] = 9;
      msg1.ext = 1;
      msg1.id = 0xF003D9;
      msg1.len = 8;   
      Can1.write(msg1);
delay(2);

///////////////////////////////////////////
////// START OF MESSAGES WE DONT WANT /////     
      msg1.buf[0] = 9;
      msg1.buf[1] = 9;
      msg1.buf[2] = 9;
      msg1.buf[3] = 9;
      msg1.buf[4] = 9;
      msg1.buf[5] = 9;
      msg1.buf[6] = 9;
      msg1.buf[7] = 9;
      msg1.ext = 1;
      msg1.id = 0xF003B6;
      msg1.len = 8;   
      Can1.write(msg1);      
delay(2);      
      msg1.buf[0] = 9;
      msg1.buf[1] = 9;
      msg1.buf[2] = 9;
      msg1.buf[3] = 9;
      msg1.buf[4] = 9;
      msg1.buf[5] = 9;
      msg1.buf[6] = 9;
      msg1.buf[7] = 9;
      msg1.ext = 1;
      msg1.id = 0xF003E9;
      msg1.len = 8;   
      Can1.write(msg1); 
delay(2);       
      msg1.buf[0] = 9;
      msg1.buf[1] = 9;
      msg1.buf[2] = 9;
      msg1.buf[3] = 9;
      msg1.buf[4] = 9;
      msg1.buf[5] = 9;
      msg1.buf[6] = 9;
      msg1.buf[7] = 9;
      msg1.ext = 0;
      msg1.id = 0x2;
      msg1.len = 8;   
      Can1.write(msg1);           
delay(2);      
      msg1.buf[0] = 9;
      msg1.buf[1] = 9;
      msg1.buf[2] = 9;
      msg1.buf[3] = 9;
      msg1.buf[4] = 9;
      msg1.buf[5] = 9;
      msg1.buf[6] = 9;
      msg1.buf[7] = 9;
      msg1.ext = 0;
      msg1.id = 0x3;
      msg1.len = 8;   
      Can1.write(msg1); 
delay(2); 
      msg1.buf[0] = 9;
      msg1.buf[1] = 9;
      msg1.buf[2] = 9;
      msg1.buf[3] = 9;
      msg1.buf[4] = 9;
      msg1.buf[5] = 9;
      msg1.buf[6] = 9;
      msg1.buf[7] = 9;
      msg1.ext = 0;
      msg1.id = 0x4;
      msg1.len = 8;    
      Can1.write(msg1); 
delay(2);     
      msg1.buf[0] = 9;
      msg1.buf[1] = 9;
      msg1.buf[2] = 9;
      msg1.buf[3] = 9;
      msg1.buf[4] = 9;
      msg1.buf[5] = 9;
      msg1.buf[6] = 9;
      msg1.buf[7] = 9;
      msg1.ext = 0;
      msg1.id = 0x6;
      msg1.len = 8;    
      Can1.write(msg1); 
delay(2);      
      msg1.buf[0] = 9;
      msg1.buf[1] = 9;
      msg1.buf[2] = 9;
      msg1.buf[3] = 9;
      msg1.buf[4] = 9;
      msg1.buf[5] = 9;
      msg1.buf[6] = 9;
      msg1.buf[7] = 9;
      msg1.ext = 0;
      msg1.id = 0x7;
      msg1.len = 8;    
      Can1.write(msg1); 
delay(2);      
      msg1.buf[0] = 9;
      msg1.buf[1] = 9;
      msg1.buf[2] = 9;
      msg1.buf[3] = 9;
      msg1.buf[4] = 9;
      msg1.buf[5] = 9;
      msg1.buf[6] = 9;
      msg1.buf[7] = 9;
      msg1.ext = 0;
      msg1.id = 0x8;
      msg1.len = 8;    
      Can1.write(msg1); 
delay(2); 
////// END OF MESSAGES WE DONT WANT /////     
////////////////////////////////////////

      
      msg1.buf[0] = 0;
      msg1.buf[1] = 0;
      msg1.buf[2] = 0;
      msg1.buf[3] = 0;
      msg1.buf[4] = 0;
      msg1.buf[5] = 0;
      msg1.buf[6] = 0;
      msg1.buf[7] = 5;
      msg1.ext = 0;
      msg1.id = 0x5;
      msg1.len = 8;   
      Can1.write(msg1);       
delay(2);     
      msg1.buf[0] = 0;
      msg1.buf[1] = 0;
      msg1.buf[2] = 0;
      msg1.buf[3] = 0;
      msg1.buf[4] = 0;
      msg1.buf[5] = 0;
      msg1.buf[6] = 1;
      msg1.buf[7] = 3;
      msg1.ext = 0;
      msg1.id = 0x13;
      msg1.len = 8;    
      Can1.write(msg1);
delay(2);    
      msg1.buf[0] = 0;
      msg1.buf[1] = 0;
      msg1.buf[2] = 0;
      msg1.buf[3] = 0;
      msg1.buf[4] = 0;
      msg1.buf[5] = 0;
      msg1.buf[6] = 1;
      msg1.buf[7] = 4;
      msg1.ext = 0;
      msg1.id = 0x14;
      msg1.len = 8;    
      Can1.write(msg1);
delay(2);    
      msg1.buf[0] = 0;
      msg1.buf[1] = 0;
      msg1.buf[2] = 0;
      msg1.buf[3] = 0;
      msg1.buf[4] = 0;
      msg1.buf[5] = 0;
      msg1.buf[6] = 1;
      msg1.buf[7] = 5;
      msg1.ext = 0;
      msg1.id = 0x15;
      msg1.len = 8;    
      Can1.write(msg1);
delay(2);    
      msg1.buf[0] = 0;
      msg1.buf[1] = 0;
      msg1.buf[2] = 0;
      msg1.buf[3] = 0;
      msg1.buf[4] = 0;
      msg1.buf[5] = 0;
      msg1.buf[6] = 1;
      msg1.buf[7] = 6;
      msg1.ext = 0;
      msg1.id = 0x16;
      msg1.len = 8;    
      Can1.write(msg1);
delay(2);
      msg1.buf[0] = 0;
      msg1.buf[1] = 0;
      msg1.buf[2] = 0;
      msg1.buf[3] = 0;
      msg1.buf[4] = 0;
      msg1.buf[5] = 1;
      msg1.buf[6] = 1;
      msg1.buf[7] = 3;
      msg1.ext = 0;
      msg1.id = 0x113;
      msg1.len = 8;   
      Can1.write(msg1); 
delay(2);
      msg1.buf[0] = 0;
      msg1.buf[1] = 0;
      msg1.buf[2] = 0;
      msg1.buf[3] = 0;
      msg1.buf[4] = 0;
      msg1.buf[5] = 1;
      msg1.buf[6] = 1;
      msg1.buf[7] = 4;
      msg1.ext = 0;
      msg1.id = 0x114;
      msg1.len = 8;    
      Can1.write(msg1); 
delay(2);
      msg1.buf[0] = 0;
      msg1.buf[1] = 0;
      msg1.buf[2] = 0;
      msg1.buf[3] = 0;
      msg1.buf[4] = 0;
      msg1.buf[5] = 1;
      msg1.buf[6] = 1;
      msg1.buf[7] = 5;
      msg1.ext = 0;
      msg1.id = 0x115;
      msg1.len = 8;    
      Can1.write(msg1); 
delay(2);
      msg1.buf[0] = 0;
      msg1.buf[1] = 0;
      msg1.buf[2] = 0;
      msg1.buf[3] = 0;
      msg1.buf[4] = 0;
      msg1.buf[5] = 1;
      msg1.buf[6] = 1;
      msg1.buf[7] = 6;
      msg1.ext = 0;
      msg1.id = 0x116;
      msg1.len = 8;   
      Can1.write(msg1); 
delay(2);
}
 
Last edited:
I now have Collin's Flexcan working with SDfat beta, and can log one CAN channel to a Class 4 card. Most sketches I've seen write .csv files but I've gone for a binary write and use the Bin2Csv function to convert after logging. I can get just over 7800 Can messages logged every second which I think is a 1Mbit bus absolutely flat-out, fully loaded. File conversion takes almost as long as the capture period, but I wanted to capitalize on the fact that a 32bit timestamp + 32 bit ID + 8byte payload is 16 bytes, which gives a nice 32 msg 512byte block to write. I intend to byte-stuff all messages that are shorter than 8 bytes, and guess I may find a 'gotcha' when I come to do this!

My code is really poor quality (newbie), and I'm only using 34% of the dynamic memory, so I'm guessing it might be possible to get both Channels logged simultaneously, at 1Mbits/s without any frame-loss.
I will try to add filter and mask setting from a text file on the micro-SD, and will put my code up if anyone is desperate for it. I'm sure there will be better code elsewhere, (google Macchina M2 for a possible source) but at the time of writing, there seems to be very few examples for T3.6 with CAN and with SD.

Darcy.
 
I found it advantageous to add another data field for microseconds when logging data on CAN. If you use a 32bit word, there will be some of the unused MSBs that don't deviate from zero when tracking the microseconds per second. You can used a bit mask and shift to use this space to keep track of which channel you are using. I made a real brief demo of the microsecond timer here: https://github.com/Heavy-Vehicle-Ne...dsPerSecond/Example_MicrosecondsPerSecond.ino
 
Only assigning one mailbox, only receives once?

OK, here is my contained example of Filters, masks and Mailboxes. It may be flawed, I have no experience of CAN, or programming code, and my process is cut, paste, test, Does it work? If the answer is no, I apply more wine, and try again....

I had real problems mixing standard and extended ID masks, and my solution was to throw some bit-shifting in randomly, 16 bits kind-of worked sometimes. 18bits seemed like a sensible number to try...
I have tried to document it to a point that it would be useful to somebody (dumb) like myself.

I'm not totally happy with it as an example of mailbox use, I really need to apply it now to my project to learn how to utilize it better in the real world, but for now it works!

Hello, and thanks for the code - It's helping me understand quite a bit about this CAN bussiness.

The library I'm using is the one found at https://github.com/collin80/FlexCAN_Library/tree/master

I'm relatively new to CAN (this is day 3) and I'm plugging around on the examples and slowly making headway, but I'm having trouble with this whole hardware filtering thing, and I admit, I don't fully understand it. For example, I just don't see how the canbus filter and canbus mask aren't redundant. I'll figure out that part I'm sure, but here's my problem at the moment, using Darcy's code above with a fancy joystick out of a fancy backhoe- It's streaming out two codes, one every 20ms (0xCFDD696), and another every 1000ms (0x18FECA96)

1. When I only set ONE mailbox to receive EITHER particular message ID, it receives it ONCE, then never again until I reboot the Teensy.
2. When I set TWO mailboxes to receive THE SAME particular message ID, it receives it always, alternating around in both mailboxes. This is done to not miss messages I guess.
3. When I set ONE mailbox to receive a particular message ID, and ONE mailbox to receive a DIFFERENT particular ID, I get both messages, but only every 1000ms, which is the two of the slower messages.
4. When I set ONE mailbox to receive the slow 0x18FECA96 message, and two to receive the 20 mSec 0xCFDD696 message, I get a beautiful stream of messages, where nobody gets left behind. My fast message alternates between the two identical mailboxes, and the slow message pops in to IT'S single mailbox.

AM I missing some kind of command that's marking a particular mailbox as read? The handlers are left as-is in the code from Darcy -

Code:
class CANClass : public CANListener 
{
public:
   void printFrame(CAN_message_t &frame, int mailbox);
   bool frameHandler(CAN_message_t &frame, int mailbox, uint8_t controller); //overrides the parent version so we can actually do something
};

void CANClass::printFrame(CAN_message_t &frame, int mailbox)
{
  if(displayCAN){
   Serial.print(mailbox);
   Serial.print(" ID: ");
   Serial.print(frame.id, HEX);
   Serial.print(" Data: ");
   for (int c = 0; c < frame.len; c++) 
   {
      Serial.print(frame.buf[c], HEX);
      Serial.write(' ');
   }
   Serial.println();
  }
   RXCount++;
 
}

bool CANClass::frameHandler(CAN_message_t &frame, int mailbox, uint8_t controller)
{
    printFrame(frame, mailbox);

    return true;
}

This is the only change to the code, aside from a baud rate change, and my changes are really only addresses....

Code:
// Now we open up mailboxes 5-9 for the Extended 29bit ID messages we want to receive    

// MAILBOX 5  
  Can0.setMask(0x1FFFFFFF,5);     // Mask is 'exposing' all bits to the filter, so an exact match is required in order
  mailbox_Filter.id=0x18FECA96;     // Filter is looking for my exact match.
  mailbox_Filter.ext=1;           
  mailbox_Filter.rtr=0;
  Can0.setFilter(mailbox_Filter,5); 

// MAILBOX 6
  Can0.setMask(0x1FFFFFE0,6);     // I'm not doing anything with this mailbox. 
  mailbox_Filter.id=0xF003C0;     // of this ID. 
  mailbox_Filter.ext=1;
  mailbox_Filter.rtr=0;
  Can0.setFilter(mailbox_Filter,6);

// MAILBOX 7
  Can0.setMask(0x1FFFFFFF,7);     // Mask is 'exposing' all bits to the filter, so an exact match is required in order
  //mailbox_Filter.id=0xF014DF;
  mailbox_Filter.id=0xCFDD696;     // Lookinf for my 20 ms message 0xCFDD696
  mailbox_Filter.ext=1;
  mailbox_Filter.rtr=0;
  Can0.setFilter(mailbox_Filter,7);
  
// MAILBOX 8                      // and again, the 20 ms message
  Can0.setMask(0x1FFFFFFF,8);     // Filter is looking for my exact match.
  mailbox_Filter.id=0xCFDD697;    // Just set this to SOMETHING to make it NOT match. Changed last digit. 
  mailbox_Filter.ext=1;           
  mailbox_Filter.rtr=0;           
  Can0.setFilter(mailbox_Filter,8);


When I'm running in case four, I get this, which is kind of what I want, but I'm not crazy about it because
7 ID: CFDD696 Data: FF FF 1 0 FF 0 FC FF
8 ID: CFDD696 Data: FF FF 1 0 FF 0 FC FF
7 ID: CFDD696 Data: FF FF 1 0 FF 0 FC FF
8 ID: CFDD696 Data: FF FF 1 0 FF 0 FC FF
7 ID: CFDD696 Data: FF FF 1 0 FF 0 FC FF
8 ID: CFDD696 Data: FF FF 1 0 FF 0 FC FF
7 ID: CFDD696 Data: FF FF 1 0 FF 0 FC FF
8 ID: CFDD696 Data: FF FF 1 0 FF 0 FC FF
5 ID: 18FECA96 Data: 0 FF 0 0 0 0 FF FF
7 ID: CFDD696 Data: FF FF 1 0 FF 0 FC FF
8 ID: CFDD696 Data: FF FF 1 0 FF 0 FC FF

I guess I don't have any problem with using two mailboxes for absolutely every ID I need, but if that's the case, why on earth would we even be able to specify one mailbox?

At any rate, I think I'm not not "resetting" something properly. Does anybody have any feedback?

Thanks!!
 
I now have Collin's Flexcan working with SDfat beta, and can log one CAN channel to a Class 4 card. Most sketches I've seen write .csv files but I've gone for a binary write and use the Bin2Csv function to convert after logging. I can get just over 7800 Can messages logged every second which I think is a 1Mbit bus absolutely flat-out, fully loaded. File conversion takes almost as long as the capture period, but I wanted to capitalize on the fact that a 32bit timestamp + 32 bit ID + 8byte payload is 16 bytes, which gives a nice 32 msg 512byte block to write. I intend to byte-stuff all messages that are shorter than 8 bytes, and guess I may find a 'gotcha' when I come to do this!

My code is really poor quality (newbie), and I'm only using 34% of the dynamic memory, so I'm guessing it might be possible to get both Channels logged simultaneously, at 1Mbits/s without any frame-loss.
I will try to add filter and mask setting from a text file on the micro-SD, and will put my code up if anyone is desperate for it. I'm sure there will be better code elsewhere, (google Macchina M2 for a possible source) but at the time of writing, there seems to be very few examples for T3.6 with CAN and with SD.

Darcy.

You have an example of this anywhere? It seems like exactly what I am trying to do.
 
You have an example of this anywhere? It seems like exactly what I am trying to do.

I've moved my 'mostly-functioning' code into my main project with the rest of my hardware and code so it is now really not a good candidate for an example. (5000 lines spread across a dozen tabs).

I still haven't tried to set up a second Can Bus channel to see if my code has problems logging two full-speed buses, but for me the second bus is a nice-to-have and hence is low on my to-do list.

I have got the masks and filters reading from a csv file on the SD card and could post that bit of code if you would like. (It's not elegant or very clever but does work as long as the csv file is exactly what it expects to see - ie, no additional spaces or carriage returns in the wrong place.

W.r.t. the message buffering and logging to SD, I could try to extract the bits of code if you would like to see how not to do it! I have multiple structs and a counter to know how many structs are ready to write to SD. It's probably 100 lines of code that could be written in 3 lines by someone who can code...

I'm pretty sure I should be using an IOstream, but I've yet to find an example recipe that I can copy, paste and add salt.

darcy.
 
It's working. Complete decode of the CAN stream, then encoding per the dashboard's Serial spec.

My only issue is that after about 45 seconds the Teensy that is acting as the bridge locks up. I think the serial buffers are getting overrun. I don't need 1m/sec over serial, so I am thinking that I'll buffer a bit of data, average it, then send it.

Without this library and Colin's hard work, I'd never have gotten it this far.

This community truly is amazing. Thank you all so very much!
 
hi detroit_aristo, unlike the canbus info in the other thread, the uart can be beneficial in -threading to prevent the buffer overflow of the uart. i use it to pull boot msgs from a rooted console which blasts thousands of characters to the uart line during bootup of the device, and display it on the serial monitor as well, when needed
 
hi detroit_aristo, unlike the canbus info in the other thread, the uart can be beneficial in -threading to prevent the buffer overflow of the uart. i use it to pull boot msgs from a rooted console which blasts thousands of characters to the uart line during bootup of the device, and display it on the serial monitor as well, when needed

I am trying to wrap my head around a serialhelper class that handles all the serial stream writes to avoid the issue I am seeing. As this is a critical part of the implementation of the bridge, Any advice you can give would be greatly appreciated.
 
i have 2 displays on 2 separate serial ports. running non modified library for the displays. what i did instead of putting mutex locks throughout my entire 75k code I wrote a centralized function using references, and pointers, to open a mutex and send it to the proper class which writes the uart screen, then releases mutex for the other callers. i only had to point my serial calls to the new function which uses the ref/pointers/mutex, after this it was very easy to do anything to my code without moving around or adding more mutex scopes, and dropping functions in any thread i choose

i can show you an example of the centralized mutex function for my canbus and/lcd if you want, even my port expander (8xmcp23s17) has a centralized mutex function, all reads/writes are automatically done with a mutex so it doesnt matter what thread your in, you only do a read/wrie to the chip and its done
 
Not working on a Teensy 3.1

Hi Guys,

I'm trying to get this new FlexCAN library to work on a Teensy 3.1 board but I'm not Receiving any packets for some reason.

I tried to use the Rx-SingleBus-WithObjects example and the only modification I did was to change the baud to 125000

Code:
//  Can0.begin(500000);  
  Can0.begin(125000);

I tried two different Teensy 3.1s and several different transceivers - no luck.

So then I went and looked up the old library that was pre-3.5/3.6 support and download from here:

https://github.com/teachop/FlexCAN_Library/tree/master, I renamed the Class to FlexCANv1 so I could toggle between the two versions and the old one works but the new one doesn't.

There must be something different about CAN on the 3.1 vs the 3.5/3.6 that its not happy about now... :(

Can someone verify that this latest library works on their Teensy 3.1 please?

Regards

Alex Shepherd
 
It works with Teensy 3.1/3.2 (TD 1.36 version and GIT version work). Are you mixing versions? The RX callback name has changed from 'gotFrame(...)' to 'frameHandler(...)'.
 
It works with Teensy 3.1/3.2 (TD 1.36 version and GIT version work). Are you mixing versions? The RX callback name has changed from 'gotFrame(...)' to 'frameHandler(...)'.

Yeah well I think it may be a version thing as I'm running TD 1.6.7 because I also have a T3.6, but I wanted to use the T3.1s for a CAN to USB adaptor - be a waste of a good T3.6 just for that and I have the T3.1s not doing anything... ;)

Anyway I eliminated that as an issue by stripping the code right back to just 3 library calls:

FlexCAN CANbus(125000);
CANbus.begin();
CANbus.read(rxmsg)

Below is my current sketch, which I can toggle between the FlexCAN library that comes with TD 1.6.7 and the older one I downloaded and renamed to FlexCANv1 by commenting/uncommenting the line:

//#define USE_V1_LIB

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.
//

#define USE_V1_LIB
#ifndef USE_V1_LIB
#include <FlexCAN.h>
FlexCAN CANbus(125000);
#else
#include <FlexCANv1.h>
FlexCANv1 CANbus(125000);
#endif

static CAN_message_t msg,rxmsg;
static uint8_t hex[17] = "0123456789abcdef";

// -------------------------------------------------------------
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)
{
  CANbus.begin();

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


// -------------------------------------------------------------
void loop(void)
{
  while ( CANbus.read(rxmsg) )
  {
    Serial.print("Packet: ");
    Serial.print(rxmsg.id, HEX);
    Serial.print('-');
   
    hexDump( rxmsg.len, (uint8_t *)rxmsg.buf );
  }
}

Next step will be to get the T3.6 out and solder some pins onto it and try that with the same code.

I wonder if there is a pin mapping issue that crept in with all the other code changes for the T3.6 support.

Regards

Alex Shepherd
 
That's wrong. Use the predefined Can0 / Can1 objects and CanX.begin(frequency).

Your sketch works with Teensy 3.2, if I change that.

Hmmm... well I changed my code to remove the Constructor for the TD library and renamed the variable for the other library to Can0 but I still can't get it to work with the TD library... See my code below

Could it be a difference between T3.1 and T3.2? I'll try the T3.6 tonight when I get more time.

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.
//

#define USE_V1_LIB
#ifndef USE_V1_LIB
#include <FlexCAN.h>
//FlexCAN CANbus(125000);
#else
#include <FlexCANv1.h>
FlexCANv1 Can0(125000);
#endif

static CAN_message_t msg,rxmsg;
static uint8_t hex[17] = "0123456789abcdef";

// -------------------------------------------------------------
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)
{
#ifdef USE_V1_LIB
  Can0.begin();
#else
  Can0.begin(125000);
#endif
  delay(1000);
  Serial.println(F("Hello Teensy 3.1 CAN Test."));
}


// -------------------------------------------------------------
void loop(void)
{
  while ( Can0.read(rxmsg) )
  {
    Serial.print("Packet: ");
    Serial.print(rxmsg.id, HEX);
    Serial.print('-');
   
    hexDump( rxmsg.len, (uint8_t *)rxmsg.buf );
  }
}
 
Your last sketch works here. Teensy 3.1 should be the same as 3.2, except for bootloader chip and power converter.

TD 1.6.7 that you mentioned, doesn't exist - Arduino 1.6.7 exists but is rather old (the libraries come with TD, not Arduino). What does your build output say, in particular for 'FlexCAN.cpp'?
 
Back
Top