FlexCAN_T4 - FlexCAN for Teensy 4

you definately need the transceiver. you can gerry rig a diode and resistors to possibly make it work, but stability wont be guarenteed obviously
 
Can you explain why this is? With a short wire connecting can1tx to can1rx it is basically the same as loopback mode, signal looks clean on the scope. I put a 10K pullup to 3.3V (which doesn't appear to change anything).
 
All CAN controllers need transceivers, it doesn't matter what mocrocontroller you have, even vehicles have them in the ECUs, it's just the way it is. There is a diode hack somewhere on google but like I said it's not meant or designed to be directly wired.
 
I'm sorry for poor English
Thank you for the wonderful library.

No problem with can2.0 using this library
I was able to confirm that it works.
Next, I would like to check with canfd

Example of reception by canfd
And
Example of sending by canfd
Can you tell me each?
 
Code:
#include <FlexCAN_T4.h>

FlexCAN_T4[COLOR="#FF0000"]FD[/COLOR]<[COLOR="#FF0000"]CAN3[/COLOR], RX_SIZE_128, TX_SIZE_128> FD;

void setup(void) {
  FD.begin();

[COLOR="#FF0000"]  CANFD_timings_t config;
  config.clock = CLK_24MHz;
  config.baudrate = 1000000;
  config.baudrateFD = 2000000;
  config.propdelay = 190;
  config.bus_length = 1;
  config.sample = 70;
  FD.setRegions(64);
  FD.setBaudRate(config);[/COLOR]
  FD.onReceive(canSniff);
  FD.enableMBInterrupts();
  FD.mailboxStatus();
}

void canSniff(const CANFD_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("  EDL: "); Serial.print(msg.edl );
  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() {
  FD.events();
}

it's mostly the same as CAN2.0 layout.
for the sending part, just make sure you use CANFD_message_t

red shows the changes needed to use FD
 
Thank you for your quick answer
That would help a lot



I'm sorry for being ignorant
Let me ask you the following
config.baudrate =
1000000;
config.baudrateFD = 2000000;

Can you tell us the difference between baudrate and baudrateFD?

The baud rate of the bus I want to receive is 500kbps canFD.

Should both be set to 500kbps in my case?
 
CANFD has 2 baudrates.

Nominal max is 1Mbps for CAN2.0 and FD
The second rate for FD is for it's data, which can go up to 8Mbps, provided your transceiver is capable (some transceivers do 5 max). If you prefer to match the speed its fine, you can put 500000 for both. The code I posted enables 64 byte mailboxes, so you can send/receive up to 64 bytes per frame
 
Can you explain why this is? With a short wire connecting can1tx to can1rx it is basically the same as loopback mode, signal looks clean on the scope. I put a 10K pullup to 3.3V (which doesn't appear to change anything).

Two further aspects must be considered:
1. With can1tx connected to can2rx, can1rx is expecting to see the bus state at all times, as if connected to can1tx.
2. During the ACK slot bit of a standard frame, can1rx is expecting another node to overwrite the recessive bit sent by can1tx with a dominant bit to ACK the message. If this ACK bit is recessive (not ACK'd), then the controller will resend the frame ASAP.

With a wire shorting from can1tx to can1rx you are satisfying the first condition above, but not the second. The frame is never properly ACK'd, so it is almost certainly being sent repeatedly. You could confirm this with the scope by checking if it is only sending a frame ever ~100ms.

For the frame to be ACK'd by can2tx, you will need transceivers or diodes to prevent the ACK bit from being a short circuit from can1tx (high) to can2tx (low).
 
Here is a way you can try it without a transceiver, beware that the pullup is at 5V, teensy pins are not 5V tolerant. If you have issues communicating after that theres not much we can do software wise anyways
 

Attachments

  • siemens_AP2921.pdf
    19.8 KB · Views: 175
Yes, thanks. I deduced overnight that it probably had to do with the ack. I have can1 and can2 connected with a pulled up local bus with diodes as described in the siemens apnote, (Pulled up to 3.3V) and it is working fine. I still didn't understand why the single port connection can1tx to can1rx (hardwired loopback), but if the channel will not ack itself that would explain it.

This lets me verify software operation and design, before I make a board with the transceiver.
 
Results of checking using the code you gave me yesterday
An ID with 8 bytes or more of data could not be received.

Here are the changes

CANFD_timings_t config;
config.clock = CLK_24MHz;
config.baudrate = 500000;
config.baudrateFD = 2000000;
config.propdelay = 190;
config.bus_length = 1;
config.sample = 70;
FD.setRegions(32);
FD.setBaudRate(config);

The transceiver I'm using is 2561FD

Please let me know if you have any idea
 
> 8 definately does work because TeensyCAN used 64byte transfers. what did serial monitor show for output?

what device is it connected to? that device must have BOTH matching rates for it to work

with code above you should be able to receive/send 32 bytes max
 
Thank you tonton81

The ID with 32 bytes of data was ignored and did not appear on the serial monitor.
(It has been confirmed that an ID with 32 bytes of data is transmitted on the bus by a different canFD measuring instrument.)

It is connected to the canfd vehicle bus.
 
sure the rate is correct? try another clock to shift the timings, FD supports multiple timing parameters for the same bitrates (due to advanced calculation algorithms built in a separate file).
First try playing with the CLK, 24 is default for oscillator. change it to peripheral clock 60

also since your tool is up, can you try sending a up to 32 byte message and see what it says?

do you receive anything other than the one your not getting? or just specific frame not receiving? by default it accepts all traffic, trying to send data from teensy and verifying it on your analyzer will show if the bitrates/timings match with your car, if you don't see anything, check the transceiver wiring, make sure the enable pin (if any) is grounded to enable the transceiver

teensy must also be grounded to the car as well, not just using the CAN lines, if you are using USB laptop to test teensy in car, both teensy and laptop have no common ground, so make sure you have a ground wire from teensy GND to the car's chasis. the instrument already has the ground attached via the plug im sure (CANH,CANL,GND), but teensy is wired without connector so validate CANH,CANL,GND connection from teensy to car
 
Last edited:
Thank you tonton81

I think the baud rate is definitely below.
config.baudrate = 500000;
config.baudrateFD = 2000000;

The reason is that different canfd instruments can measure at the same baud rate.

Try changing the CLK from 24 to 60. Is there a possibility that FD cannot be measured if CLK is slow?
 
no thats just the clock for the controller, the bitrate calculation is based off that.

Code:
config.clock = CLK_60MHz;

but liike i said if your FD rate is not set properly you wont get any frames because the CRC will fail and the controller will toss it. make sure BOTH devices are 500000 & 2000000, if the 2nd rate is not correct for your vehicle, you will NOT be able to read/write.

you also told me yesturday that you wanted 500000 for both, but today you put 500000 & 2000000. guessing the rate for your device is very hard to determine why "it won't work". you need to source your device specs, or get a scope to confirm the rate, else it will never work. FD is hard to diagnose without the proper FD rate. Your bus didn't crash right? thats because nominal speed was correct so it didnt corrupt CAN traffic already on the bus since it won arbitration. However, the 2nd rate, if it was wrong, fails the CRC as its computed wrong on the bus and the nodes just toss it out, and arbitrations continue. So you need to get the EXACT rate for your car's bus to get it to a usuable state.

FD was scope tested working at 2, 4, 6, and 8Mbps by skpang, so they are calculated correctly
 
Last edited:
Dear tonton81, dear all,

I thought been enough fluent with c++, but I realized that not, in tryng to deeply used the FlexCAN_T4 library.
So, I want to made a function with parameters : can_bus number (1,2 or 3), number of mailbox, id CAN
Something like this
void CommonCAN_init(FlexCAN_T4 Bus, uint16_t MB, uint16_t ID_CAN)
{
Bus->setMBFilter(MB,ID_CAN);
Bus->enhanceFilter(MB);
....
}

Normaly, I don't have difficuties to manage class' pointer, but with this library my understunding of code reach a step to high for me.
Did someone have a idea of how I can achieve that?
Thank a lot in adavance,
 
it's a template compile time object. You may pass the object to your other program in a function after. Mailboxes can be changed at runtime too (setMaxMB()), your function is neither a pointer nor a reference from what I see, but I gather you want to pass more than one bus into your function? try &bus or *bus before using it inside your function with & or ->

Also thats the template class you are probably not going to go far since those objects are on a base class

you should use FlexCAN_T4_Base instead of FlexCAN_T4, because the runtime object is of base class not template :)

It may have shown that in the compile error log as well

wait, no the sketch has the compile time object of class FlexCAN_T4, the library itself uses it's own base class. Try just using the & or * beside Bus in your function
 
Last edited:
Thanks alot for your fast reply
... I have to really switch on my brain, cause I'm still lost.

Juste a some question : Is there 64MailBox per CAN or for 64 in total for the 3 can bus?

I made :
Code:
FlexCAN_T4<CAN2, RX_SIZE_64, TX_SIZE_16> Can_COM1;

void BusCan_InitMB(FlexCAN_T4* BusCan)
{
BusCan->setMBFilter(MB2,0x10AAFF00);
BusCan->enhanceFilter(MB2);
}

void setup()
{
Can_COM1.begin();
Can_COM1.setBaudRate(BAUTRATE_CAN_COM1);
Can_COM1.setMBFilter(REJECT_ALL);
BusCan_InitMeca(&Can_COM1);
}
[ /CODE]

But the template, make me confused...
There is of course error:
- variable or field 'BusCan_InitMB' declared void
- missing template arguments before 'BusCan'

Tonton81, I know it's c++ "tips", but can I abuse more and ask for your lights?
 
yes, each controller has 64 mailboxes, they can be changed except the CANFD mode, size depends on mailbox data capacity.

Yes I see the error here, as a workaround until it can be figured out, the CAN frames have identifiers of which bus they came from, so you can see the received frame has msg.bus 2 set, meaning it came from CAN2

This is why we can pass all 3 busses callbacks to one function in a user sketch and differentiate which frame came from where
 
Last edited:
To sum-up, it means, if we use CAN2.0, there are theoretically 192 (64*3) Mail Boxes ? one CAN controler per channel CAN? not sure to well undestund https://www.nxp.com/webapp/Download?colCode=IMXRT1060RM page 2515

For my initial request, I'm totaly lost... I'will have a break and a coffee...
But before, how could I pass all 3 busses callbacks to one function, as you said?
In fact, my aim, is to made a recursive function, to initialised some frames to one MailBox, with a specific CAN ID (filter), and affected to one of the 3 bus. Is there an elegant way to do that?

Again, thank a lot
 
192 mailboxes total in CAN2.0 mode, all 3 CAN controllers, yes. each bus has 64 max.

you can pass all your busses into one callback in your sketch. if you receive a frame from CAN2 for example, "msg.bus" will return 1 or 2 or 3, depending on if it came from bus CAN1 CAN2 or CAN3, in this case, the frame you received from CAN2 will have msg.bus set to 2, so you know it came from CAN2
 
Ok understood, to made something generic for reading all CanX.readMB(msg) and after I check msg.bus.
But what's happens for the init of MBs, can we do something generic/recursive? to avoid code manualy each filters MB Can1.setMBFilter(X) , Can2.setMBFilter(Y)...
 
well filters you need to set one by one no? what do you want to configure exactly? why not use the object in the function itself? what is your purpose for the project?
 
Back
Top