FlexCAN_T4 - FlexCAN for Teensy 4

@tonton81, sorry if I missed it in this thread - how does the queue work in the class template? Is it in terms of bytes or messages? In other words, using TX_SIZE_16 would queue two CAN 2.0 messages or 16 CAN 2.0 messages? Is memory allocated from the Teensy or some pool of memory internal to the FlexCAN library? What is the maximum queue size?
 
it's a template queue so it's on the stack since it's created at compile time not runtime, 16 would queue 16 message frames.
If you are not using events() and directly firing interrupts, the RX queues will not be used, but the transmit queues are always used.

You can use as much memory as you want as long as it's a power of 2, i added a few enums, if you need more you can add in the enum in the .H file and it will work with that

FlexCAN_T4 uses my Circular_Buffer library to store message queues as a circular array, so it can queue a struct converted to an array, and dequeue an array to convert back to a struct, while keeping the message frame details intact
 
it's a template queue so it's on the stack since it's created at compile time not runtime, 16 would queue 16 message frames.
If you are not using events() and directly firing interrupts, the RX queues will not be used, but the transmit queues are always used.

You can use as much memory as you want as long as it's a power of 2, i added a few enums, if you need more you can add in the enum in the .H file and it will work with that

FlexCAN_T4 uses my Circular_Buffer library to store message queues as a circular array, so it can queue a struct converted to an array, and dequeue an array to convert back to a struct, while keeping the message frame details intact

I'm assuming that if I'm using mailboxes, the RX queue wouldn't matter either since a new message would just overwrite the old one sitting in the mailbox?
 
yes it does matter as it saves the message making the mailbox available to receive again a new frame.

In interrupt mode (without events() being used), the message is fired directly to callback without using queues.

In interrupt mode (with events() being used), the ISR sends the mailbox frame directly to the queue where it can be dequeued to the callback via events() in loop().

In polling mode, message is read directly from mailbox and nothing is queued. Failing to read the messages will cause message overruns if the mailboxes are full.

In most cases people generally use direct interrupt firing, it works pretty well in my case, im using teensy 4.0 as a gateway (CAN3 Legacy mode) and dual CAN (CAN1 & CAN2) all with direct firing of callback
 
Hey guys,

I am getting "DBG NORM: -1" messages in my Serial Monitor but I don't know whats the meaning of them.
Sometimes it's single prints, the other time there als 3 prints.
I can't find something about this message neither in the .cpp or .h files nor in the IMXRT1062 PDF.

My second question is, whether there is possibility to slow down the bus request. I am splitting up CAN-FD frames to several CAN frames and my receiving CAN hardware is overstrained with the speed of the arriving CAN frames.

Thanks in advance
 
Thanks, the library was not up to date.

Another question - The CAN ID which I am setting is in the extended format (29 bit). When printing it to the Serial Monitor it shows the ID correctly either in decimal or hexadecimal (e.g. 0x13DD6510). But on the physical output (double checked with picoscope) it only sends 0x510 which matches an 11 bit ID.
Do I have to tell FlexCAN respectively the Teensy to use the extended format for my CAN Output instead of base format?
 
FIFO Filtering influence on MB Filters

OK, I have a new one.

So up to now I have been using MB filtering exclusively but for J1939 Network PGNs you need to mask them for that essentially only the PDU format and data page bits are used.

This is because you do not know the DA or the SA for the Network PGN.

So instead of using precious MB filters I thought I would use the FIFO user filters only for the network PGN's.

I am using the same call back function as the FIFO gives me MB 99 so it is easy to sperate the standard filtered messages ID from the DBC file and the J1939 network functions.

So initially you only need to see the address claim PGN so that is the only FIFO filter I am using when I send a J1939 network message 0x1CECFF00 which is already in the DBC I get nothing.

If I disable FIFO by disabling the J1939 network functions I am working on then the message is received by the mail box it should be received by.

If I reenable the FIFO using filter which corresponds with the ID both the correct MB and FIFO fire.

Alternatively I have set this up so I steal some of the MB's for the J1939 network PGN, both MB fires (MB filter and MB fifo filter).

Why would enabling FIFO by not receiving a message in FIFO which is equivalent to a MB filter inhibit the MB from firing?

Any ideas?

Thanks

Bruce
 
if both fire, did you run distribution() ? a match is copied if so to other mailboxes with matching filter, because normally only ONE mb/fifo fire, and if you have individual callbacks that use that frame it is basically first come first serve, the other callback won't fire, and if that callback also uses that frame it will just be lost. distribution() is the only thing that copies it to a queue of another MB (the queue with MB id) with matching filters.

also you can choose which reception has priority
FIFO first then MBs
or vice versa
 
Yes, I am using distribution() but that does not seem to stop both from firing. PS I do not care of both fire as I am using the FIFO for J1939 network messages only and I am using MB for the full filtering of the DBC message ID's. It is up to the user if they want to have J1939 network message PGN's in the DBC or not but if J1939 message are to be handled there must be reception of the ID's.

ISO is simpler in the fact the # of ID's are limited and then you handle the messages based on the content of the data but J1939 you must receive a wide variety of message ID's via PGN's and in the case of network messages you must receive based on the PGN formation and DP bits only. so 10 out of 29 bits are unique.

So I am not sure why when I am not receiving the FIFO I can not receive the MB? If I do not enable FIFO then everything works fine but if I enable FIFO but do not not have a filter set to receive the ID in question why doesn't the MB fire?
 
Also, do you always need "events"? I only added events with FIFO but when only using MB I never had "events" and only had interrupts.

Does it matter in the order for calling "distribute"? Do you do this after you set the filters, before, or does not matter?

Thanks
 
distribute should be run after filters are setup, events() isn't needed if you want fifo/mbs to receive. did you enableFIFOInterrupt? it's different than enableMBinterrupt, if not fifo is in polling state (loop read()). if that is the case fifo is receiving the message and filling while the MB doesn't receive it, and overrun is likely.
 
Yes both MB and FIFO interrupts are enabled.

Why would enabling FIFO stop MB from firing? As soon as enable the FIFO the MB stops responding?

I also tried setting priority to MB but that seemed to do nothing.

Does FIFO need to be set up before MB?

Thanks
 
they can be setup in any order and distribution must be ran last
I don't know your layout but FIFO occupies by default the first 8 mailboxes, which leaves you with MB8-15, and consider that the mailbox default with FIFO enabled is all transmit. Print out mailboxStatus() it will confirm this. You can then reassign the mailbox to be a reception one instead of transmit, but yeah enabling FIFO it defaults remaining MBs as transmit only, so filters are useless for transmits, they just won't receive unless you reconfigure them using setMB()
 
"I don't know your layout but FIFO occupies by default the first 8 mailboxes"

OK, that make a lot of sense now..... Did not understand that FIFO utilizes mailboxes....I thought they were seperate but equal so for me it makes not sense to use FIFO when I can use << 8 mailboxes to get the same job done.

Going back to only using Mail boxes.

Thanks
 
Teensy 3.x has 16 mailboxes, with FIFO that leaves 8 free.
Teensy 4.x has *up to* 64 mailboxes, with FIFO that leaves *up to* 56 mailboxes remaining

by default 16 is loaded, if you need more (or less), setMaxMB
for example if you wanted 1 transmit and 1 receive MB, setMaxMB(2).

if you really want 16 MBs WITH FIFO, then setMaxMB(16+8) (16 MBs, taking into consideration 8 for FIFO), your MBs would be from MB8-23 afterwards

FIFO also has 8 filters by default. You can increase this at a cost of consuming mailboxes. Example, if you have 16 mailboxes, and enable FIFO, you have FIFO and 8 mailboxes with FIFO supporting 8 filters (0-7). Now, if you wanted 16 filters instead of 8 for FIFO, it will consume 2 mailboxes. So, although the FIFO queue is always 6 messages deep, you have a FIFO that supports up to 16 filters (0-15) with 6 remaining mailboxes MB10-15. The value I listed for FIFO filters are indexes, and in no way does it relate to the MBx enums.

FIFO is also good if you wanted ordered receptions, unless you are running a single mailbox reception.
 
Last edited:
@tonton81 I'm sure you tested FlexCan on a Teensy MicroMod, but I am having trouble getting it to work on both the SkarkFun MM ATP board with an external transceiver as well as a custom carrier board.

I have a T4.1 set up to print out anything it recieves.
If I transmit from a T4.0 it work. If I transmit from a TMM it doesn't.

Here is the sketch I am using on the Teensy MM:
Code:
#include <FlexCAN_T4.h>
FlexCAN_T4<CAN3, RX_SIZE_256, TX_SIZE_16> Can0;

void setup(){
  while (!Serial && millis() < 5000);
  Serial.begin(115200);
  delay(1000);
  Serial.print(CrashReport);
  
  Can0.begin();
  Can0.setBaudRate(500000);
  Can0.enableMBInterrupts();
  Can0.onReceive(canSniff);
  Serial.println("FlexCAN ready");
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH);

}

void loop(){
Can0.events();
canSend();
delay(500);
digitalWrite(13, HIGH);
delay(500);
}


void canSend(){
 CAN_message_t msgTx, msgRx;
    msgTx.buf[0] = 0x07; 
    msgTx.buf[1] = 0x22;
    msgTx.buf[2] = 0xf4; 
    msgTx.buf[3] = 0x0b; 
    msgTx.buf[4] = 0x20; 
    msgTx.buf[5] = 0x2a; 
    msgTx.buf[6] = 0x10; 
    msgTx.buf[7] = 0xc0;
    msgTx.len = 8;            // number of bytes in request
    msgTx.flags.extended = 0; // 11 bit header, not 29 bit
    msgTx.flags.remote = 0;
    msgTx.id = 0x7E0; // request header for OBD
    msgTx.seq = 0;
    Can0.write(msgTx); 
    digitalWrite(13, LOW);
  
  
  }
void canSniff (const CAN_message_t &msg){
  digitalWrite(13, LOW);
  Serial.println(" ");
  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(" ");
    } 
}

Would you be able to run a test on your side?

EDIT: I can confirm CAN2 works on the MicroMod. But not CAN3.
 
Last edited:
The pins are CAN3, which is what Sukkin tested. But he tested CAN FD, not CAN.
CAN2 is on the tow pins above on the ATP board he used - these are the same pins I used to confirm CAN2 is working
 
One of the unique features of the Teensy is its ability to communicate with CAN devices. The Teensy MicroMod can receive CAN messages but in order to send them properly you will need a separate CAN transceiver. CAN-RX is tied to MicroMod pad 41 (Teensy pin 30) and CAN-TX is tied to MicroMod pad 43 (Teensy pin 31).

also make sure the CANRX and CANTX is not reversed?
 
Micromod Teensy and 3 CAN

I developed a board which uses all 3 CAN controller for the Micromod Teensy with the ATP board.

Micromod 3CANSD.jpg

All three controllers work as expected.
 
Have you tested CAN2.0 on CAN3 controller? Can you confirm it send and receives as expected?
 
Back
Top