FlexCAN_T4 - FlexCAN for Teensy 4

have you tried starting the I2C before and after flexcan begin?
do you have a sketch?
have you tried different I2C clockspeeds?

did you try modifying the flexcan clock?
Canx.setClock(CLK_60MHz) - check source for different values
 
Last edited:
Ok, so tried to move the <Wire.h> and <FlexCAN_T4> include statements before and after each other. Tried beginning the wire library before and after the can libraries and tried all available Wire.setClock(); speeds including; 10000, 100000, 400000, 1000000 and 3400000. For everything that i changed, the only thing that displays the correct data is if i don't call the can read subroutines
 
And the can clock speeds are already set to 60MHZ.

#include <FastTouch.h> // capacitive touch library
#include <EEPROM.h> // eeprom access memory
#include <FlexCAN_T4.h> // flexcan library for teensy
#include <Wire.h> // I2c wire library
//#include <ds3231.h> // RTC library
#include <stdio.h> // 10 DOF GY-87
#include <math.h> // 10 DOF GY-87
#include "I2Cdev.h"
#include "HMC5883L.h"
#include <nRF24L01.h> // Radio comms library (MUST BE AFTER FLEXCAN)
#include <RF24.h> // Radio comms library
#include <SPI.h> // SPI comms library

void setup()
{
Serial.begin(115200);
Serial.println("5 inch NEXTION DISPLAY");

Serial.println("I2C begin"); // begin i2c
Wire.setSDA(18); // declare SDA pin
Wire.setSCL(19); // declare SCL pin
Wire.begin(); //start i2c (required for connection) to REAL TIME CLOCK
Wire.setClock(400000);

Serial.println("CAN2 begin"); // can2 begin
Can0.begin();
Can0.setBaudRate(500000); // can2 set baud
Can0.setClock(CLK_60MHz); // can2 clock speed
Can0.enableFIFO(); // can2 fifo
// Can0.enableFIFOInterrupt(1);
// Can0.mailboxStatus();

Serial.println("CAN1 begin"); // can1 begin
Can1.begin();
Can1.setBaudRate(500000); // can 1 set baud 500kb/s
Can1.setClock(CLK_60MHz); // can 1 clock speed
Can1.enableFIFO(); // can 1 fifo
// Can1.enableFIFOInterrupt(1);
// Can1.mailboxStatus();
 
found the problem? I don't think the I2C has any influence on flexcan it should work fine, the triple CAN board from skpang uses an I2C display addon.
 
Hey tonton81,

here is the loop and sub routines;
if i comment out both CAN_READ(CANREP); and CAN1_READ(CANREP); so that can is not read by the subroutine at all, the i2c data is fine, as soon as can is read, the i2c data changes

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP //

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


void loop() {

op_timer = micros();

if ((op_timer - op_gy87) > 20)
{
GY87_READ_SENSORS(); // request I2C data from GY-87
if(SHOW_GY87 == 1){GY87_DISPLAY_DATA();} //display GY-87 data on serial if enabled
op_gy87 = micros();
}

CAN_READ(CANREP); // read Can2 (repeat CANREP number of times)
CAN1_READ(CANREP); // read Can2 (repeat CANREP number of times)
SERIAL_READ_RH(5); // read serial from right screen 5 times
SERIAL_READ_LH(5); // read serial from left screen 5 times
READ_TOUCH();



LED_WARN();
CONSUMPTION(); // updates consumption data from flow meter data

if ((op_timer - op_nextion) > 1000)
{
UPDATE_NEXTION(); // update Nextion screens
op_nextion = micros();
}
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// CAN2 READ CAN2 READ CAN2 READ CAN2 READ CAN2 READ CAN2 READ CAN2 READ CAN2 READ //

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void CAN_READ(int rep) {
//Serial.println();
//Serial.println("READ CANBUS 2");
for ( int i = 0 ; i < rep ; i++)
{

if (Can0.read(rxmsg))
{
len = rxmsg.len;
CANRXID = rxmsg.id;

if (SHOW_CAN == true)
{
Serial.println(); Serial.print("RAW ID> "); Serial.print(CANRXID); Serial.print(" RAW LEN> "); Serial.print(len);
}

CONVERT(); // switch case populate can data into variables and conversion calculations

sprintf(msgString, "Standard ID: 0x%.3lX DLC: %1d Data:", CANRXID, len);
if (SHOW_CAN == true) {
Serial.print(msgString);
}

if (SHOW_CAN == true)
{
for (byte i = 0; i < len; i++)
{
sprintf(msgString, " 0x%.2X", rxmsg.buf);
Serial.print(msgString);
int NUMb = rxmsg.buf;
Serial.print(" ("); Serial.print(NUMb); Serial.print(")");
}
Serial.print(" MICROS "); Serial.print('\t'); Serial.println(micros());
}
}

// Can0.mailboxStatus();
}
UPDATE_VARIABLES(); // update variable database
delayMicroseconds(CANDELAY);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// CAN1 READ CAN1 READ CAN1 READ CAN1 READ CAN1 READ CAN1 READ CAN1 READ CAN1 READ //

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void CAN1_READ(int rep) {
// Serial.println("READ CANBUS 1");
for ( int i = 0 ; i < rep ; i++)
{

if (Can1.read(rxmsg))
{
len = rxmsg.len;
CANRXID = rxmsg.id;

if (SHOW_CAN == true)
{
Serial.println(); Serial.print("RAW ID> "); Serial.print(CANRXID); Serial.print(" RAW LEN> "); Serial.print(len);
}

CONVERT(); // switch case populate can data into variables and conversion calculations

sprintf(msgString, "Standard ID: 0x%.3lX DLC: %1d Data:", CANRXID, len);
if (SHOW_CAN == true) {
Serial.print(msgString);
}


if (SHOW_CAN == true)
{
for (byte i = 0; i < len; i++)
{
sprintf(msgString, " 0x%.2X", rxmsg.buf);
Serial.print(msgString);
int NUMb = rxmsg.buf;
Serial.print(" ("); Serial.print(NUMb); Serial.print(")");
}
Serial.print(" MICROS "); Serial.print('\t'); Serial.println(micros());
}
}

// Can1.mailboxStatus();

}

delayMicroseconds(CANDELAY);
UPDATE_VARIABLES(); // update variable database
if (SHOW_DATA == true)
{
DISPLAYDATA();
}
}
 
the subroutine reads the canbus and sends the data to CONVERT(); a conversion routine which bitshifts, does some math and populates a data array for ecu values based on the canrx id. So the CAN side of things works fine but as soon as it is executed it corrupts the incoming data from I2C
 
very odd, there is no trickery in the read (polling) function, and it doesn't play with timers, interrupts, or other hardware, just reads the memory of the mailbox, what happens if you comment out all those functions CAN_READ and just put a dummy Can0.read(msg) in the loop without handling it?
 
Just wanted to say thanks for this library. Was able to test all 3 can channels concurrently on T4.1. Test was listen only, for now, 3 separate buses.

Can anyone confirm that can2 & can3 alternate pins are not available on the T4.1?
 
the only difference between 4.0 and 4.1 is that CAN3 has been routed to pins 30 and 31 at edge of board, the other CAN1 and CAN2 have same regular and alternate pins. It's already updated in the library
 
Hello,

Can anybody help me to understand, how to use the Waveshare can transceiver SN65HVD230 chip? I want to close the canbus ends with 2pcs separated 120 ohm resistor, so I dont need resistor on the transceiver board. Can I turn it off somehow? There is a jumper on the board, but if I close it, it make a short between the canH and canL, what is not good I think (what is the function of this jumper?). I have removed the resistor from the board, and now I can measure 70ohm between canH and canL. I hoped there will be a brake between them. So now I am lost.

Thanks
 
Looking at pictures of that board, the "jumper" on the board is probably not meant to be a jumper. More likely its just a 2pin 0.1inch header for connecting to CAN_H/CAN_L. You can connect via this header and/or via the screw terminals. I have no guess as to why you are measuring 70ohms between CAN_H and CAN_L with no termination resistors connected.
 
Pin 14&15 is not CAN3.

Try and use
FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> can1;

On pin

CRX1 pin 23
CTX1 pin 22.
 
I have got the answer from the support, I can remove the 120 ohm resistance. I hope it will work. It would be very simple to make a jumper or dip-switch for this function.
 
looks good, what kinda transceiver you are using? some have reported to be reading fine but not transmitting

Code:
CAN.sendMsgBuf(5376, 1, 2, canMsg)

try specifying length of 2? on new code your specifying 8

Some ecus are specific to responding to certain lengths
 
Last edited:
can you plug in your other mcu, just as a reader, to see if teensy is actually sending something on the bus?

also check your bus termination, your old CAN board may have been using a resistor and your new transceiver isn't. both ends of the bus must be properly terminated

you can test this with a resistance meter on the CANH/L contacts of breakoutboards while theyre disconnected. if you have a 120 or 60 ohm resistance on old board, you need to make sure the transceiver on T4 is equivalent
 
Last edited:
Hello, I just got a Teensy 4.1 a few days back and have been trying to get CAN examples working. Yesterday I just discovered this forum which point to the source repository so I downloaded the latest FlexCAN_T4-master.zip and unpacked and did a diff with version I had in Arduino library which turned out to be an older version. Still have same issue with latest library.

I've direct wired CAN1TX - CAN2RX and CAN1RX to CAN2TX (teensy pins 23-1, and 22-0), no can driver chip in use. I've been attempting to transmit msg from one port and receive on the other, using some modified examples. It appears the transmit works, but nothing is received. I see activity on the lines with a scope.

Today I tried loopback mode and that works as I'd expect with both ports.

Loopback test:
#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,msgout;

#if 1
#define CANX can1
#define CANNAME "CAN1"
#else
#define CANX can2
#define CANNAME "CAN2"
#endif

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);
delay(1000);
Serial.println(F("Hello Teensy 4.1 CAN Loopback Test."));
CANX.begin();
CANX.setBaudRate(250000);
CANX.mailboxStatus();
CANX.enableLoopBack(1);
delay(9000);
msgout.flags.extended = 0;
msgout.id = 0x100;
msgout.len = 8;
msgout.buf[0] = 10;
msgout.buf[1] = 20;
msgout.buf[2] = 0;
msgout.buf[3] = 100;
msgout.buf[4] = 128;
msgout.buf[5] = 64;
msgout.buf[6] = 32;
msgout.buf[7] = 16;
}
static int iteration = 1;

void loop() {
msgout.id = 0x100;
if(CANX.write(msgout)){
Serial.print("Msg sent on ");
Serial.println(CANNAME);
}
msgout.id = 0x101;
msgout.buf[7] += 1;
if(msgout.buf[7] == 0) msgout.buf[6] += 1;
delay(5);
// CANX.mailboxStatus();
// delay(800);

if ( CANX.read(msg) ) {
Serial.print(CANNAME);
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: ");
hexDump(msg.len, msg.buf);
Serial.print(" TS: "); Serial.println(msg.timestamp);
}
Serial.print("Iteration ");
Serial.println(iteration++);
delay(5);
while(iteration > 8); //hang here
}

Direct wired test:
=========================================================
#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,msgout;

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);
delay(1000);
Serial.println(F("Hello Teensy 4.1 dual CAN Test."));
can1.begin();
can1.setBaudRate(250000);
can2.begin();
can2.setBaudRate(250000);
can1.mailboxStatus();
can2.mailboxStatus();
delay(9000);
msgout.flags.extended = 0;
msgout.id = 0x100;
msgout.len = 8;
msgout.buf[0] = 10;
msgout.buf[1] = 20;
msgout.buf[2] = 0;
msgout.buf[3] = 100;
msgout.buf[4] = 128;
msgout.buf[5] = 64;
msgout.buf[6] = 32;
msgout.buf[7] = 16;
}
static int iteration = 1;

void loop() {
msgout.id = 0x100;
if(can1.write(msgout))
Serial.println("Msg sent on can1");
msgout.id = 0x101;
msgout.buf[7] += 1;
if(msgout.buf[7] == 0) msgout.buf[6] += 1;
/* if(can2.write(msgout))
Serial.println("Msg sent on can2");
msgout.buf[7] += 1;
if(msgout.buf[7] == 0) msgout.buf[6] += 1;
*/
delay(100);
// can1.mailboxStatus();
// can2.mailboxStatus();
// delay(800);

/* 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: ");
hexDump(msg.len, msg.buf);
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: ");
hexDump(msg.len, msg.buf);
Serial.print(" TS: "); Serial.println(msg.timestamp);
}
Serial.print("Iteration ");
Serial.println(iteration++);
delay(100);
while(iteration >8); //hang here
}
 
Interesting data sheet, but in my case I am not connecting connecting multiple TX lines together. In my final application I will be using CAN transceivers to talk with remote systems, this is just a sanity check step to test out the library function, etc.

Can someone explain why connecting the TX output of 1 CAN channel to the single RX input of another should not work. I don't see anything in the electrical spec that should be an issue, but perhaps I'm missing it , the data manual is over 3000 pages after all. Does the RX require a pull-up? If this is the case I would have assumed internal pull-up would have been initialized by the driver. I guess I'll look into that.
 
Back
Top