FlexCAN_T4 - FlexCAN for Teensy 4

There is no latency in entering and exiting the ISR? Don't the statuses need to be pushed and popped from the stack? That doesn't take any clock cycles?

What is the difference between calling events() in the loop of polling read() in the loop?

That is how two of the examples included on Github are written " if ( can1.read(msg) ) {".

Also the example mailbox_filtering_example_with_interrupts.ino is using interrupts and mailboxes specifically but also is calling .event() in the loop. Is this necessary? Or is this example utilizing both mailboxes and FIFO because I think FIFO is active by default and sense there is no "reject_all" filtering for set for FIFO so there is nothing inhibiting the reception of any frames?

Sorry for all the questions but given all the bells and whistles this thing has one could easily go down the rabbit hole and never be seen again.

Thanks

Bruce
 
the message struct is memmoved into the queue, thats not a performance hit, you can check how the queue actually works in Circular_Buffer.h. Calling events() will have the queue of frames while polling will most likely miss frames if not read fast enough. queue still uses interrupts, polling doesn't. As for mailbox filtering example i explained events() already, should be clear when you use it or not. you can use FIFO and mailboxes at same time for complexity sake, like have FIFO for less critical frames and mailbox for frame specific or priority critical data, with or without interrupts. maybe you just want each frame to have their own callback which you can assign for a task:

void car_vss(const CAN_message_t msg) { ... }
 
So by polling you mean if ( can1.read(msg) ) { which will read any mailbox which occupied or use an interrupt and set the call back in which you do not need to use the can1.read(msg)

And FIFO use .events() and you do not need to to call int readFIFO(CAN_message_t &msg);

Can you explain the difference between int read(CAN_message_t &msg); int readMB(CAN_message_t &msg);, int readFIFO(CAN_message_t &msg);? These function either poll all received messages (read), MB received messages (readMB) or FIFO received messages (readFIFO)?

Sorry for all the questions but I am coming from the world with SPI based CAN controllers which is a much simpler implementation.

Thanks

Bruce
 
SPI CAN controllers are more hit by SPI transfer performance, while integrated CAN controllers don't have that overhead as they are RAM accessed.

read() reads from either fifo or mb.
readmb() reads only from mailboxes
readfifo() reads only from fifo

mailboxes that are interrupt enabled will not be touched by the poll reads.

events() is optional for either fifo and/or mailboxes.
it's just there if you prefer not to have your callbacks, which may contain performance hit code if not done well, run directly off the ISR. it'll just queue it for the loop(). If you keep your callback quick and effecient, direct firing without queues is the best performance, by ommitting the events() in the loop.
 
So when and interrupt enabled the received data is copied to the message structure without read(msg).

If you enable interrupts for each of the 3 can controllers on the 4.1 then are 3 message structures created in the back ground to copy the received data too?

So you may have canSniff1(const CAN_message_t &msg1) {, canSniff2(const CAN_message_t &msg2) {, canSniff3(const CAN_message_t &msg3) { or would it be canSniff1(const CAN_message_t &msg) {, canSniff2(const CAN_message_t &msg) {, canSniff3(const CAN_message_t &msg)?

Typically ISR routine just sets a flag and then leaves the returns from the ISR then the flag is executed in the loop. So then when the flag is set I need to be able to process the data from the CAN controller associated with that flag.

Do I need to copy the msg structure in the ISR to a sperate structure so I know I am processing the correct data associated with each of the CAN controller?

Thanks

Bruce
 
you could also put all 3 controllers in the same callback. you can identify the frame source by reading msg.bus, which should return 1, 2, or 3
 
One hopefully not stupid question. Instead of FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> myCAN1; Can it be declared as FlexCAN_T4<CAN1, RX_SIZE_2, TX_SIZE_16> myCAN[1]; ?

This make thing a lot easier when calling things in a for loop.

Thanks
 
Would have have to declare myCAN[] in advance like and array?

You can't declare myCAN[1]...myCAN[3] you would need to declare myCAN[0],myCAN[1],myCAN[2]?

Thanks

Bruce
 
you won't be able to use the template as an array but you can use the base class to create an array of 3 pointers, one set to each of your bus, then that will work. I don't see a use in putting 3 controllers in an array though..
 
I am having trouble with mailbox interrupts.

I would like mailbox 0 to be interrupt enabled. (It is a response to a button being pressed)
The rest of the mailboxes I would like to just passively update when can0.events(); is called during the main loop. (These are just random stats like temperature, speed, etc.)

If I only have interrupts enabled for MB0, that is the only message that works. If I enable interrupts for all mailboxes (can1.enableMBInterrupts();), all of my mailboxes work.

Is can0.events(); in the main program loop the correct command to just passively read mailbox messages when there is time? It doesn't seem to be doing anything when interrupts are only enabled for mailbox 0. Am I doing something wrong here?


Code:
FlexCAN_T4<CAN0, RX_SIZE_256, TX_SIZE_16> can1;

void initCanT4(void){

  can1.begin();
  can1.setBaudRate(100E3);
  can1.setMaxMB(8);

  can1.setMB(MB0, RX, STD);
  can1.setMB(MB1, RX);
  can1.setMB(MB2, RX);
  can1.setMB(MB3, RX);
  can1.setMB(MB4, RX);
  can1.setMB(MB5, RX);

  can1.setMBFilter(REJECT_ALL);
  can1.enableMBInterrupt(MB0);
  can1.enableMBInterrupts();
  can1.onReceive(MB0,canSniff);
  can1.onReceive(MB1,canSniff);
  can1.onReceive(MB2,canSniff);
  can1.onReceive(MB3,canSniff);
  can1.onReceive(MB4,canSniff);
  can1.onReceive(MB5,canSniff);

  can1.setMBFilter(MB0, 0x1D6);
  can1.setMBFilter(MB1, 0x3B4);
  can1.setMBFilter(MB2, 0x1B4);
  can1.setMBFilter(MB3, 0x0A8);
  can1.setMBFilter(MB4, 0x0AA);
  can1.setMBFilter(MB5, 0x1D0);
  

  can1.onReceive(canSniff);

//  can1.mailboxStatus();

}
 
mailboxes that don't have interrupts enabled will not get your messages in the queue because you have to poll them using read(), events() is optional but read() will read non-interrupt mailboxes and interrupt queued mailboxes will not queue messages stored in non interrupt mailboxes, you must read() those instead
 
myCAN[i]

you won't be able to use the template as an array but you can use the base class to create an array of 3 pointers, one set to each of your bus, then that will work. I don't see a use in putting 3 controllers in an array though..

By creating 3 pointers you mean?:
Code:
FlexCAN_T4<CAN1, RX_SIZE_2, TX_SIZE_16> myCAN[0];
FlexCAN_T4<CAN2, RX_SIZE_2, TX_SIZE_16> myCAN[1];
FlexCAN_T4<CAN3, RX_SIZE_2, TX_SIZE_16> myCAN[2];

It is a lot easier/neater to call myCAN when you are trying to set up or process a bus than setting up case of if...then statements every time you need loop through each of the buses.

Thanks

Bruce
 
you can't have an array of template objects if constructor arguments are different, you need an array of base class pointers to achieve this
 
you can't have an array of template objects if constructor arguments are different, you need an array of base class pointers to achieve this

In the form of?:
Code:
static FlexCAN_T4_Base* myCAN[0];
static FlexCAN_T4_Base* myCAN[1];
static FlexCAN_T4_Base* myCAN[2];

FlexCAN_T4<CAN1, RX_SIZE_2, TX_SIZE_16> myCAN[0];
FlexCAN_T4<CAN2, RX_SIZE_2, TX_SIZE_16> myCAN[1];
FlexCAN_T4<CAN3, RX_SIZE_2, TX_SIZE_16> myCAN[2];

Sorry, but this is reaching the fringe of my C/C++ programming knowledge.

Thanks

Bruce
 
Code:
static FlexCAN_T4_Base* myCAN[3] = { nullptr };
FlexCAN_T4<CAN1, RX_SIZE_2, TX_SIZE_16> Can0;
FlexCAN_T4<CAN2, RX_SIZE_2, TX_SIZE_16> Can1;
FlexCAN_T4<CAN3, RX_SIZE_2, TX_SIZE_16> Can2;


//then in setup() somewhere
myCAN[0] = Can0;
myCAN[1] = Can1;
myCAN[2] = Can2;
 
Thanks for helping with my ignorance.

Code:
static FlexCAN_T4_Base* myCAN[3] = { nullptr };
FlexCAN_T4<CAN1, RX_SIZE_2, TX_SIZE_16> Can0;
FlexCAN_T4<CAN2, RX_SIZE_2, TX_SIZE_16> Can1;
FlexCAN_T4<CAN3, RX_SIZE_2, TX_SIZE_16> Can2;

bool StartCAN()
{
  myCAN[0] = Can0;
  myCAN[1] = Can1;
  myCAN[2] = Can2;
  return true;
}

I get the following error:

cannot convert 'FlexCAN_T4<(CAN_DEV_TABLE)1075642368u, (FLEXCAN_RXQUEUE_TABLE)2u, (FLEXCAN_TXQUEUE_TABLE)16u>' to 'FlexCAN_T4_Base*' in assignment

Any thoughts?

Thanks

Bruce
 
try = &Can1 ? the ampersand

Code:
static FlexCAN_T4_Base* myCAN[3] = { nullptr };
FlexCAN_T4<CAN1, RX_SIZE_2, TX_SIZE_16> Can0;
FlexCAN_T4<CAN2, RX_SIZE_2, TX_SIZE_16> Can1;
FlexCAN_T4<CAN3, RX_SIZE_2, TX_SIZE_16> Can2;

bool StartCAN()
{
  myCAN[0] = &Can0;
  myCAN[1] = &Can1;
  myCAN[2] = &Can2;
  myCAN[1].begin();
  return true;
}

Well that compiled fine until I tried to do something with it like add begin
error: request for member 'begin' in 'myCAN[1]', which is of pointer type 'FlexCAN_T4_Base*' (maybe you meant to use '->' ?)
myCAN[1].begin(); ^
So change
to
:

Then I get the following:
'class FlexCAN_T4_Base' has no member named 'begin'
myCAN[1]->begin();
^
Which makes send because FlexCAN_T4_Base doesn't have a begin.

"FCTP_CLASS class FlexCAN_T4 : public FlexCAN_T4_Base {
has a begin.

But the above mimic
_CAN1->setBaudRate(currentBitrate, (( FLEXCANb_CTRL1(_bus) & FLEXCAN_CTRL_LOM ) ? LISTEN_ONLY : TX));

So like I said this is stretching my knowledge to the limit.

Thanks

Bruce
 
the base class has basic virtual functions. use the regular templated objects for setting up the bus, use the pointers to write to the buses
 
the base class has basic virtual functions. use the regular templated objects for setting up the bus, use the pointers to write to the buses

There is no way to use the templated objects in such a manner.

Otherwise going to have to set up a lot if "case statement" to go through the set up of all 3 buses.

Any other thought on how to set this up on in a loop in a more efficient way than case statement?

Thanks

Bruce
 
what exactly do you want to set on 3 controllers at the same time? trying to figure out why you need to symmetrically control 3 ports? :)
 
myCAN[i]

what exactly do you want to set on 3 controllers at the same time? trying to figure out why you need to symmetrically control 3 ports? :)

I want to set everything up in a loop.

I have possibly 3 DBC files on the SD card. Read in and parsed into a structure. If there are PID's in the DBC file, the message ID is in a certain range so those are parsed into a PID structure.

So essentially you have DBC -> Message-> Signal or DBC -> Message - > PID -> Signal

So I am setting this up so the reception is in mail boxes so only 1 or two messages will get filtered for reception in each mail boxes so essentially the calculation path becomes:

MB ->Message->Signal or MB ->Message - >PID ->Signal with the calculation result stored in the signal structure for logging.

Thanks

Bruce
 
Back
Top