FlexCAN_T4 - FlexCAN for Teensy 4

The ISR's only job is to queue it.into.the.buffer and exit, if enough frames can fill the queue before you finish pulling them the oldest, excess frames in the queue will be discarded. The background callback is if you want to handle the frame from within the ISR context, and not later via the queue. Running events() as fast as possible is your way to reading all the queues without having it fill to max and start discarding stale frames.

The fact that the ISR is so fast to clear the mailbox doesn't allow for overflow to next mailbox, is reason why only MB2 is picking up frames, as the first RX MB. You need to process events() as soon as possible to leave room for other frames to drop into the queue from the ISR. If you delay 500ms for events() and 20 frames come in, ISR puts them in queue, and you run events ONCE, theres 19 left to do. Delay again, 20 more frames, your up to 49,events() runs ONCE, your at 48 left. You need to process events as fast as possible, not let it wait on delayed code

Rezo thats fine, you can definately go faster if you want
 
Last edited:
Thanks for the confirmation tonton.

I have another question.

I some of my calculations of the response, I am placing some of the data into formula's based on my requests (filter based on header ID and the first 3 bytes of the frame).
In one of my formulas I need to treat the 5th byte as a signed int.

Here is a cut portion of my code (it has some sensitive data in the code that I don't want to share publicly):
Code:
 while (waiting < 60) {   //Check for timeout

    if(Can0.read(can_MsgRx)) { 


                    #define a can_MsgRx.buf[4]
                    #define b can_MsgRx.buf[5]
                    #define c can_MsgRx.buf[6]
                    #define d can_MsgRx.buf[7]


    return ((signed(a) * 256) + b) * 0.01;
    }
 }

Here is an example of the last 4 bytes:
FF 90 AA AA

What I expect to see is 0xFF = -1 and 0x90 = 144. And in the formula: ((-1*256) + 144) * 0.01 = -1.12
But what I get is 0xFF = 255 and 0x90 = 144. And in the formula ((255*256) + 144) * 0.01 = 654.24


Now for some reason it's treating can_MsgRx.buf[4] as an unsigned int and not a signed int.

I looked into the FlexCAN_T4.h file and noticed that the buffer within the CAN_message_t constructor is declared as an unsigned 8 bit integer. Could this be the reason I can't treat it the 4th byte as a signed integer?
Is there a workaround for this? Or am I talking complete rubbish? (I'm a real noob when it comes to C++)
 
No, this is a driver made for the internal controller, which is much faster than the MCP2515 and without the SPI overhead, is there a reason why you want to use a 2515 when you have a much better built in one?
 
No, this is a driver made for the internal controller, which is much faster than the MCP2515 and without the SPI overhead, is there a reason why you want to use a 2515 when you have a much better built in one?

The reason is that I have to work at 307.2 kbps, and I found that is only possible with certain oscillators, that I can change on mcp2515 board
 
Last edited:
I am not sure the tolerance on T4, T3 ran off a CAN clock of 16MHz and T4 can run up to 60MHz, so the timings might be possible, I don't have the tools to test the theory though.
 
I am not sure the tolerance on T4, T3 ran off a CAN clock of 16MHz and T4 can run up to 60MHz, so the timings might be possible, I don't have the tools to test the theory though.

I did all the possible combination of internal Teensy clock, unfortunaly there is the need of an oscillator that is a multiple of power of 2, like an 6.144 MHz, so that 307.2kbps is an integer multiple of the input clock
 
Hi,

I'm doing a lot of saving and transferring with the data that I'm logging off of CAN and CANFD networks, and I've encountered 2 obstacles:

1)
How does the library handle the Cyclic Redundancy Check field of the CAN and CANFD messages? And how can I access them?

2)
How can I set listen_only mode (no acknowledge) on the CAN and CANFD transceivers?
 
I've finally got all my hardware in place so I can start testing - but I've run into an issue.

I can't seem to receive frames with BRS enabled on my Teensy. As soon as I enable that bit (in CANalyzer 11 Pro's Interactive Generator), the Teensy apparently stops acknowledging the message.

What works:
Sending messages Teensy -> Interface (BRS disabled, 8 - 64 bytes)
Sending messages Teensy -> Interface (BRS enabled, standard, 8 - 64 bytes)
Receiving messages Interface -> Teensy (BRS disabled, 8 - 64 bytes)

What does not work:
Receiving messages Interface -> Teensy (BRS enabled, 8 - 64 bytes)

I'm using an MCP2558FD, connected to FlexCAN3 on my Teensy 4. The MCP2558FD is split terminated (60-60 Ohm with 4700 pF). From there, wiring to my VN5610A with a 120 Ohm termination adaptor.
Baud rates are 500k / 2000k

edit: Hmm, works for now. No idea what I changed though. Anyways - thanks for your awesome library!
 
Last edited:
Absolutely loving this library but I'm afraid I'm going to continue to be a nuisance :eek: :D
I need to get all 3 of the Teensy4's CAN transcievers working and in LISTEN_ONLY mode.
Currently I have them all working and the CANFD in LISTEN_ONLY mode, but am having trouble getting the other 2 CANs to join it!
Here's a cut down sketch that replicates the issue:
Code:
#include <FlexCAN_T4.h>
FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> Can1;

void setup() {
  Can1.begin();
  Can1.setBaudRate(500000, LISTEN_ONLY);
}

void loop() {

}

produces error

Code:
sketch_feb21a: In function 'void setup()':
sketch_feb21a:6: error: no matching function for call to 'FlexCAN_T4<(CAN_DEV_TABLE)1075642368u, (FLEXCAN_RXQUEUE_TABLE)256u, (FLEXCAN_TXQUEUE_TABLE)16u>::setBaudRate(int, FLEXCAN_RXTX)'
   Can1.setBaudRate(500000, LISTEN_ONLY);

                                       ^

In file included from C:\############\sketch_feb21a.ino:1:0:

C:\############\libraries\FlexCAN_T4/FlexCAN_T4.h:279:18: note: candidate: void FlexCAN_T4<_bus, _rxSize, _txSize>::setBaudRate(uint32_t) [with CAN_DEV_TABLE _bus = (CAN_DEV_TABLE)1075642368u; FLEXCAN_RXQUEUE_TABLE _rxSize = (FLEXCAN_RXQUEUE_TABLE)256u; FLEXCAN_TXQUEUE_TABLE _txSize = (FLEXCAN_TXQUEUE_TABLE)16u; uint32_t = long unsigned int]

 #define FCTP_OPT FlexCAN_T4<_bus, _rxSize, _txSize>

                  ^

C:\############\libraries\FlexCAN_T4/FlexCAN_T4.tpp:459:16: note: in expansion of macro 'FCTP_OPT'

 FCTP_FUNC void FCTP_OPT::setBaudRate(uint32_t baud) {

                ^

C:\############\libraries\FlexCAN_T4/FlexCAN_T4.h:279:18: note:   candidate expects 1 argument, 2 provided

 #define FCTP_OPT FlexCAN_T4<_bus, _rxSize, _txSize>

                  ^

C:\############\libraries\FlexCAN_T4/FlexCAN_T4.tpp:459:16: note: in expansion of macro 'FCTP_OPT'

 FCTP_FUNC void FCTP_OPT::setBaudRate(uint32_t baud) {

                ^

Multiple libraries were found for "FlexCAN_T4.h"
 Used: C:\############\libraries\FlexCAN_T4
no matching function for call to 'FlexCAN_T4<(CAN_DEV_TABLE)1075642368u, (FLEXCAN_RXQUEUE_TABLE)256u, (FLEXCAN_TXQUEUE_TABLE)16u>::setBaudRate(int, FLEXCAN_RXTX)'

This has worked on Can3 using CANFD:
Code:
#include <FlexCAN_T4.h>
FlexCAN_T4FD<CAN3, RX_SIZE_256, TX_SIZE_16> Can3;

void setup() {
  Can3.begin();
  Can3.setBaudRate(500000, LISTEN_ONLY);
}

void loop() {

}

How can I setup my CAN transcievers to be LISTEN_ONLY as well as the CANFD that I have already working?
 
Updated FlexCAN_T4 CAN2.0 interface to support listen-only mode.
Also posted a simple FIFO demo with interrupts - not relevant to your code, just for general use.

domRG, this should work now:
Code:
Can1.setBaudRate(500000, LISTEN_ONLY);
 
Last edited:
Hoping for a little guidance - working on a car data display/gauge project (among other functionality). First step was what I thought would be simple - getting data over CAN from my Megasquirt ECU and displaying it over the serial monitor. After some fiddling around, I was at least able to see the correct ID for the ECU (I changed it to a different value and the displayed value changed accordingly).

However, I can't seem to get correct/any/changing data in the buf object (zeros for the first 8 bytes). If I read out more than the first 8 bytes, I start seeing non-zero data (out to maybe 150 bytes?), but it is all unchanging, except for a single btye (9th) that cycles from 0 to 3. I've previously had success pulling CAN data from the ECU with an Uno and CANBUS shield, so I don't think it's an issue on the Megasquirt side, but rather my lack of skill with this library...

I was doing a pretty basic if(myCan.read(rxmsg)) { print stuff}, which shows the correct ID (1512 by default with Megasquirt). Should I be doing something else? I can post more details and some code when I get back to my laptop.

Reference for Megasquirt CAN, I'm using the stuff in chapter 2:
http://www.msextra.com/doc/pdf/Megasquirt_CAN_Broadcast.pdf
 
I realized that reading buf[] out past msg.len was probably just giving me some other memory, so totally meaningless for the CAN data (oops!).

To maybe more narrowly define my issue, I expect to see data on IDs 1512, 1514, 1515, and 1529 (I have those IDs enabled, all others disabled for now). But so far anything I've tried is only showing messages from 1512, which should contain ECU-power-on duration, injector pulsewidths, and RPM, but shows as all zeros. I'm guessing the fact that I'm receiving anything at all (ID) should rule out wiring issues? I haven't added a terminating resistor, but there's one included in the Megasquirt (I'll double-check the resistance of the bus later). I'll also double-check with my Uno/shield setup to rule out any issues with the Megasquirt.

Oh, one other curious thing - the serial monitor is printing new lines MUCH faster than 5Hz...

Here's a very slightly modified version of the library example with the received output:
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); /* optional tranceiver enable pin */
  Can0.begin();
  Can0.setBaudRate(500000);
  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);
  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 > 200 ) {
    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();
  }

}

megasquirt_CAN_no_data.jpg
 
Definately weird, do you have a CAN analyzer to confirm results in the stream? Are you running the latest version on github (although this has never been reported at all till now?). If not, do you have a vehicle you can connect the CAN bus to to verify data stream?
Is your transceiver enabled? Usually there needs to be a termination at both furthest ends of the bus.
 
Tried my old Uno/CANBUS shield setup, worked perfectly right away with no changes to the Megasquirt. Accurately reads RPM, injector pulsewidth, etc. The shield doesn't seem to have a terminating 120ohm resistor built in (the Megasquirt does, and with shield plugged into Megasquirt I get 120ohm, shield by itself is 50kohm).
The CAN transceiver I'm using (this one) with the T4 has a built-in resistor, so plugged into Megasquirt I get 60ohm. Doesn't have an enable pin, just 3v3, GND, CANH/L, and CANRX/TX. Doesn't seem like the issue lies with any wiring.
Downloaded the library a few days ago. Deleted the default FlexCAN and FlexCAN_T4 libraries that installed with teensyduino (from the program files/arduino/hardware/teensy folder structure).
 
That breakout has a 120 ohm resistor surface mount on it, it may be throwing the data off, its between CANH and CANL, you could break it off with pliers and try without or with a smaller resistance, make sure you have common grounds, it could also possibly be a bad/incompatible transceiver

Aparently your specific transceiver has issues posted on the net
Here is one article: https://spin.atomicobject.com/2017/05/06/troubleshooting-can-bus-communication-subaru/

He changed the tranceiver to a different model in the end and was running fine
 
Last edited:
Thanks, I will give that a try. I've got a different SN65HVD230 board on the way too (one that has worked with a Teensy 3.2 and Megasquirt). It was set up with a 10k resistor from RS to ground, I jumpered it to set it to high speed mode, no change. Was going to try removing the 120ohm resistor next... I also have logic level shifters on hand (Megasquirt is 5V). This is just a bench setup at the moment with short jumper wires, btw.
 
I'm using CAN1, so pins 22 and 23. I can try swapping them, but I do get the correct base ID of the Megasquirt to show up correctly, just no data and not enough IDs, and messages being printed at a much higher frequency than the Megasquirt is sending them... So maybe a problem with the transciever. I do have one of those Waveshare boards on the way in case there's an issue with the one I've been using.
 
Back
Top