FlexCAN_T4 - FlexCAN for Teensy 4

Trying to understand message ID length, 29 bit vs 11 bit .

MCP2551 will read standard 11 bit message ID 0x5FC but this library will read as extended 29 bit message ID 0x17F00010 .
Same network, same data. Sending data in standard format with the library and a SN65HVD23X will keep the 11 bit standard message ID as 0x5FC and online modules will respond correctly.

Why is this, what I'm missing ?
 
the library reads both, that is correct. you probably didnt set the extended flag on the other library but by default both types of mailboxes extended and standard are setup to read the frames on the bus of both types on FlexCAN_T4.
 
Can I set the FlexCan_T4 to only show Standard?
I figured out how to set it whenever I send data but not when receiving.
 
yes if you want only standard frames just change the extended ones to standard. use mailboxStatus() to view the layouts and you'll know which to change. example: myCan.setMB(5, RX, STD)
STD for standard and EXT for extended
 
Hi guys, 1st post (long time Embedded developer, first time teensy user).
I'm doing some benchmarks on CAN-FD for a project - got a couple of teensy 4.1's back-to-back with skpang's breakout.
All working great, even at 12MBits/s, so well done guys!

Question on the timestamps... Any easy way to get the transmit TS? Maybe trigger an INT when message hits the bus to read back the TS?
Would like to get accurate round-trip times and synchronise clocks.

Cheers.
 
yes it may be possible to add transmit callbacks, you can handle your own timestamp in your callback if you wish, unless you want the flexcan one specifically? then it would have to read the MB buffer but not sure if the timestamp is stored on sent, i know the transmit does have interrupt on completion though. testing would need to be done to see if we can read back the data at the time of sent mailbox and maybe return that to user callback (IF the data is still there, and IF the timestamp is modified after transmit)
 
1) set boards manager to 3.2
2) select FlexCAN_T4 example FIFO with interrupt
3) in the example make sure CAN0 is set in the FlexCAN_T4 constructor

should be fine
 
Code:
#include <FlexCAN_T4.h>
FlexCAN_T4<CAN0, RX_SIZE_256, TX_SIZE_16> Can0;

void setup(void) {
  Serial.begin(115200); delay(400);
  pinMode(6, OUTPUT); digitalWrite(6, LOW); /* optional tranceiver enable pin */
  Can0.begin();
  Can0.setBaudRate(500000);
  Can0.setMaxMB(16);
  Can0.enableFIFO();
  Can0.enableFIFOInterrupt();
  Can0.onReceive(canSniff);
  Can0.mailboxStatus();
}

void canSniff(const CAN_message_t &msg) {
  Serial.print("MB "); Serial.print(msg.mb);
  Serial.print("  OVERRUN: "); Serial.print(msg.flags.overrun);
  Serial.print("  LEN: "); Serial.print(msg.len);
  Serial.print(" EXT: "); Serial.print(msg.flags.extended);
  Serial.print(" TS: "); Serial.print(msg.timestamp);
  Serial.print(" ID: "); Serial.print(msg.id, HEX);
  Serial.print(" Buffer: ");
  for ( uint8_t i = 0; i < msg.len; i++ ) {
    Serial.print(msg.buf[i], HEX); Serial.print(" ");
  } Serial.println();
}

void loop() {
  Can0.events();
}
 
Code:
#include <FlexCAN_T4.h>
FlexCAN_T4<CAN0, RX_SIZE_256, TX_SIZE_16> Can0;

void setup(void) {
  Serial.begin(115200); delay(400);
  pinMode(6, OUTPUT); digitalWrite(6, LOW); /* optional tranceiver enable pin */
  Can0.begin();
  Can0.setBaudRate(500000);
  Can0.setMaxMB(16);
  Can0.enableFIFO();
  Can0.enableFIFOInterrupt();
  Can0.onReceive(canSniff);
  Can0.mailboxStatus();
}

void canSniff(const CAN_message_t &msg) {
  Serial.print("MB "); Serial.print(msg.mb);
  Serial.print("  OVERRUN: "); Serial.print(msg.flags.overrun);
  Serial.print("  LEN: "); Serial.print(msg.len);
  Serial.print(" EXT: "); Serial.print(msg.flags.extended);
  Serial.print(" TS: "); Serial.print(msg.timestamp);
  Serial.print(" ID: "); Serial.print(msg.id, HEX);
  Serial.print(" Buffer: ");
  for ( uint8_t i = 0; i < msg.len; i++ ) {
    Serial.print(msg.buf[i], HEX); Serial.print(" ");
  } Serial.println();
}

void loop() {
  Can0.events();
}

That work THANKS.

How can I monitor just

Can ID 0x1F5
 
put this at top line of canSniff function:

if ( msg.id != 0x1F5 ) return;

filtering it to view only specific IDs is also possible
 
Tonton81

Sorry but can you do it in red on above script you did. Im trying to learn where and what function go.

Also do you do programming? I willing to compensate you.
 
It's the Tx TS recorded when the message actually makes it on the bus after any arbitration delays.

OK, I'll look into it.

For reference, time synchronisation over CAN:
https://www.autosar.org/fileadmin/user_upload/standards/classic/4-3/AUTOSAR_SWS_TimeSyncOverCAN.pdf

Thanks :)

I just added transmit callback support. It is same as onReceive, just use onTransmit(MB8, callback) (mailbox specific) or onTransmit(callback) (global). The demo canSniff function can be used as a callback for onTransmit to show what has been sent on the bus and with current timestamp.
 
I just added transmit callback support. It is same as onReceive, just use onTransmit(MB8, callback) (mailbox specific) or onTransmit(callback) (global). The demo canSniff function can be used as a callback for onTransmit to show what has been sent on the bus and with current timestamp.
Oh wow, thank you that's incredibly useful. Had to drop this for the moment, but I'll be back on it eventually!
 
So, I finally got around to making a Teensy 4.1 based design. I put CAN-FD transceivers on there for all three channels even though not all three can actually do CAN-FD. But, it doesn't really hurt anything to use them and it's fun to keep the design nice and neat. Anyway, just got to testing and am testing sending messages between the first two CAN buses on the T4.1. I can reliably get some odd behavior. Using Arduino IDE 1.8.13 and TeensyDuino 1.53

I took the beta_sample sketch and modified it just slightly to make it possible to send messages on both CAN buses. The buses are looped to each other. Yes, I did terminate them.

Code:
#include <FlexCAN_T4.h>

FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> can1;
FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_16> can2;
CAN_message_t msg;
CAN_message_t txMsg;

void setup(void) {
  can1.begin();
  can1.setBaudRate(250000);
  can2.begin();
  can2.setBaudRate(250000);

  txMsg.id = 0x34A;
  txMsg.len = 8;
  txMsg.buf[0] = 0x10;
  txMsg.buf[1] = 0xAC;
  txMsg.buf[2] = 0x54;
  txMsg.buf[3] = 0x31;
  txMsg.buf[4] = 0xA6;
  txMsg.buf[5] = 0xF4;
  txMsg.buf[6] = 0x7E;
  txMsg.buf[7] = 0x37;
}

void loop() {
  if ( can1.read(msg) ) {
    Serial.print("CAN1 "); 
    Serial.print("MB: "); Serial.print(msg.mb);
    Serial.print("  ID: 0x"); Serial.print(msg.id, HEX );
    Serial.print("  EXT: "); Serial.print(msg.flags.extended );
    Serial.print("  LEN: "); Serial.print(msg.len);
    Serial.print(" DATA: ");
    for ( uint8_t i = 0; i < 8; i++ ) {
      Serial.print(msg.buf[i]); Serial.print(" ");
    }
    Serial.print("  TS: "); Serial.println(msg.timestamp);
  }
  else if ( can2.read(msg) ) {
    Serial.print("CAN2 "); 
    Serial.print("MB: "); Serial.print(msg.mb);
    Serial.print("  ID: 0x"); Serial.print(msg.id, HEX );
    Serial.print("  EXT: "); Serial.print(msg.flags.extended );
    Serial.print("  LEN: "); Serial.print(msg.len);
    Serial.print(" DATA: ");
    for ( uint8_t i = 0; i < 8; i++ ) {
      Serial.print(msg.buf[i]); Serial.print(" ");
    }
    Serial.print("  TS: "); Serial.println(msg.timestamp);
  }
  if (Serial.available())
  {
    int c = Serial.read();
    if (c == 'c') can1.write(txMsg);
    if (c == 'd') can2.write(txMsg);
  }
}

So, basically you can send c or d and it sends out of the CAN buses to the other one. This works. But, here are the oddities:

1. If I send more than 8 letters in a row then only 8 messages actually show up as received. For instance. cccc works and 4 messages are received. cccccccccc will show that 8-9 messages were received but not 10. I'm using the Serial Monitor in the IDE so when I send this traffic it gets sent all at once. The question is, why can't it successfully send and receive 10, 12, 20 messages? It reliably stops after either 8 or 9.
2. If I mix the two commands so that messages are sent from both buses then it almost always quits responding. cd might work but cdcd will just make the whole sketch quit working.

I did try playing with the optimization setting a bit; didn't help. It seems like a weird result but I wonder if the version in TD1.53 is old or if I'm doing something wrong? I really never did use Teensy boards very much so maybe there's something obvious I'm doing that's dumb but I don't see it. This example sketch is really very basic.
 
what does mailboxStatus() show? if it assigned 8 transmit mailboxes that probably explains why. I forgot what the default is (hopefully 16?) where 4 are STD, 4 EXT, and 8 TX. If so you can increase the mailboxes (up to 64). On flexcan, if the last RX mailbox gets full (all of them), the overflow happens on the last mailbox. If you have 4 standard RX like i mentioned, writing 12 transmits will fill all 4 and the 4th would overflow constantly with the last received updated frame. Thats why you should read em so they can be available to fill again. I would suggest to try interrupt mode instead of polling if frame loss happens if not read fast enough. remember you have 8 transmitting with 4 receiving (thats if i assume you're mailbox limit is 16). use setMaxMB(64) if you want more reception mailboxes, 16 will be automatically set as Standard, 16 for Extended, and 32 transmits. You may reconfigure them later using setMB() if you want to assign X amount of STD,EXT,or TX of your own choice :)

I use all 3 CAN channels in interrupt mode in my setup, TeensyCAN uses interrupt mode as well last i tested 1 meg payload transferred without loss, crc validated too
 
Beginner question: testing on a T3.2 I'm using the below code. The LED never turns on and I only get the first serial output. It looks like the Teensy is crashing. I downloaded the latest version from git a couple days ago. Suggestions? Is there a known bug with this?

Code:
#include <FlexCAN_T4.h>

FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> canBus;
static CAN_message_t dashMsg;

void setup()
{
  // Init Serial
  Serial.begin(9600);
  // while (!Serial) ; // wait for Arduino Serial Monitor
  Serial.println("Teensy 4.0 CAN Example test");

  // Init CAN
  canBus.begin();
  Serial.println("begin");
  canBus.setBaudRate(1000000);
    Serial.println("setbaud");

  // Turn LED on
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH);
}


void loop()

{
  // Get CAN Messages & Update values
  if (canBus.read(dashMsg) ) {
    // Flash onboard LED
    digitalWrite(13, LOW);
    Serial.println("read");
    // Get ID
    String id = String(dashMsg.id, HEX);
    Serial.println(id);
    // Flash onboard LED
    digitalWrite(13, HIGH);
  }
}
 
define crashing? do you see CAN traffic? your connections okay? you probably didn't see the startup prints due to no delay in setup(), but if your not connected to CAN properly the rest of the loop won't work
 
Right, but you would expect the LED to turn on, right @tonton81? I tried with a 2 second delay. The first output prints fine and then nothing after that happens. No pin 13 LED turns on.

I have a logic analyzer hooked up to pin 22 and see no traffic.

PS: I really don't mean to be rude as I'm very happy for finding this library. I just cannot get this to work as expected.
 
Last edited:
pin13 should definately turn on, but, you did mention you are on Teensy 3.2 :)

change CAN1 in constructor to CAN0
 
That works much better! :)
But - still no signal on Pin 22. That is the CAN0 TX pin, right?

The reason I'm testing on a T3.2 is that on my T4.1, I also get no output on the CAN2 port (pin0 + pin 1) on the T4.1. Below is the code I'm testing with on T4.1:

Code:
#include <FlexCAN_T4.h>

FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_16> can;
CAN_message_t msg;

#define DRIVER1_ADDRESS 0x601

int counter = 0;
void sendMessage();

void setup(void) {
  can.begin();
  can.setBaudRate(1000000);
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  if ( can.read(msg) ) {
    Serial.print("CAN2 "); 
    Serial.print("MB: "); Serial.print(msg.mb);
    Serial.print("  ID: 0x"); Serial.print(msg.id, HEX );
    Serial.print("  EXT: "); Serial.print(msg.flags.extended );
    Serial.print("  LEN: "); Serial.print(msg.len);
    Serial.print(" DATA: ");
    for ( uint8_t i = 0; i < 8; i++ ) {
      Serial.print(msg.buf[i]); Serial.print(" ");
    }
    Serial.print("  TS: "); Serial.println(msg.timestamp);
  }

  counter++;
  if(counter % 200000 == 0)
  {
    //digitalWrite( LED_BUILTIN, !digitalRead(LED_BUILTIN) );
    digitalWrite( LED_BUILTIN, HIGH );
    delay(200);
    sendMessage();
    digitalWrite( LED_BUILTIN, LOW );
  }

}

void sendMessage()
{
  uint16_t index = 0x6040;
  uint32_t data = 0x80;

  msg.id = DRIVER1_ADDRESS;
  msg.buf[0] = 0x2B;                 // Command specifier
  msg.buf[1] = (index >> 8) & 0xFF;  // Index bit 1
  msg.buf[2] = (index >> 0) & 0xFF;  // Index bit 2
  msg.buf[3] = 0x00;                 // Subindex
  msg.buf[4] = (data >> 24) & 0xFF; // Data bit 1
  msg.buf[5] = (data >> 16) & 0xFF; // Data bit 2
  msg.buf[6] = (data >> 8) & 0xFF;  // Data bit 3
  msg.buf[7] = (data >> 0) & 0xFF;  // Data bit 4
  can.write(msg);
}
 
Back
Top