MultiCAN+ FIFO, how is it intended to be used?

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
User15596
Level 2
Level 2
MultiCAN+ on the XMC1404.

2 Nodes in are setup in loopback (shouldn't be called loopback because it sends from one node to the other on the internal CAN bus, should be called Internal Bus Mode).

Each node has 1 message object for transfer and 4 MO's for reception in a FIFO. Node0 has List1, Node1 has List2.

The only given CAN_RECEIVE(...) functions in the XMC both have an argument that asks which message object I want to read from. Meaning I need to know "where" in the FIFO I am at any time....


  • How am I supposed to know there the tail of my pointer is?
  • Does the MultiCAN+ module really give you a FIFO without any way to track how many messages are currently in the FIFO and where the tail / oldest message is?
  • Am I just supposed to read messages as absolutely fast as possible to mitigate overflow - and keep track of the tail myself?



It seems to me that by the base object a CURRENT pointer, a TOP and BOTTOM, that I'm missing some rather important data about how many messages are actively stored at any given point in time.

Thanks. SR
0 Likes
5 Replies
DRubeša
Employee
Employee
First solution authored First like received
Hi SR,

have you maybe checked the "MULTICAN_CONFIG_EXAMPLE_XMC47" example where we show the FIFO functionality (together with Gateway but that´s not important in your case)? There you can see how CUR, TOP and BOT are set and how they are changing during the reception of a message.

Best regards,
Deni
0 Likes
User15596
Level 2
Level 2
Deni,

That's the example we've been following. The issue is... That example only sends one message, reads immediately then and stops. That example has only one receive object, not a fifo. It has a TX fifo for MO1 & MO2 List2 Node1, but this example only ever transmits on MO2 explicitly. Explicitly sending isn't using the FIFO at all it seems.

A FIFO example that sends one message using a specific message object and then receives explicitly at a non-FIFO message object is exceptionally useless to us.

Please see these pics where CUR does move, BOT and TOP do not.

3238.attach
1 message received. Started at 1, received into 1. Now "current spot next message will be stored" is 2.

3239.attach
Then 4 messages received. Rolled over back to 1 which is the next empty spot in the list.

To stay on topic and not get mixed up in whatever Gateway stuff that might be there... The BOT and TOP registers never move, and it seems they shouldn't these are constrained in the list. The CUR moves as messages comes in, this is the FIFO HEAD, the location where the LATEST message is stored. If CUR gets up to TOP it rolls back to BOT, this makes sense. BUT......... FIFOs have a head (CUR) AND a tail. The TAIL should be where the OLDEST message is stored.

  • How am I supposed to know there the tail of my FIFO is?
  • Does the MultiCAN+ module really give you a FIFO without any way to track how many messages are currently in the FIFO and where the tail / oldest message is?
  • Am I just supposed to read messages as absolutely fast as possible to mitigate overflow - and keep track of the tail myself? This does not seem likely as MultiCAN+ seems to be a very complex CAN peripheral and this is extremely basic FIFO functionality.


Please let me propose this scenario....



  • TX Message Object 0
  • RX FIFO 1-4
  • FIFO is empty, my fifo tail=0
  • CUR = 1
  • Receive 10 messages
  • 4 will be stored in the objects I have, and 6 lost, all objects will have their MSGLST bits set.
  • CUR=3 because we "looped over" 2.5 times
  • If I am polling CAN, I will not know my oldest message is actually at Message Object 3 (7th message received)
  • If I "missed" the messages coming in, I will still think my oldest is at Message Object 0 (9th message received)


The only way this makes sense to not give us a FIFO Tail is if this is not intended to properly recover from for an overflow event. Or if you can protect for an overflow by reading the MSGLOST bits and fixing the issue before you lose all objects. Because... once you lose all objects, there seems to be no way to detect where the oldest message is (the reason we want a FIFO at all!).

Please see pic for MSGLOST bit
3240.attach
0 Likes
lock attach
Attachments are accessible only for community members.
DRubeša
Employee
Employee
First solution authored First like received
Hi S R,

in the attachment to this email you will find an example that´s based on the case you mentioned in your latest post. Now, this example isn´t solution to your problems, it´s more as an example to show certain functionalities and in which direction you should go to resolve your issue. A little bit of rambling about your post and an example I´ve provided. You correctly noticed that a TOP and BOTTOM pointer are fixed and initialized beforehand. CUR is a hardware controlled pointer whose role is as you mentioned in your post, to track the message object where the next message will be received.

What happens once you fill the FIFO and CUR value becomes equal to BOT pointer? You get the overflow and next received message will overwrite the OLDEST message in the FIFO, a message that was stored at the BOT location. As is quite apparent, a first message will be stored at the BOT location, following at the BOT +1, until the CUR == TOP and then next one will wrap around. Message overwriting each other is not what we want...it will cause the Message Lost flag to be set. So we want to readout the data to prevent overwriting to occur. In the example I´ve made I took the most basic scenario; I wait until whole FIFO (4 elements) is full, an FIFO overflow interrupt is raised and then inside of ISR I read all the FIFO elements. Then the transmit continues starting from the first element of a FIFO (BOT pointer) and so on. I´ve received 10 different messages 10 times and I don´t see any message lost (feel free to run the example yourself). However, this is the loopback mode where I transmit and receive on the same core so I cannot have any issues due to the not sufficient amount of time to read the FIFO. In real life application you will have following situation; your RX FIFO will be filling and you need to be able to readout the data before overwriting occurs. There is additional pointer you may use (we covered TOP, BOT, CUR); pointer SEL. This pointer can be used to define the message object in the FIFO which will cause the interrupt once it´s reached. Once the CUR == SEL, interrupt is called and you may read out the data. However, some general advice how to due it I cannot give it to you while it all depends on your application.

You can try this approach that I mentioned above...once the FIFO is full readout the data until you have read out whole FIFO and then on the next FIFO overflow you do the same and so on. Just be aware that the CPU will stay in the interrupt routine for quite some time...if this is not desirable (and mostly it isn´t), you may try to use DMA to speed up this process and exclude CPU moving data around. You may also rely on the RX interrupt flag set by the RX FIFO base object once the new message is received in the FIFO structure. It all depends what you find better.

And to finish this already too long post off, to answer your questions:

How am I supposed to know there the tail of my FIFO is?
--> one the first readout instance tail is equal to BOT while the first (oldest) message will be located there. If you´re reading whole FIFO out at once, then the tail is always equal to BOT. However, if you´re reading part after part of FIFO than you should track what was the last message you have read and then the oldest message would be the location of that message + 1.

Does the MultiCAN+ module really give you a FIFO without any way to track how many messages are currently in the FIFO and where the tail / oldest message is?
--> similarly to first answer, depends on your FIFO usage. If you read at once whole FIFO then how many messages is in the FIFO = CUR - BOT. If you read something already, then you track by yourself.

Am I just supposed to read messages as absolutely fast as possible to mitigate overflow - and keep track of the tail myself? This does not seem likely as MultiCAN+ seems to be a very complex CAN peripheral and this is extremely basic FIFO functionality.'
--> see the answers above. Overflow is not necessarily bad thing, it provide you a signal when you can start reading the data out. What is bad is overwriting, and that will happen if you don´t read the data quick enough.



Best regards,
Deni
0 Likes
User15596
Level 2
Level 2
DRubeša,

Thanks a ton! That's an excellent post with good information. It's obvious you put a lot of time into it, along with the example and "offical" support or not - things like that go a long way into giving us some confidence in selecting the Infineon chips.

That said, I'm a little dissapointed such an obviously complex and robust CAN module has such a minimalist FIFO. I get that this is probably directed more towards a CAN system that has acceptance filters and specific "mailboxes" per ID, but still, having to track our own fifo tail for rx or head for tx is a little surprising.

Your example was very clear and easy to read, however, it seems to wait for FIFO FULL before any reading is done, this allows you to use the CURRENT as it will roll over back to fifo BOTTOM. This isn't practical for us. For one, we don't know another message will come during the middle of a fifo maybe some imortant data came and now bus is off. And two, like you said about CPU delay/latency in regards to DMA, it doesn't seem like a prudent thing to have no available buffers before I can empty them. However, point was still effective.


The shortest possible realization for us is that you're really not supposed to overflow the fifo, there are very limited options you have once that happens and you can't then be sure of where your actual oldest message is. That's fine. We'll work around that by putting in an additional software FIFO that's a lot more suited to the application. The idea is we'll get the messages out of the hardware registers / DAVE software config and into our FIFO where we can track them and route as needed. This is something we had to do regardless, the only difference is we'll take more care to not loop the hardware fifo over and to keep track of the tail manually.


Seriously, thanks again for the support. This is a complicated peripheral but we now have a better understanding of how it was intended to be used.
0 Likes
DRubeša
Employee
Employee
First solution authored First like received
Hi S R,

firstly, I would like to thank you for the appreciation...it´s nice to know you find that post helpful.

I have some comments also on your latest post. Especially regarding this line:
"This isn't practical for us. For one, we don't know another message will come during the middle of a fifo maybe some imortant data came and now bus is off."

I agree that in such a scenario our module and it´s FIFO implementation would be not so practical, however this is not the case here :).

Let´s assume the following scenario. You have XMC1400 as a RX side in the CAN network. You defined and configured RX FIFO base object together with it´s slave objects. You enable FIFO overflow interrupt generation as I done in my example and your code is in while loop/idle state/doing something else and waiting for a CAN FIFO to be filled. While you´re waiting for a CAN FIFO to be filled (and FIFO overflow to be triggered), messages are received in the FIFO and CUR pointer is increment for every new message WITHOUT CPU intervention. CAN module state machine and hardware are doing everything on their own. You have configured everything at the beginning...ID filtering, number of slave objects, etc and now the CAN module is "doing its thing".

Once the interrupt comes, CPU goes into ISR and starts reading RX FIFO messages in any order you prefer. I would suggest from the BOT pointer (while it contains the oldest message) to the TOP pointer. And now the cool part; while you´re reading messages, CAN bus is NOT off...new messages will be received whole time even though you´re reading message objects. Imagine CAN module as several smaller sub-modules where one sub-module is connected directly to CAN bus and receives the messages, then one sub-module does the filtering and decides about acceptance criteria, one as RAM storage where all the data received is stored and so on...All these modules are controlled by state machine but more importantly they all work to be done in parallel. So CPU can access this "RAM storage" sub-module to read the message data field while other sub module is doing receive on the bus. Now you can see that only critical point is is there enough time once the FIFO overflow happens to readout the first message before it will be overwritten by the next received message. If you manage to readout the first message before overflow, you will have valid data and all other message objects will be readout without any collision while interrupt routine will be faster then new CAN message coming on a bus. Let´s investigate this corner case then, were we need to readout the first data before it gets overwritten.

This would be the easiest to explain with some animation but I will try with the text description nevertheless. So initial state is that we have a RX with 4 elements as done in the example. Let´s assume that CUR points to last element in the FIFO (so CUR == TOP), meaning next message will fill the FIFO and FIFO overflow event will be triggered. A new message is received, hardware automatically sets CUR pointer to BOT pointer, CUR is now equal to SEL and interrupt is triggered. This will happen immediately after the last message in the FIFO is received. Now let´s discuss a bit about CAN protocol itself. I don´t know exactly about your planned CAN network load (how much time will something be sent over CAN bus). I will take the worst case possible which is not possible in the real application but just for the sake of calculations. Let´s assume you have 100% CAN bus load (no idle times, after one CAN message comes next one immediately). CAN baudrate...500kbit/s why not...now for the message data length...it can be from 0 to 8 bytes (I don´t know for your exact requirements but I´m pretty sure you will try to use the as much data field as possible to improve CAN bus utilization). So I will take for my example 8 bytes of data. Except data field what do we have more in CAN format...arbitration field (13 bits), reserved bit, control field (4 bits), CRC field (15 + 1 bit), End Of frame (7 bits) and intermission phase (3 bits)....together with 8 bytes of data field (64 bits) we can assume we have 108 bits (give or take if I have maybe forget some bits) to be received by the CAN RX module. With 500kbits/s these 108 bits to be received will take 216 us. So we have 216us before our oldest message will be overwritten.

XMC1400 runs on 96 MHz and if take we assume that every ARM assembly instruction take 1 clock cycle (to simplify things) you can perform up to 20735 instructions...and how many instructions you need to read first (as I previously mentioned first message is critical one, later one you will read for sure without issues if you manage the first one) message. Well, definitely less than 20000 😛 Of course there is some time before the message is received and hardware increments the CUR pointer and "detects" CUR == SEL and raises interrupt flag but 216us is quite some time in embedded world.

So, here are some thought of mine and some rough calculations to provide some plausibility to them...let me know if something is obviously wrong with my observations but I hope that you see that there is quite some possibilities with the MultiCAN+ module and that you be pretty creative with it.

Best regards,
Deni
0 Likes