Teensy 4.1 and CanBus

Boothby

Member
Hi all,
having troubles getting the CAN1 , CAN2, or CANFD to send out any data on the associated pins. would guess this one is an easy one to answer. any suggestions? here is code i found on the forum that i am trying to run on the Teensy 4.1. Should be data on Can1 (pin 22 - CTX1). Ultimately wanting to use the CANFD at 4.5Mb/s.
thank you in advance.
Boothby

// -------------------------------------------------------------
// CANtest for Teensy 4.0 using CAN2 and CAN2 bus
#include <FlexCAN_T4.h>

#define debug(msg) Serial.print("["); Serial.print(__FILE__); Serial.print("::"); Serial.print(__LINE__); Serial.print("::"); Serial.print(msg); Serial.println("]");
void debug_pause(void)
{
Serial.print("Paused...");
while (!Serial.available());
while (Serial.available()) Serial.read();
Serial.println("Restarted.");
}

FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> Can1;
FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_16> Can2;

static CAN_message_t msg;
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)
{
Serial.begin(115200);
int iSerialTimeout = 1000000;
delay(100);
while (!Serial && (iSerialTimeout-- != 0));
debug (F("start setup"));

Can1.begin();
Can2.begin();

pinMode(0, INPUT);
pinMode(1, OUTPUT);
pinMode(22, OUTPUT);
pinMode(23, INPUT);



Can1.setBaudRate(1000000); // I like to set the baud rates just to be on the safe side
Can2.setBaudRate(1000000);

// t4 missing msg.ext = 0;
msg.id = 0x100;
msg.len = 8;
msg.flags.extended = 0;
msg.flags.remote = 0;
msg.flags.overrun = 0;
msg.flags.reserved = 0;
msg.buf[0] = 10;
msg.buf[1] = 20;
msg.buf[2] = 0;
msg.buf[3] = 100;
msg.buf[4] = 128;
msg.buf[5] = 64;
msg.buf[6] = 32;
msg.buf[7] = 16;
debug (F("setup complete"));
//debug_pause();
}


// -------------------------------------------------------------
void loop(void)
{
msg.buf[0]++; //since you are in a loop i just incremented each time in stead of doing it 5 times
Can1.write(msg); //you could do it your way as well
Serial.println("T4.0cantest - Repeat: Read bus2, Write bus1");
CAN_message_t inMsg;
if (Can2.read(inMsg)!=0) // Changed this to if as as opposed to while - the way you had it just gets stuck since you haven't even sent a message yet
{
Serial.print("W RD bus 2: "); hexDump(8, inMsg.buf);
}
delay(200);
}
 
do NOT run pinMode at all, begin() sets up the CAN pins, you effectively turn off the CAN peripheral controls and switch them to GPIO mode, essentially breaking communication

CAN3 can be set as CAN2.0 or CANFD, it's dual purpose.
CANFD is also able to talk to and receive both CAN2.0 and CANFD, so long as other peripherals on the bus support it as well. 2 values in the CANFD message struct need to be set before a frame is sent as CAN2.0 but FD can receive both types of frames depending on mailbox size (64 bytes max at 8Mbps(data))
 
Not sure if i got the hang of this forum. in case the message i just type vanished, i did run the code without the pinMode. desperation. Still no activity on pin 22 (CTX1) looking with scope. Can1.write() should do something... thanks for your quick response.
 
use the FIFO with interrupts example as-is, with correct baud rate, if you still have issues it's down to the transceiver, wiring, or not terminated bus (120ohm resistor at both ends of the bus), you can add sending code to that example if you are testing writes.

Hint: run Can1.mailboxStatus() every 1 sec in the loop, if all your TX mailboxes remain FULL, it's definately a transceiver or termination issue
 
this is the code example i found arduino 1.8.13. is this what you refer to?

#include <FlexCAN_T4.h>
FlexCAN_T4<CAN1, 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(1000000);
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, HEX); Serial.print(" ");
} Serial.println();
}

void loop() {
Can0.events();

static uint32_t timeout = millis();
if ( millis() - timeout > 200 ) {
CAN_message_t msg;
msg.id = random(0x1,0x7FE);
for ( uint8_t i = 0; i < 8; i++ ) msg.buf = i + 1;
Can0.write(msg); Serial.println("sending");
timeout = millis();
}

}
 
Hi, wanted to let you know that code is working. problem i have is i don't have the transceivers yet. that meant that the input to the Teensy 4.1 was left floating and happened to be read in as low. to the code, that meant the bus was active and therefore couldn't send until that input went high. so simple once you know... thank you for your help. until next time
Boothby
 
Hi tonton81,
Question on the CANFD of the Teensy4.1. What is the highest baudrate? Here is the stepup code. when i try for 5M, it stops, but runs at 4M. For the FlexCan_T4, is there more distription than the .h itself? For example, this code specifies the config.clock=CLK_24MHz. Not sure where that comes from. Then there is the config.baudrate and config.baudrateFD. again, not sure of the differences.

include <FlexCAN_T4.h>

FlexCAN_T4FD<CAN3, RX_SIZE_256, TX_SIZE_16> FD; // can3 port
//FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_16> can2; // can2 port
//FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> can1; // can1 port

//int led = 13;
IntervalTimer timer;
uint8_t d=0;


void setup(void) {
pinMode(LED_BUILTIN, OUTPUT); //indication the processor is alive.
digitalWrite (LED_BUILTIN, HIGH) ;
Serial.begin(115200); delay(1000);
Serial.println("Teensy 4.0 Triple CAN test - modified ONLY FD ACTIVE");
digitalWrite (LED_BUILTIN, LOW) ;

FD.begin();
CANFD_timings_t config;
config.clock = CLK_24MHz;
config.baudrate = 500000; // 500kbps arbitration rate
config.baudrateFD = 5000000; // 2000kbps data rate
config.propdelay = 190;
config.bus_length = 1;
config.sample = 75;
FD.setRegions(64);
FD.setBaudRateAdvanced(config, 1, 1);
FD.onReceive(canSniff);
FD.setMBFilter(ACCEPT_ALL);
FD.setMBFilter(MB13, 0x1);
FD.setMBFilter(MB12, 0x1, 0x3);
FD.setMBFilterRange(MB8, 0x1, 0x04);
FD.enableMBInterrupt(MB8);
FD.enableMBInterrupt(MB12);
FD.enableMBInterrupt(MB13);
FD.enhanceFilter(MB8);
FD.enhanceFilter(MB10);
FD.distribute();
FD.mailboxStatus();
 
5Mbps or above you need to change the clock, use CLK_60MHz
The baudrates are calculated off the clock always, 24MHz is default oscilator clock, 60 is the max peripheral clock.

baudrate is the nominal arbitration rate, is the same as limits of CAN2.0, 1Mbps max.
baudrateFD is the flexdata rate, which is up to 8Mpbs max (most transceivers are 5Mbps max, make sure your's is capable of 8 obviously)
 
Thank you. Appreciated. probably know just how extensive the datasheets are for the NXP iMXRT1062 chip. Does changing this clock effect CAN1/2, Serial settings?
 
yes all controllers run off the same clock.
You do not need to change it in CAN2.0 (setClock()) and CANFD (config.clock). It can be set once on either controller, and setBaudrate will calculate off the current clock.

Teensy 3.x runs off a 16MHz OSC clock.
Teensy 4.x could be changed up to 80MHz, even though the RM states the controller use 60MHz max. Not sure if that's an error in the manual vs register options, or considered an 'overclock', but someone did report 80MHz worked at 10Mbps CANFD even though the max listed rate was 8Mbps, so that is yet to be verified
 
Hi tonton81. I went looking into the FlexCAN_T4.h to get better understanding. Nice work! I have read up on masks and filters so a node can accept all, none, range of IDs. Looking at your .h code, i see what is probably the method of setting those.

FD.setMBFilter(ACCEPT_ALL);
FD.setMBFilter(MB13, 0x1);
FD.setMBFilter(MB12, 0x1, 0x3);
FD.setMBFilterRange(MB8, 0x1, 0x04);
FD.enableMBInterrupt(MB8);
FD.enableMBInterrupt(MB12);
FD.enableMBInterrupt(MB13);
FD.enhanceFilter(MB8);
FD.enhanceFilter(MB10);
FD.distribute();
FD.mailboxStatus();

What i would like to do is to a node that will look specifically for a unique ID then response back with a packet. what would be the appropriate code to do that?

Boothby
 
I suggest you start without a filter so you can start simple.
Your callback will have the ID you are looking for
Code:
if (msg.id == 0x123) {Serial.println("found special frame");}

depending on what you want to send back (I put a print as example), you can create a new message frame and send it out:

Code:
CANFD_message_t out;
out.id = 0x456;
out.len = 24; // or 8 - 64, depending on the FD mailbox size (setRegion())
out.buf[0.....23] = 0x3; // set your bytes
FD.write(out); // send out the FD frame
 
Hi tonton81,
I'm using FlexCan Library for some time now, communicating with all kinds of ECU, Standard-CAN and CAN_FD. There are several ECU that send lots of different messages, 11bit and 19bit ID mixed. Is there any way to filter MB0 recveiving with three ID at once,
i.E. 0x0AD, 0x17FE0077 and 0x1C420077? Because receiving all the other frames jams my application sometimes.

Thanks in advance!
 
standard or extended, can't mix because the masking bits will accept tons of IDs in between or outside that range.
You can setup 3 mailboxes, each with those filtered if you wish
Are you using FIFO? How does it jam? Are you using events()?
 
Yes of course, you're absolutely right! Why not use more than one MB for receive...?! That did the trick!
Thanks again very much for your suggestion!

Have a nice time!
 
Hi tonton81,
had success sending a 64-byte packet from one Node to another, then back. no filters. and i believe polled. From your FlexCAN_T4.h file, i try to make sense, parts i get, parts i don't. I would now like to use the filters and switch to interrupts. I see what looks like that functionality but lack the understanding how to use it. referring to the startup routine calls i found is this code (included) noticed that canSniff() was never called. that might be associated with interrupts? appreciate your time and help.
FD.setMBFilter(MB12, 0x1, 0x3);
FD.setMBFilterRange(MB8, 0x1, 0x04);
FD.enableMBInterrupt(MB8);
FD.enableMBInterrupt(MB12);
FD.enableMBInterrupt(MB13);

here is a screen capture of the second Node receiving a packet of data from the first before it returns its packet.
Capture.jpg

here is the code:
/*
* 2021May24
* found my adafruit superstrip had poor contact. expects larger size wire. switched to the 3M
* max clock for CAN1 or CAN2 is 4MHz.
* and it should be mentioned that one does need the 485 driver. because it needs to listen to itself to dectect collisions!!!
* Also found with this code unable to go faster than 4Mb/s
*
* 2021May25. By setting the Clock to 80MHz, achieved 8Mb/s. but currently, the imu boards are designed with the LTC2875 which is limited
* to 4Mb/s. so that where i will stay. nice to know can go faster.
*
* 2021May26 will now have the Receiver return a packet back to the transmitter. This is working. comes in on
* mailbox 0. believe it is polled and not interrupt based.
*/



/*
* Teensy 4.0 Triple CAN Demo
* https://github.com/skpang/Teensy40_triple_CAN_demo/blob/master/Teensy40_triple_CAN_demo.ino
* For use with:
* http://skpang.co.uk/catalog/teensy-40-triple-can-board-include-teensy-40-p-1575.html
*
* can1 and can2 are CAN2.0B
* can3 is CAN FD
*
* Ensure FlexCAN_T4 is installed first
* https://github.com/tonton81/FlexCAN_T4
*
* www.skpang.co.uk October 2019
*
*/
#include <FlexCAN_T4.h>

FlexCAN_T4FD<CAN3, RX_SIZE_256, TX_SIZE_16> FD; // can3 port

IntervalTimer timer;



void setup(void) {
pinMode(LED_BUILTIN, OUTPUT); //indication the processor is alive.
digitalWrite (LED_BUILTIN, HIGH) ;
Serial.begin(115200); delay(1000);
Serial.println("Teensy 4.0 Triple CAN test - modified ONLY FD ACTIVE");
digitalWrite (LED_BUILTIN, LOW) ;

FD.begin();
CANFD_timings_t config;
//config.clock = CLK_24MHz;
config.clock = CLK_24MHz; //from tonton84 forum, need to change to 60MHz for faster speeds this is for the peripheral
config.baudrate = 500000; // 500kbps arbitration rate
config.baudrateFD = 4000000; // 2000kbps data rate
config.propdelay = 190;
config.bus_length = 1;
config.sample = 75;
FD.setRegions(64);
FD.setBaudRateAdvanced(config, 1, 1);
FD.onReceive(canSniff);
FD.setMBFilter(ACCEPT_ALL);
//FD.setMBFilter(REJECT_ALL );
FD.setMBFilter(MB13, 0x1);
FD.setMBFilter(MB12, 0x1, 0x3);
FD.setMBFilterRange(MB8, 0x1, 0x04);
FD.enableMBInterrupt(MB8);
FD.enableMBInterrupt(MB12);
FD.enableMBInterrupt(MB13);
FD.enhanceFilter(MB8);
FD.enhanceFilter(MB10);
FD.distribute();
FD.mailboxStatus();

}

void sendframe()
{

CANFD_message_t msg;
msg.len = 64;
msg.id = 0x3fd;
msg.seq = 1;
for ( uint8_t i = 0; i < 64; i++ ) {
msg.buf = i + 65; //changing so different than what was sent.
}

FD.write( msg); // write to can3
}


void canSniff(const CANFD_message_t &msg) {
Serial1.print("canSniff ");
Serial.print("ISR - 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, HEX); Serial.print(" ");
} Serial.println();

}





void loop() {

CANFD_message_t msg;


FD.events(); /* needed for sequential frame transmit and callback queues */
if ( FD.readMB(msg) ) {
Serial.print("MB: "); Serial.print(msg.mb);
//Serial.print(" OVERRUN: "); Serial.print(msg.flags.overrun);
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(" BRS: "); Serial.print(msg.brs);
// Serial.print(" EDL: "); Serial.print(msg.edl);
Serial.print(" DATA: ");
for ( uint8_t i = 0; i <msg.len ; i++ ) {
Serial.print(msg.buf); Serial.print(" ");
}
Serial.print(" TS: "); Serial.println(msg.timestamp);
digitalWrite (LED_BUILTIN, !digitalRead (LED_BUILTIN)) ;

sendframe(); //send a msg back to the transmitter.
}
}
 
Hi tonton81,
had success sending a 64-byte packet from one Node to another, then back. no filters. and i believe polled. From your FlexCAN_T4.h file, i try to make sense, parts i get, parts i don't. I would now like to use the filters and switch to interrupts. I see what looks like that functionality but lack the understanding how to use it. referring to the startup routine calls i found is this code (included) noticed that canSniff() was never called. that might be associated with interrupts? appreciate your time and help.
FD.setMBFilter(MB12, 0x1, 0x3);
FD.setMBFilterRange(MB8, 0x1, 0x04);
FD.enableMBInterrupt(MB8);
FD.enableMBInterrupt(MB12);
FD.enableMBInterrupt(MB13);

here is a screen capture of the second Node receiving a packet of data from the first before it returns its packet.
View attachment 24919

here is the code:
/*
* 2021May24
* found my adafruit superstrip had poor contact. expects larger size wire. switched to the 3M
* max clock for CAN1 or CAN2 is 4MHz.
* and it should be mentioned that one does need the 485 driver. because it needs to listen to itself to dectect collisions!!!
* Also found with this code unable to go faster than 4Mb/s
*
* 2021May25. By setting the Clock to 80MHz, achieved 8Mb/s. but currently, the imu boards are designed with the LTC2875 which is limited
* to 4Mb/s. so that where i will stay. nice to know can go faster.
*
* 2021May26 will now have the Receiver return a packet back to the transmitter. This is working. comes in on
* mailbox 0. believe it is polled and not interrupt based.
*/



/*
* Teensy 4.0 Triple CAN Demo
* https://github.com/skpang/Teensy40_triple_CAN_demo/blob/master/Teensy40_triple_CAN_demo.ino
* For use with:
* http://skpang.co.uk/catalog/teensy-40-triple-can-board-include-teensy-40-p-1575.html
*
* can1 and can2 are CAN2.0B
* can3 is CAN FD
*
* Ensure FlexCAN_T4 is installed first
* https://github.com/tonton81/FlexCAN_T4
*
* www.skpang.co.uk October 2019
*
*/
#include <FlexCAN_T4.h>

FlexCAN_T4FD<CAN3, RX_SIZE_256, TX_SIZE_16> FD; // can3 port

IntervalTimer timer;



void setup(void) {
pinMode(LED_BUILTIN, OUTPUT); //indication the processor is alive.
digitalWrite (LED_BUILTIN, HIGH) ;
Serial.begin(115200); delay(1000);
Serial.println("Teensy 4.0 Triple CAN test - modified ONLY FD ACTIVE");
digitalWrite (LED_BUILTIN, LOW) ;

FD.begin();
CANFD_timings_t config;
//config.clock = CLK_24MHz;
config.clock = CLK_24MHz; //from tonton84 forum, need to change to 60MHz for faster speeds this is for the peripheral
config.baudrate = 500000; // 500kbps arbitration rate
config.baudrateFD = 4000000; // 2000kbps data rate
config.propdelay = 190;
config.bus_length = 1;
config.sample = 75;
FD.setRegions(64);
FD.setBaudRateAdvanced(config, 1, 1);
FD.onReceive(canSniff);
FD.setMBFilter(ACCEPT_ALL);
//FD.setMBFilter(REJECT_ALL );
FD.setMBFilter(MB13, 0x1);
FD.setMBFilter(MB12, 0x1, 0x3);
FD.setMBFilterRange(MB8, 0x1, 0x04);
FD.enableMBInterrupt(MB8);
FD.enableMBInterrupt(MB12);
FD.enableMBInterrupt(MB13);
FD.enhanceFilter(MB8);
FD.enhanceFilter(MB10);
FD.distribute();
FD.mailboxStatus();

}

void sendframe()
{

CANFD_message_t msg;
msg.len = 64;
msg.id = 0x3fd;
msg.seq = 1;
for ( uint8_t i = 0; i < 64; i++ ) {
msg.buf = i + 65; //changing so different than what was sent.
}

FD.write( msg); // write to can3
}


void canSniff(const CANFD_message_t &msg) {
Serial1.print("canSniff ");
Serial.print("ISR - 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, HEX); Serial.print(" ");
} Serial.println();

}





void loop() {

CANFD_message_t msg;


FD.events(); /* needed for sequential frame transmit and callback queues */
if ( FD.readMB(msg) ) {
Serial.print("MB: "); Serial.print(msg.mb);
//Serial.print(" OVERRUN: "); Serial.print(msg.flags.overrun);
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(" BRS: "); Serial.print(msg.brs);
// Serial.print(" EDL: "); Serial.print(msg.edl);
Serial.print(" DATA: ");
for ( uint8_t i = 0; i <msg.len ; i++ ) {
Serial.print(msg.buf); Serial.print(" ");
}
Serial.print(" TS: "); Serial.println(msg.timestamp);
digitalWrite (LED_BUILTIN, !digitalRead (LED_BUILTIN)) ;

sendframe(); //send a msg back to the transmitter.
}
}
 
also, here is a scope image of the handshake running at 4Mb/s. first on the bus is Node1, then Node two responding 54us later.
Transmitter Receiver Packets.jpg
 
Hi tonton81,
did see in your .h file enableMBInterrupts. the canSniff() routine was call but stop after 5 packets. probably a buffer i need to empty.
will have multiple Nodes on the bus. with the code presently having no filters and only using the id, will the hardware acks from multiple Nodes confuse the sending Node? seems like if Node 1 needs to talk to Node 5, it should be Node 5 acking back.
 
if data stops check your CAN terminations, nodes have to ack to their own frames, but all nodes see the same frame
 
Hi tonton81, not the hardware. reverting back to previous firmware works. do i need the interrupts to do the filtering? thx boothby
 
interrupts have nothing to do with filtering, but if not all mailboxes are read in poll mode then you will start missing frames
 
Back
Top