FlexCAN_T4 - FlexCAN for Teensy 4

I havn't messed with CANopen so at the moment I couldn't give you an answer. If there is a library that uses it and it's working on teensy (most likely with old flexcan library), I may try to port it over. IFCT allowed alot of old flexcan library emulation for Teensy 3.2-3.6, but not adapted to T4 yet. Do you have an official link to teensy version of CANopen I could look at?
 
Hello and thank you for the reply.

Its my opinion that it will be many years until someone with the time and the skills will be able to claim the Full CANopen stack crown for a free library!
But i do know people have got various bits of the protocol working, so they can run CANopen devices but you can't call it a full blown stack implementation to the standards.

I would hope someone can back me up or put me straight on this, but i believe a very low overhead implementation will open up these CANopen devices and allow most of the functionality to be accessible, but with more work on the user end to send the can frames.

The Basic requirement would be :-

1) the NMT..... you will see references to this in the other library's (network management / state machine to deal with the process of passing into various stages of "On" / "off" / "standby" to put it simply, this relates to the CAN messages in my first post) but the NMT send out a heartbeat that bust be managed by the NMT.

2) POD transmit and receive.... so again if you can send messages in a frame you can turn a drive into a position or velocity mode for example then send it a value to run at.


https://github.com/jgeisler0303/CANFestivino
This is the only link that i believe comes close to running on Arduino....but it was for using the MCP2515 or the "Seeed CAN bus shield"


I did spend some / alot of time with a linux canopen library https://github.com/christiansandberg/canopen
this worked very well and full featured but was for python, and used on a beagelbone black single board computer....... so not sure if this is even useful ? but very well documented.


I hope this is useful information, and thank you for considering this.
 
the old flexcan library or the MCP library could be emulated with a dummy class that will forward their controls over to the latest flexcan driver. i dodn't say i'd write a canopen stack thats an entire new project on it's own, but if the library uses mcp2515 library then we only need to mimic the mcp2515 library with a dummy class to get right control over the new driver, we did emulation work in IFCT, but felt it kinda bloated the driver class, so a separate library with the dummy classes would be a suggested route to goto but best to find a well known and used canopen stack on arduino platform before we start diving into new classes :)
 
I saw pgchui attempt to do this and was having some issues with cansniff. I'm just trying to verify if my transceivers work. I'm using a teensy 4.1 using can1 and can 2 with SN65HVD230 to make sure they work since SN65HVD230 seem to have issues sometimes.

I'm not seeing anything printing on the serial monitor, I figured I would see something regardless if it is garbage or not.




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

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

void canSniff(const CAN_message_t &msg);

void setup() {
    Serial.begin(9600);
    can1.begin();
    can2.begin();
    can1.setBaudRate(1000000);
    can2.setBaudRate(1000000);
    can1.enableFIFO();
    can1.enableMBInterrupt(FIFO);
    can1.onReceive(FIFO, canSniff);
    can2.enableFIFO();
    can2.enableMBInterrupt(FIFO);
    can2.onReceive(FIFO, canSniff);
    delay(1000);
    Serial.println("CAN setup finished");
}

void loop() {
    can1.events();
    can2.events();
    if (Serial.available()) {
        char c = Serial.read();
        if (c == 'a') {
            Serial.println("Sending ...");
            CAN_message_t msg;
            msg.len = 8;
            msg.id = 0x321;
            msg.buf[0] = 1;
            msg.buf[1] = 2;
            msg.buf[2] = 3;
            msg.buf[3] = 4;
            msg.buf[4] = 5;
            msg.buf[5] = 6;
            msg.buf[6] = 7;
            msg.buf[7] = 8;

            can1.write(msg);

//            delay(100);
//            can2.read(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();
        }
    }
    delay(100);
}

void canSniff(const CAN_message_t &msg) {
    Serial.println("Interrupted");
    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();
}
 
are you looping the busses? do you have termination?

I'm not sure what you mean by looping. The transceivers are both terminated, I didn't remove them since I know the bus has to be terminated on both ends..

IMG_20200731_005125.jpg
IMG_20200731_005118.jpg

here is a picture of the setup
 
Change enableMBInterrupt(FIFO) to enableFIFOInterrupt() for both CAN channels. I think you may have found a bug (or at least an issue with the readme, which suggests this exact code).

Also, events() isn't needed if you have the latest version of FlexCAN_T4 library from https://github.com/tonton81/FlexCAN_T4/

@tonton81: I think enableMBInterrupt(FIFO) tries to writeIMASKBit(99), which is out of range.
 
Still no dice, I changed per msadie's suggestion:

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

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

void canSniff(const CAN_message_t &msg);

void setup() {
    Serial.begin(9600);
    can1.begin();
    can2.begin();
    can1.setBaudRate(1000000);
    can2.setBaudRate(1000000);
    can1.enableFIFO();
    can1.enableFIFOInterrupt();
    can1.onReceive(FIFO, canSniff);
    can2.enableFIFO();
    can2.enableFIFOInterrupt();
    can2.onReceive(FIFO, canSniff);
    delay(1000);
    Serial.println("CAN setup finished");
}

void loop() {
    if (Serial.available()) {
        char c = Serial.read();
        if (c == 'a') {
            Serial.println("Sending ...");
            CAN_message_t msg;
            msg.len = 8;
            msg.id = 0x321;
            msg.buf[0] = 1;
            msg.buf[1] = 2;
            msg.buf[2] = 3;
            msg.buf[3] = 4;
            msg.buf[4] = 5;
            msg.buf[5] = 6;
            msg.buf[6] = 7;
            msg.buf[7] = 8;

            can1.write(msg);

//            delay(100);
//            can2.read(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();
        }
    }
    delay(100);
}

void canSniff(const CAN_message_t &msg) {
    Serial.println("Interrupted");
    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();
}

EmptySerialMonitor.PNG

TeensySettings.jpg
 
It did a thing!

ItDidaThing.PNG

I'm not sure why it doesn't continue to update, and I also lost the ability to select the baud rate. Do you think because Serial.begin() is in the setup() and not loop() would cause this?
 
Serial.begin() belongs in setup().

Per your code, it will only display more if you type "a" in the line at the top of the serial monitor and hit Send.
 
yes msadie you're right, FIFO wasn't meant to be used in enableMBInterrupt(). I will have to set a limiter based on MAXMB size so people would be forced to use enableFIFOInterrupt() instead
 
Serial.begin() belongs in setup().

Per your code, it will only display more if you type "a" in the line at the top of the serial monitor and hit Send.

Well that's what I get for copying and pasting code without fully understanding it. At least the serial monitor part of it is figured out, thanks for the help so far guys!
 
Hello,

I am new in the CAN BUS world. Can you propose any document, what explains how FlexCAN work. I have read a lot of threads, but it is difficult to put all puzzles together. I could find details about the CAN BUS system itself, but I am searching a summary about the FlexCAN features, functions.

Thanks
 
Check the link in the first post, it has a large readme, plus there are a couple examples in there. Some brief comments about functions can be found in the source file, but if you are looking for registers and clocks, you need to check the IMXRT1062 release manual
 
Hello tonton81,

Thanks for your suggestion. I am reading them through.
No, I am not a programmer, so I dont need the very deep water(registers, clocks), just would like to understand basic things like the mailbox concept, FIFO, callback, mailbox with interrupts, and so on. It is also not clear, where finishes the CANBUS, and where start FlexCan in the features. So really basic thinks :)
I have just found a short explanation about the mailbox concept, so it is a little bit more clear now.
 
it is a bit confusing at first, think of each mailbox as a random queue to hold incomming frames, can also be referred to as a message box. if you have 64 mailboxes, without reading any of them, you can hold up to 64 message frames before you start loosing additional frames. the idea is to read them as fast as possible sp remaining vacant mailboxes can store new frames. the basic concept is usually sending and receiving, when you want to go more advanced and filter out frames, automatic filtering is there to help you :)
 
Ok, I see. How can I read always the last message with the same ID and remove the older not read messages?
I plan to use canbus for RC servo control. The main Teensy sends data in every 0.01s to the other Teensy, which generaters the RC PWM signal for the servos. So the most important think is to use the latest data. It is less problem, if 1-2 messages are lost.
Another theme: there is a place where the canbus wires is bended continuously, so it will brake after a certain time. I want to double there the canbus wires with a simple Y connection, and connect both to Teensy Can1, Can2. I plan to use data from one of them, but I want to monitor both Can ports, the messages arrive continuously. If not, I change the data source to the good Can port (if needed), and send warning message to the main Teensy. What would be the best way to program this process?
 
you can lower the mailbox count if needed, example, instead of 64 mailboxes, you can setup 8, so you can store up to 8 latest frames. or, with FIFO, you'll have 6 latest frames with 8 transmit capable mailboxes by default. you will always get latest frames, the frames you dont use you will just not use em so theyre tossed. essentially you will always have latest data
 
I have some more dumb questions for you, I read the readme at the beginning. Actually pretty helpful so sorry I was negligent in reading that. I think I was a bit overwhelmed by what was going on.

I am able to successfully transmit messages from the Teensy to the ecu that I am using. (YAY):cool:

Now I am trying to receive messages from the ecu back to the Teensy. My original thought was to just do a Can2.read(msg), but how do I go about manipulating the message (since the can packet is only able to hold 8 bytes of data and I have 2 bytes of data I want to manipulate). Is this where mailboxes come into play? Since the posts above me have been discussing that.

I hope I actually asked a question that makes sense, I will share my code but just know I'm still learning coding and it might not totally make sense.

Code:
#include <FlexCAN_T4.h>

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

uint16_t Analog_In_38;
bool Digital_In_28;
bool Digital_In_29;
float Engine_RPM;
int8_t CoolantTempIn;
int8_t CoolantTempOut;
bool CoolFanStatus;
bool CoolPumpStatus;
byte EngineRPM_MSB;
byte EngineRPM_LSB;

void setup(void) 
{
  pinMode(28,INPUT_PULLUP);
  pinMode(29,INPUT_PULLUP);
  pinMode(30,INPUT_PULLUP);

  Can2.begin();
  Can2.setBaudRate(1000000);
  
}

void loop() 
{
  Digital_In_28 = digitalRead(28);
  Digital_In_29 = digitalRead(29);
  Analog_In_38 = analogRead(38);

  byte Analog38_LSB = Analog_In_38 & 0x00FF;
  byte Analog38_MSB = Analog_In_38 >>8;

  msg.id = 0x500;
  msg.len = 8;
  msg.buf[0] = Analog38_MSB;
  msg.buf[1] = Analog38_LSB;
  msg.buf[2] = Digital_In_28;
  msg.buf[3] = Digital_In_29;
  msg.buf[4] = 128;
  msg.buf[5] = 64;
  msg.buf[6] = 32;
  msg.buf[7] = 16;

  Can2.write(msg);
  Can2.read(msg);


  msg.id = 0x1001;
  msg.len = 8;
  msg.buf[0] = EngineRPM_MSB;
  msg.buf[1] = EngineRPM_LSB;
  msg.buf[2] = CoolantTempIn;
  msg.buf[3] = CoolantTempOut;
  msg.buf[4] = CoolFanStatus;
  msg.buf[5] = CoolPumpStatus;
  msg.buf[6] = 0;
  msg.buf[7] = 0;

  byte lowByte=msg.buf[1];
  byte highByte=msg.buf[0];
  Engine_RPM = ((int) highByte << 8 )| lowByte; 

  Serial.print("Analog38LSB:");
  Serial.println(Analog38_LSB);
  Serial.print("Analog38MSB:");
  Serial.println(Analog38_MSB);

  Serial.print("Digital 28 is:");
  Serial.println(Digital_In_28);
  Serial.print("Digital 29 is:");
  Serial.println(Digital_In_29);
  Serial.print("Analog 38 is:");
  Serial.println(Analog_In_38);
  Serial.print("Engine_RPM:");
  Serial.println(Engine_RPM);
  delay(250);

}
 
Last edited:
think of a mailbox as just a queue. now all your data is in queues.

When you do a Can2.read(msg), that is actually polling the mailboxes, and not interrupt driven. You can start with that for now and if you deem your CAN traffic is critical, you can move to interrupt mode.

now when you do a read(), your "msg" frame is updated (if a frame os available. you however didnt check the data and instead overwrote it, check
Code:
Can2.write(msg);
  Can2.read(msg);

msg should have new frame data, but then you overwrite it.
read the variables and see what data you get
 
think of a mailbox as just a queue. now all your data is in queues.

When you do a Can2.read(msg), that is actually polling the mailboxes, and not interrupt driven. You can start with that for now and if you deem your CAN traffic is critical, you can move to interrupt mode.

now when you do a read(), your "msg" frame is updated (if a frame os available. you however didnt check the data and instead overwrote it, check
Code:
Can2.write(msg);
  Can2.read(msg);

msg should have new frame data, but then you overwrite it.
read the variables and see what data you get

Was able to get it work, thanks for all the help (and the patience!) you too msadie
 
Hey guys, I've run into a problem using Teensy 4.1 Flexcan_t4 and I2C. So for reference, i have a Teensy 4.1 driving a pair of nextion screens displaying data from an ecu as a dashboard. I have 2 separate Can lines, one from the ecu and another for inputs from external sensor modules. Everything is working absolutely fine on the canbus side of things but here is where the problem comes to light. I have a 10 degrees of freedom (GY-87) module i am trying to connect for altitude and g force data via I2C. Before connecting it to the Dash setup, had written and tested and calibrated the I2C commands and back end math with a Teensy 4.0 so i know the code is correct on that front. Once connected to the Teensy 4.1 i started getting some readings from the sensor that are way out of whack. After trying a bunch of stuff, i found that by commenting out the call lines that calls on the routine that reads from the two Canbus lines, the data from the GY-87 is correct.

I have tried combinations of moving between the Can1, Can2 and Can3 inputs but no matter what i do, if Can is read on any one of the channels, the I2C data goes out of whack. Has anyone come across a conflict between can and I2C that might shed some light on the situation? Also, is there a way to end the can library in the sub routine as so i can start the library and stop the library in the subroutine as a crude work around? something like a Can0.end()??
 
Back
Top