FlexCAN_T4 - FlexCAN for Teensy 4

Do you have proper bus termination resistors? Combined resistance between CANH and CANL should be 60 ohms.

Also, can you clarify what the leds are doing with the Rs pin? If it isn't strongly pulled to ground, it's either in some slope control mode or low power mode. Maybe try temporarily jumping it to ground to help troubleshoot.
 
The measured termination is 60.7 on a closed bus, so it seems good.
I dissabled the leds by shorting the rs pin to GND, but it still doesn't work :/
 
What exact pins are CanTX & CanRX & CanRS tied to?

Tie Rs to ground thru a 10K. No need to bring it to the Teensy.

I left Vref as NC.
 
CanTX: direct to either 22, 1 or 31
CanRX: direct to either 23, 0 or 30
CanRs: to the leds in the schematic and direct to either 2, 4 or 6.

I'm now wating on some new soldering tools to arrive, so once i have them(tonight/tomorrow), i'll take 2 SN65's of the board and freewire them so a teensy to test it out without the board.
 
How to only send messages once ?

Hi everyone,
I'm currently trying to get familiar with the FlexCAN_T4 lib on my Teensy 4.0, and I have one question : I can send and receive messages, but whenever I send something it is sent continuously, not just once as I would have expected.

I use CAN1 and a CAN transceiver to send, CAN2 to receive.

I think it comes from writeTxMailbox() function : at the end, mbxAddr[0] is set to 'code | FLEXCAN_MB_CS_CODE(FLEXCAN_MB_CODE_TX_ONCE)'. The thing is, it stays at this state and never comes back to FLEXCAN_MB_CODE_TX_INACTIVE.

Is there anything I missed there ? I looked for a flag indicating that the transfer was completed, but I couldn't find one.
Is it a connection issue ? Is that because nobody acknowledges the message, so the Teensy just keeps trying ?

Here is the complete function :
Code:
FCTP_FUNC void FCTP_OPT::writeTxMailbox(uint8_t mb_num, const CAN_message_t &msg) {
  writeIFLAGBit(mb_num);
  uint32_t code = 0;
  volatile uint32_t *mbxAddr = &(*(volatile uint32_t*)(_bus + 0x80 + (mb_num * 0x10)));
  mbxAddr[0] = FLEXCAN_MB_CS_CODE(FLEXCAN_MB_CODE_TX_INACTIVE);
  mbxAddr[1] = (( msg.flags.extended ) ? ( msg.id & FLEXCAN_MB_ID_EXT_MASK ) : FLEXCAN_MB_ID_IDSTD(msg.id));
  if ( msg.flags.remote ) code |= (1UL << 20);
  if ( msg.flags.extended ) code |= (3UL << 21);
  for ( uint8_t i = 0; i < (8 >> 2); i++ ) mbxAddr[2 + i] = (msg.buf[0 + i * 4] << 24) | (msg.buf[1 + i * 4] << 16) | (msg.buf[2 + i * 4] << 8) | msg.buf[3 + i * 4];
  code |= msg.len << 16;
  mbxAddr[0] = code | FLEXCAN_MB_CS_CODE(FLEXCAN_MB_CODE_TX_ONCE);
}

Thanks for your help !
And thanks @tonton81 for this great library !
 
by design if no acknowledgement the hardware itself tries to resend, this is what makes canbus reliable for delivery. check for proper termination on the network
 
1616513862292.jpg
Here is my setting.

The fact that I do receive my messages on CAN2 (pins 0&1) doesn't mean that my setting is right ?
 
I can only see one CAN transceiver board. You need one transceiver for each CAN node.

You can't connect CAN_H and CAN_L to the Teensy like that. It need to go via a CAN transceiver.
 
I'm back. After getting some new transievers and replacing the old one and using normal 120ohm termination on each side instead of split termination, i was able to send a 100Hz signal across the transievers.
166644865_353193566026949_7082038431409798365_n.jpg.
However when i tried to send a CAN message accross, my buffer just get's filled and i get this signal accros:
166386182_637057540583981_1782081740596425083_n.jpg

the code is still the same as above:
hy,

I'm trying to test out my Teensy canbus board with SN65HVD230 canbus transievers and a T4.1. I have 3 transievers, one for each output, but i can't seem to get the T4.1 sending messages. At first i tried just sending messages on one T4.1 and recieving it on the same one, but couldn't get it to work. So i made a schetch and placed it on 2 seperate T4.1's with one recieving and one sending. Still, i'm not able to get the T4.1 sending messages. i hooked up my osciloscope, and noticed the CTX pin is not sending anyting, even when changing canbus. However, the LED is flashing correctly, but i am never getting a "can2 recieved" message in my terminal.
 
Rayan, just an idea:
Can you record a single frame on your scope, with the probes on the receiving node's RX and TX signals?
Does RX look like a proper CAN frame?
Is TX quiet, except for a single ACK bit?
Can you post a picture of the recording?
 
Hi msadie,

here is the TX (blue) and RX(yellow) of the sender:
IMG_20210330_104913.jpg
IMG_20210330_104953.jpg

here is the TX (blue) and RX(yellow) of the reciever:
IMG_20210330_102626.jpg
IMG_20210330_105016.jpg

I tried switching the reciever and sender nodes arround, but it results in the same behaviour. It seems like the reciever is not sending an ACK bit, but the RX looks like the send TX. The delay between the TX_transmitter and RX_reciever signal is 40us, so i don't think that should be a problem
 

Attachments

  • IMG_20210330_102517.jpg
    IMG_20210330_102517.jpg
    104.3 KB · Views: 52
  • IMG_20210330_101925.jpg
    IMG_20210330_101925.jpg
    94.1 KB · Views: 45
Good news, i found the fault in the design.

Even though i followed refference design of the SN65HVD230 transiever chip, the TX capacitor is not supposed to be there.
As such, here is the current, and working schematic.
schematic.PNG

Thnx a lot,
RR
 
I can't see a reference design - the datasheet does explain about noise-reducing components on the digital signals,
but you seem to have used 100nF for a noise-reducing capacitor value which is far too large. 33pF, 100pF, that
sort of value is appropriate. Only the decoupling capacitor(s) should be 100nF (C4 in your circuit). C5 and C6
are on a logic line, not a supply, so you don't decouple them.
 
How to use FlexCAN_T4 class as a function argument?

How to use FlexCAN_T4 class as a function argument?

Hello and thank you for a great library!

We are working on a project where we need to control multiple motors using CAN. To get as high rates as possible we want to use two CAN buses, where motor 0 and 1 are connected to CAN1 and motor 2 and 3 are connected to CAN2. Because the project is somewhat large each motor has an individual class object and one of the class variables should be the CAN port. Please see the class below.

ExampleClass.h
Code:
#ifndef ExampleClass_h
#define ExampleClass_h

#include "FlexCAN_T4.h"

class ExampleClass
{
public:
    ExampleClass() {}

    ExampleClass(FlexCAN_T4 *_can_port);

    void send(CAN_message_t _msg);
private:
    FlexCAN_T4 *can_port;
};

#endif

ExampleClass.cpp
Code:
#include "ExampleClass.h"

ExampleClass::ExampleClass(FlexCAN_T4 *_can_port)
{
    can_port = _can_port;
}

ExampleClass::send(CAN_message_t _msg)
{
    (*can_port).write(_msg);
}

The idea was to define the FlexCAN_T4 instances (can1 and can2) in the main.ino file and then pass the address of the these instances to the constructors of the functions. Please see the main file below.

Code:
#include "FlexCAN_T4.h"
#include "ExampleClass.h"

FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> can1;
FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_16> can2;

// Create a vector containing 4 instances
ExampleClass* class_array = new ExampleClass[4];

void setup() {
  can1.begin();
  can1.setBaudRate(250000);
  can2.begin();
  can2.setBaudRate(250000);
  
  for(int i = 0; i < 4; i++)
  {
    if(i < 2)
    {
      // Initialize the first two elements with CAN1
      class_array[i] = ExampleClass(&can1);
    }
    else
    {
      // Initialize the last two elements with CAN2
      class_array[i] = ExampleClass(&can2);
    }
  }
}

void loop() {}

The error message is attached below. It is related to the use of templates that we cannot seem to understand properly in this context. We have tried to solve this for a couple of weeks without success, so I thought it was worth asking here in case anybody knows how to proceed. We have tried taking care of the error messages, but that has only made things more confusing so I just added the simplest possible example here to illustrate what we want to achieve.

Thank you for very much!

eab660b52ad38e35f4500c27b3cd2a68.jpg
 
Last edited:
I *think* you wan't to pass an object, but in templates the objects are not easily passable to functions. However, thats why a base class exists so FlexCAN_T4 can also do it's tasks in background giving you the ability to have your own named object, without the extra loss of resources and pins of controllers you don't need initialized. Anyways, you need to make a pointer of FlexCAN_T4_Base* class. You may pass them to your functions as long as you are using the FlexCAN_T4_Base class reference and not FlexCAN_T4 class directly.

Check out the isotp source included in FlexCAN_T4, it will show you how it uses the base class to read and write the bus as a plugin library

Examples:
Pointer creation:
Code:
static FlexCAN_T4_Base* _isotp_busToWrite = nullptr;

Set the pointer: (tp.setWriteBus(&Can1), function here shows passing a pointer from your template object, like "can1")
Code:
    void setWriteBus(FlexCAN_T4_Base* _busWritePtr) { _isotp_busToWrite = _busWritePtr; }

Use the pointer:
Code:
_isotp_busToWrite->write(msg);
 
Last edited:
I have the following code on a Teensy 4.0 in an automotive environment. It will communicate with the slow (33,333) and medium (95,238) speed buses but not the high (500,000) speed bus. I've also tested it on the bench with a Macchina M2 with Savvy Can but it's still not sending or receiving.

Code:
#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); // enable tranceiver
pinMode(13, OUTPUT); digitalWrite(13, LOW); // enable led
Can0.begin();
Can0.setBaudRate(500000);
//Can0.setClock(CLK_60MHz);

//Can0.setBaudRate(33333);
//Can0.setBaudRate(95238);
Can0.setBaudRate(500000);
Can0.setMaxMB(16); 
Can0.enableFIFO();
Can0.onReceive(canSniff);
}

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();

 static uint32_t timeout = millis();
 if ( millis() - timeout > 800 ) { // send random frame every 20ms
 digitalWrite(13, !digitalRead(13));
 CAN_message_t msg;
 msg.id = random(0x1, 0x7FE);
 for ( uint8_t i = 0; i < 8; i++ ) msg.buf[i] = i + 1;
 Can0.write(msg);
 timeout = millis();
 }

}

I'm probably doing something very wrong because if I connect the Can 1 port to the Can 2 port directly with the code below I get activity.

Code:
#include <FlexCAN_T4.h>

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, OUTPUT);   
  digitalWrite(led,HIGH);
  Serial.begin(115200); delay(1000);
  Serial.println("Teensy 4.0 Triple CAN test");
  digitalWrite(led,LOW);
  
  can2.begin();
  can2.setClock(CLK_60MHz);
  //can2.setBaudRate(95238);       // 95kbps data rate
  can2.setBaudRate(500000);       // 500kbps data rate
  can2.enableFIFO();
  can2.enableFIFOInterrupt();
  can2.onReceive(FIFO, canSniff20);
  can2.mailboxStatus();
  
  can1.begin();
  can1.setClock(CLK_60MHz);
  can1.setBaudRate(500000);     // 500kbps data rate
  can1.enableFIFO();
  can1.enableFIFOInterrupt();
  can1.onReceive(FIFO, canSniff20);
  can1.mailboxStatus();

  timer.begin(sendframe, 500000); // Send frame every 500ms 
}

void sendframe()
{
  
  CAN_message_t msg2;
  msg2.id = 0x401;
  
  for ( uint8_t i = 0; i < 8; i++ ) {
    msg2.buf[i] = i + 1;
  }
  
  msg2.buf[0] = d++;
  msg2.seq = 1;
  //can2.write(MB15, msg2); // write to can2
  can2.write(msg2); // write to can2

  msg2.id = 0x402;
  msg2.buf[1] = d++;
  can1.write(msg2);       // write to can1

}


void canSniff20(const CAN_message_t &msg) { // global callback
  Serial.print("T4: ");
  Serial.print("MB "); Serial.print(msg.mb);
  Serial.print(" OVERRUN: "); Serial.print(msg.flags.overrun);
  Serial.print(" BUS "); Serial.print(msg.bus);
  Serial.print(" LEN: "); Serial.print(msg.len);
  Serial.print(" EXT: "); Serial.print(msg.flags.extended);
  Serial.print(" REMOTE: "); Serial.print(msg.flags.remote);
  Serial.print(" TS: "); Serial.print(msg.timestamp);
  Serial.print(" ID: "); Serial.print(msg.id, HEX);
  Serial.print(" IDHIT: "); Serial.print(msg.idhit);
  Serial.print(" Buffer: ");
  for ( uint8_t i = 0; i < msg.len; i++ ) {
    Serial.print(msg.buf[i], HEX); Serial.print(" ");
  } Serial.println();
}



void loop() {
  
  can2.events();
  can1.events();
  
}

Any help would be greatly appreciated. Many thanks!
 
have you tried different clocks? 500k shouldnt have issues unless the bus has very specific timings, changing the clock will calculate a different timing even though speeds are same. On the FD end there are several timing configs per clock as an example, try something other than 60mhz. in any case, i use 500kbps & 125kbps on my civic at 60mhz

if the timings or baudrate were wrong one symptom you may see is there are bus errors and your dash lights will light like a christmas tree. If that doesn't happen, check your connections and common ground

ex, some people hookup their teensy with laptop to CANH and CANL of car but forget about the ground and the laptop nor teensy is grounded to communicate with the bus

i probably read wrong but you said there are 3 busses in your car? in anycase make sure the car wiring is correct
 
Thank you for your prompt reply.

You were right, it turned out to be a grounding issue. It's communicating at 500k at 60mhz now.

Yes, it's a gmlan based car (opel corsa) with 3 busses. A high speed (500k) for drivetrain, safety kit,... a mid speed (95k) for entertainment, parking sensors,... and a slow speed (33.33k) for instruments, buttons,...

Thanks again for your suggestion, it's most appreciated!


have you tried different clocks? 500k shouldnt have issues unless the bus has very specific timings, changing the clock will calculate a different timing even though speeds are same. On the FD end there are several timing configs per clock as an example, try something other than 60mhz. in any case, i use 500kbps & 125kbps on my civic at 60mhz

if the timings or baudrate were wrong one symptom you may see is there are bus errors and your dash lights will light like a christmas tree. If that doesn't happen, check your connections and common ground

ex, some people hookup their teensy with laptop to CANH and CANL of car but forget about the ground and the laptop nor teensy is grounded to communicate with the bus

i probably read wrong but you said there are 3 busses in your car? in anycase make sure the car wiring is correct
 
I *think* you wan't to pass an object, but in templates the objects are not easily passable to functions. However, thats why a base class exists so FlexCAN_T4 can also do it's tasks in background giving you the ability to have your own named object, without the extra loss of resources and pins of controllers you don't need initialized. Anyways, you need to make a pointer of FlexCAN_T4_Base* class. You may pass them to your functions as long as you are using the FlexCAN_T4_Base class reference and not FlexCAN_T4 class directly.

Check out the isotp source included in FlexCAN_T4, it will show you how it uses the base class to read and write the bus as a plugin library

Examples:
Pointer creation:
Code:
static FlexCAN_T4_Base* _isotp_busToWrite = nullptr;

Set the pointer: (tp.setWriteBus(&Can1), function here shows passing a pointer from your template object, like "can1")
Code:
    void setWriteBus(FlexCAN_T4_Base* _busWritePtr) { _isotp_busToWrite = _busWritePtr; }

Use the pointer:
Code:
_isotp_busToWrite->write(msg);

Thank you very much for the quick reply @tonton81! I will try your suggestions this weekend and report back to you afterwards!
 
I can't see a reference design - the datasheet does explain about noise-reducing components on the digital signals,
but you seem to have used 100nF for a noise-reducing capacitor value which is far too large. 33pF, 100pF, that
sort of value is appropriate. Only the decoupling capacitor(s) should be 100nF (C4 in your circuit). C5 and C6
are on a logic line, not a supply, so you don't decouple them.

oh, yeah. that could explain it. i just got a sample book in so i'll try 33pF. C6 was chosen fairly large as it shouldn't be switched during normal opperation, should i use a smaller cap there?

Edit: placed the 10k back and a C5 as an 33pF cap and it works!!!!!
 
Last edited:
@tonton81 Mind if I send you a TCAN330 board? I created a non-FD board and am having trouble getting it to work, unsure why. I read in this thread that I'm not alone.
 
make sure you have the chip set to normal mode, theres pins that have pullups and pulldowns on that IC and if it's not in normal mode it won't work, @msadie has the same chip as you and claims it works

what does your sketch and physical pins look like?
 
As @tonton81 mentioned, I've had success with both the TCAN330 and TCAN337. Aside from the special function pins and being powered by 3.3V, these transceivers function the as well as any others I've used with teensy 4/4.1.
 
I wasn't expecting any problems. I have long-term experience with the SN65HVD230D chips and they're flawless.
Here's my setup. This is a custom PCB I made, which has dual TCAN330's. There are pins to pull SHDN/SILENT modes high or low (Teensy pins 2, 3).
The board has a jumper pad that should be cut to either control SHDN or S. I have not cut the trace, thinking I can just pull both low at the same time (maybe this is the mistake?).
I am using one of the examples sketches, just adding the pullup/down:

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;

const int sleepPin1 = 2;
const int sleepPin2 = 3;

void setup(void) {
  pinMode(sleepPin1, OUTPUT);
  pinMode(sleepPin2, OUTPUT);
  digitalWrite(sleepPin1, LOW);
  digitalWrite(sleepPin2, HIGH);
  
  can1.begin();
  can1.setBaudRate(250000);
  can2.begin();
  can2.setBaudRate(250000);
}

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);
  }
}

I am connecting to an 11B/250K CAN simulator. This is known working, tested with a different device.
I'm using CAN2 (pins 0, 1), pulling the appropriate function pin low (sleepPin1), but not getting anything at all from the Teensy. I have also tried removing the 120ohm resistor.
sleepPin2 is high to disable CAN1 (22, 23). I have a common ground with the simulator.
Any ideas are greatly appreciated.

IMG_2699.jpg
 
Back
Top