IFCT - Improved Flexcan Teensy Library

Status
Not open for further replies.
Please check the simple examples posted with the library, it shows you how to send/receive the 8 bytes.
You can do your 32 bit conversions before/after if necessary :)
 
Code:
void loop() {
  CAN_message_t msg;
  if ( Can0.read(msg) ) canSniff(msg);
}

void canSniff(const CAN_message_t &msg) {
  Serial.print("MB "); Serial.print(msg.mb);
  Serial.print("  LEN: "); Serial.print(msg.len);
  Serial.print(" EXT: "); Serial.print(msg.flags.extended);
  Serial.print(" REMOTE: "); Serial.print(msg.rtr);
  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();
}

I'm unsure of if FIFO is what im after. Basically what Id want is to do would be to

Code:
X = Can0.read(0x234) // read a specific CAN ID and address is to a variable. is this possible? I know my nomenclature is going to be wrong but I hope you get what I'm trying to achieve.

or do I do a

Code:
if(msg.id = 0x234)
{
  for ( sint8_t i = 0; i < msg.len; i++ ) 
 {
    b =x*10
    a=msg.buf[i]
    x = b+a       // makes it a single string of bits
  }

}


Sorry I am a total nub at CAN messages.
 
it’s just an array of 8 bytes, by default it will pickup all IDs however you can filter it in callback via software or hardware via filtering.

your second code is software filtering but yeah that’s acceptable.
you can just set the variable to X = msg.id; .
Since that is a standard frame ID it uses 11bits, I would still use 32bit unsigned for peace of mind.
 
Running in to an issue setting msg.seq - compiler is throwing an error say CAN_message_t is read-only:

My code:
Code:
void relayFrame(const CAN_message_t &frame) {
  // Take incoming frame and send to other bus
  frame.seq = 1;
  if(frame.bus == 0 && can1Enabled) {
    Can1.write(frame);
  } else if(frame.bus == 1 && can0Enabled) {
    Can0.write(frame);
  }

Error relating to line frame.seq = 1:
Code:
/home/david/Arduino/ObjectOrientedCAN/CANalyzer.ino/CANalyzer.ino.ino: In function 'void relayFrame(const CAN_message_t&)':
CANalyzer.ino:72:13: error: assignment of member 'CAN_message_t::seq' in read-only object
   frame.seq = 1;
             ^
exit status 1
assignment of member 'CAN_message_t::seq' in read-only object

Any ideas as to what's up? I'm going to switch to Canx.write(MB15, frame) for now as this should have the same effect of forcing FIFO on transmit, right?

I'm thinking that it has to do with the const keyword in the function definitiion, but if I remove that I get a whole bunch of different errors:

Code:
/home/david/Arduino/ObjectOrientedCAN/CANalyzer.ino/CANalyzer.ino.ino: In function 'void setup()':
CANalyzer.ino:21:28: error: invalid conversion from 'void (*)(CAN_message_t&)' to '_MB_ptr {aka void (*)(const CAN_message_t&)}' [-fpermissive]
   Can0.onReceive(relayFrame);
                            ^
In file included from /home/david/Arduino/ObjectOrientedCAN/CANalyzer.ino/CANalyzer.ino.ino:1:0:
/home/david/Arduino/libraries/IFCT-master/IFCT.h:197:10: note:   initializing argument 1 of 'void IFCT::onReceive(_MB_ptr)'
     void onReceive(_MB_ptr handler); /* global callback function */

          ^
CANalyzer.ino:27:28: error: invalid conversion from 'void (*)(CAN_message_t&)' to '_MB_ptr {aka void (*)(const CAN_message_t&)}' [-fpermissive]
   Can1.onReceive(relayFrame);
                            ^
In file included from /home/david/Arduino/ObjectOrientedCAN/CANalyzer.ino/CANalyzer.ino.ino:1:0:
/home/david/Arduino/libraries/IFCT-master/IFCT.h:197:10: note:   initializing argument 1 of 'void IFCT::onReceive(_MB_ptr)'
     void onReceive(_MB_ptr handler); /* global callback function */

          ^
exit status 1
invalid conversion from 'void (*)(CAN_message_t&)' to '_MB_ptr {aka void (*)(const CAN_message_t&)}' [-fpermissive]
 
yes thats read only

you could copy it to modify it

CAN_message_t copyFrame = frame;
copyFrame.seq = 1;

modify everything in copyFrame.
 
Teensy blocks during write on bad CAN bus conditions

Dear tonton

Your code works very well in my system. So I decided to do some stress tests.
If I wrongly configure my can bus with wrong resistors/cable etc. I can generate a situation where the teensy almost completely blocks (USB lost, loop execution extremely slow)
This only happens by putting data on the bus, i.e. the write function. If I only listen to the bus its ok.

Any idea to release this blocking state or what ever it is?

Best Elo
 
Does it restore when you properly fix the cables/resistor? The problem is your trying to access the registers despite being in a bus off state. Can you reproduce this between 2 teensies? Also if you can try out an alternative test using FlexCAN_T4 library to see if it works on your board, compatibility was added but only tested on a Teensy 3.5

The write function ends at writeTxMailbox() in the source, perhaps you can try to comment out the whole function, and uncomment one line at a time to see where it gets stuck, and report back?
 
Does it restore when you properly fix the cables/resistor?
The write function ends at writeTxMailbox() in the source, perhaps you can try to comment out the whole function, and uncomment one line at a time to see where it gets stuck, and report back?

Good Idea! Yes, it restores properly after fixing the bus.

I tracked down the blocking to this line:

Code:
  FLEXCANb_MBn_CS(_baseAddress, mb_num) = (FLEXCAN_MB_CS_CODE(FLEXCAN_MB_CODE_TX_ONCE) |
                                      FLEXCAN_MB_CS_LENGTH(msg.len) |
                                      ((msg.flags.remote) ? FLEXCAN_MB_CS_RTR : 0UL) |
                                      ((msg.flags.extended) ? FLEXCAN_MB_CS_IDE : 0UL) |
                                      ((msg.flags.extended) ? FLEXCAN_MB_CS_SRR : 0UL));
 
Thats the register for the code field, so i dont see how it gets stuck there, can you print something in serial monitor before and after that line to see if it prints both texts?
 
I have a similar situation, but I believe my bus is correctly terminated. For me everything hangs when I inject messages over serial to be written to the bus. Reading from one controller and writing to the other works fine (Teensy 3.6). I was unable to determine if it was an issue with the Serial bus or the CAN bus. I switched back to FlexCAN to get my project running as I was still in the early development stages, but now that I have a stable application I can do some more testing with IFCT.
 
tonton,

I did some more testing with an additional serial monitor and figured out: It is not a block but actually a reset! (watchdog is off)
Its so fast that I was thinking its a block and since the USB got lost I was not aware of the reset.

So to make it clear, the code line generates a reset in case of a bad CAN bus setup:

Code:
  tic = micros();
  FLEXCANb_MBn_CS(_baseAddress, mb_num) = (FLEXCAN_MB_CS_CODE(FLEXCAN_MB_CODE_TX_ONCE) |
                                      FLEXCAN_MB_CS_LENGTH(msg.len) |
                                      ((msg.flags.remote) ? FLEXCAN_MB_CS_RTR : 0UL) |
                                      ((msg.flags.extended) ? FLEXCAN_MB_CS_IDE : 0UL) |
                                      ((msg.flags.extended) ? FLEXCAN_MB_CS_SRR : 0UL));
  Serial2.print(F("time in [us]: "));
  Serial2.println(micros()-tic);

If the bus is correct this is the Serial ouput:
HTML:
time in [us]: 7

If it is wrong:
HTML:
timý
Start

"Start" is printed out after the reset in the setup method.
 
Weird, that register shouldnt do anything except activate the mailbox in hardware, did you try it in another teensy?
 
@tonton81,

I have a project that I'm thinking of using a CAN link for robust communication between two elements. I haven't had an opportunity to dig into CAN prior to this application so I've found some generic references on the protocol. I believe I understand the "mask" and "filter" concepts, but I haven't found good descriptions on "mailboxes" and "FIFO" operations, especially in various libraries.

I found references to your IFCT library while researching available libraries for the Teensy family. I'm wondering if it would be a hardship if you could write some sort of description for your API and an accompanying explanation of the messaging concepts, particularly the FIFO and mailbox operations. I find the examples ok but they seem a bit incomplete and are no substitute for at least some sort of documentation. I certainly don't want to have to reverse engineer your code to figure out what's going on. I'd rather be able to use an API description and get on with my application. It would be very beneficial to have some description after all the hard work you put in to creating this library.

Thanks in advance for any consideration.

Regards,
Glenn
 
Yes, thanks for the concern. I hopefully will have finished off the FlexCAN_T4 which would be a successor to IFCT in terms of performance, while maintaining the Teensy 3.x compatibility. If there are any bugs, I'd like to set notes and work on those as priority. Documentation will be worked on shortly. As a side note, with mask and filters, the library is fully automated to handle those features to make it easy for the user to select what IDs he wants, and the hardware would mask out the rest, filters and masks are computed by the library code, with support for single, multiple, and range of IDs
 
@tonton81,

Thanks for the update on the library direction and the sequence of tasks. I certainly can appreciate your situation trying to wrap up the new library. Looking forward to the new version with Teensy 3.x backward compatibility and the documentation down the road.

In the meantime I'll experiment with the library to see if I can at least get a start on understanding the features and operation.

Best Regards,
Glenn
 
Hello everybody. Awesome work and quite extensive features in those libraries! Very good! Thank you very much.

I'm using FlexCAN_T4 on a teensy 3.2 with great success! Two teensy's 3.2. with a round trip time of 280uS on 500kBits. This is with diodes and also with CAN transceivers.

I have a hard time to understand the masks since they are set automatically.

I have two kind of messages (ext IDs) that I want to get in two MB's.:

0x14060050 to 0x1406FF50 should go to MB 1
0x14060051 to 0x1406FF51 should go to MB 2

So basically my selector is the last byte where I'd like to filter through 00-FF of the next higher byte. Wouldn't that be feasible by setting a mask like FFFF0050 and FFFF0051 or how can this be done? Is it possible to set such a mask or by using setMBFilterRange maybe with a clever ordering without using the distribute function?

Any help would be highly welcomed here. Thanks!
 
Are you looking to only save 2 IDs? Mailboxes can be completely custom configured. If you plan to use filtering it is highly recommended to put your priority ID filters in the leading mailboxes and have the catch-all frames mailboxes at the end of the mailbox lists. First you must reject-all ids from all mailboxes using can.setMBFilter(REJECT_ALL). If you are using FIFO, youll have to run setFIFOFilter additionally to reject all before setting the IDs you want to collect. Distribution is for overlapping mailboxes. Remember only the first mailbox to catch the frame collects it, no one else. So only that handler would get called and not the other one if you have set. Distribution basically makes 2 or more mailboxes with matching acceptance filters clone it to the queue for the additional callback to fire as if it received it there as well. Also keep in mind if you have 2 or more mailboxes accepting the same IDs in hardware, the last mailbox in line will constantly be overflowed with the latest frame if not read in time.

If you only want to catch 2 frames you can reject_all then apply the filters to the first 2 mailboxes, however, by default (with fifo disabled) the lower half of total mailboxes are STANDARD while upper half are EXTENDED. If you really want to change the state of mailbox1, use can.setMB(MB1, RX, IDE); Then set your filter with setMBFilter(MB1, 0x14060050); you can use ranges too, but what you request is simply not possible. I've only written multiple ID (up to 5) and ranges (1,7 == 1,2,3,4,5,6,7). I mean, it can be done provided an algorythm of some type is used, or if a user would input a masked area to include only, then yeah, but thats complex stuff right there. You could also set a custom mask but that implementation wasnt done to automatic versions, so new functions would need to be implemented if you were to provide your own filter

My question is, why not filter the FF in your callback instead? :)
 
Thanks tonton81. That's quite clear to me now. Yes I wanted to ask if custom filters/masks would help me here but now it's clear.
Since this is my own protocol, I can change the meaning of the bytes. I will change the lowest byte with the next one so that I have use a "steady" right-justified filter predicate like this:
0x14065100 to 0x140651FF for any messages that has to be processed in the callback handling 0x51 messages
and
0x14065000 to 0x140650FF to any messages that has to be processed in the callback handling 0x50 messages

With this I have my range (which indicates an object Id going from 00 to FF) at the LSB so regular filtering will work.

Can.setMBFilterRange(MB2, 0x06 << 16 | 0x50 << 8, 0x06 << 16 | 0x50 << 8 | 0xFF); //message type 1
Can.setMBFilterRange(MB3, 0x06 << 16 | 0x51 << 8, 0x06 << 16 | 0x51 << 8 | 0xFF); //message type 2

Can I ignore the 0x14 leading byte?

Thanks!
 
All bits (0x14) must be set to checked so no you cannot omit it, the hardware will simply toss it out as bad match, everything else is ok.
Your filters are done in hardware for best performance, so its up to the SMB to decide whether to put it in a matching mailbox, or throw it out and move on. The full ID must be specified, or in your case you bit shifted one together, and the corresponding mask is generated on it. If the ID in the stream is AND'd to the mask in the hardware and it matches the local ID (one or many you chose), again, AND'd, only then would the hardware pass it to the mailbox. Distribution uses.this type of method for cross mailbox referencing. If you use multiple ids or ranges and have any bleed-thru frames, there is enhance filtering capability of the library. Running that will ensure only the IDs you requested get dumped and queued for retrieval, amd the bleed-thru frames are tossed (basically a sub filter implementation by software after the hardware pulled in a frame)

FIFO filtering is a little bit more complexed. Tables A and B are implemented for filtering, C and D are not due to the partial ID captures, it makes no sense to have that type of support on a bus with less than 60 nodes with 64 mailboxes............ if you are looking for sequential frame capturing, FIFO is 6 messages deep, and by default the remaining mailboxes are set as TX, so you have multiple transmit buffers and only FIFO. But at that point you cant have separate callbacks, youll only have one. However, you CAN (pun intended) have FIFO AND mailbox support, your first mailbox will be MB8, FIFO consumes 8 mailboxes, 6 for frames, 2 additional mailboxes for 8 filters.
 
Ok! I make sure I bit shift the 0x14 in the filter criteria then. Thanks. I'll do some tests and come back about the filters should I get some surprises. I'll keep the enhanced filtering methods in mind also.

I never really understood the needs for FIFO - maybe it's just my application use case that doesn't need it? And since this is independent of the sequential flag, I don't really get it. All I want is to get my messages based on the selector (my 2nd last byte) in each of the MB's in a way that when the sender sends a message 0x....5001 and then 0x....5002 that 0x...5001 is first appearing in the MB with interrupts that handles the 0x...50... messages (filterrange set to 0x....5000 to 0x....50FF on this MB). If in the meantime another MB fires, that's OK. How can messages appear in wrong order? When is it time for FIFO and when for sequential flag mode?

Also: Is there a way to access the ESR1 register? I'd like to know if there are any bus errors. Since I use the internal CAN processor hooked to a CAN transceiver - does the processor know about errors on layer 1 such as shorts of CAN High to Ground etc. or is it only on layer 2 errors?
 
If you have more than one mailbox accepting the same frames, then they can be in any order. Thats why people have 2 options.
Ordered by FIFO, or run single mailbox mode (reject the rest or switch them all to TX).

Yes the ESR1 is there in hardware, however, i have not implemented it yet in software. That is still a todo thing on the list
 
I managed to read out the ESR1 register as a workaround until it'll be in the library.

But I have a new problem ;-(

I can send exactly one extended frame (2 bytes payload) every 50ms without a problem. I have a Metro timer in my loop(), fill up my CAN_message_t struct and send it with Can0.write(msg);

When I increase the timer to lower than 50ms or when I want to send two frames each 50ms, things are not robust.

I print the result of Can0.write to Serial. Sometimes it stops sending and suddenly stops logging (the whole system seems to freeze then), sometimes it stops sending but the logging goes on with a successful result code, sometimes seq=1 changes the behaviour for a while. Sometimes unplugging the bus doesn't change a reported successful write, sometimes starting without the bus, then connecting the bus, goes for a couple of messages etc... all in all it's hard for me to debug where exactly the problem lies.

- The frames should get ACK'd (how to verify?) - there is another node (only two nodes in total) that listens to those frames. The callback of the receiver doesn't really have long running code. At 50ms all is fine.
- The transceiver is not the problem - same situation using diodes
- 500k or 1M baud doesn't change the behaviour
- termination with 2x120 Ohms at each end using transceivers MCP2551 (5V)
- RS pin pulled to Ground
- using FlexCAN_T4.h on Teensy 3.2 (both nodes)
- sending a single message every second and echoing it at the other node gives me roundtrip times of 280uS - that's excellent! However this is a standard ID frame.

Something seems to be "overflowing" but I don't get how to tackle this. Is there a back pressure on write to the timer - is there such a thing as writing too fast? how can I make the write synchronous so it blocks during accessing the bus (and waiting for the ACK?)? Am I saturating the bus already with 50ms 1 extended frame 2 bytes payload?

I'd like to ask how you guys narrow this down, are there best practices maybe a short ino code that is well known to work and writes "as fast a possible" repeatedly the same message showing how to setup TX MB's and the flags etc... ?!

Maybe the library is known to be problematic on T3.2 on such performance needs?

Any help is much appreciated.
Thanks.
 
You have "X" amount of mailboxes in TX mode, if you constantly write faster than they deplete they wont be able to output and a return of 0 will occur until at least one is available to write. Next, the sequential transfers (msg.seq = 1) is able to queue them in series, UP TO the size of the transmit queue should the absolute first TX mailbox be busy when writing too fast. Overflowed queues will be pushed and tossed, you need to take your network into consideration, and congestion. Standard IDs have priority over extended IDs, and the lowest ID has highest priority, so if your sending extended frames flooding the bus when standard frames are doing same, your mailbox will attempt a resend on next attempt if it looses arbitration
 
holynoise, I was just thinking, with enhancements off and in multi ID mode, your original ID may probably work

Can.setMBFilter(MB1, 0x14060050, 0x1406FF50); /* 2 ID multi-ID mode, non-range based */
Can.setMBFilter(MB2, 0x14060051, 0x1406FF51);

Just don't use enhancements, it may just work (untested), all the frames in between should bleed-thru the hardware filter and receive properly in their respective mailbox
On another note, each individual mailbox, and fifo, has it's own sub filter enhancement support, so you can choose which ones you want sub filtered, or in your case for both mailboxes, leave their enhancements off, else you will only receive those 2 IDs :)
 
Status
Not open for further replies.
Back
Top