2022-10-04 09:07 AM
Hello,
I am using an STM32H7B3I-EVAL board with a STM32H7B3LIH6Q MCU.
I am looking to use FDCAN to communicate with multiple nodes and someone recommended using mailboxes for messages sent/received. The documentation was unclear, so I wanted to ask if Mailboxes are a feature with this MCU?
Solved! Go to Solution.
2022-10-04 04:12 PM
In a multi-core controller, a hardware mailbox peripheral is used to pass messages between cores. In your case, with a single M7 core, there are no hardware mailboxes. A software-based mailbox is essentially a single-entry queue. For a CAN protocol stack, incoming RX messages are removed from the CAN hardware RX FIFO and placed in the queue during the RXFIFOx interrupt. The CAN protocol task unblocks when a message is placed in the queue. The task removes the message and processes it through the protocol services.
The CAN RX and TX buffers are based on hardware and have a fixed size and functionality. If you set up the CAN filters properly you can route incoming CAN messaged to either FIFO0 or FIFO1, a two-level priority scheme. Depending on what RTOS you use any message in the high priority FIF00 buffer is inserted at the head of the CAN message queue, so it is handled out of sequence. FIFO1 message are inserted at the queue tail and are handled in the order they arrive.
I don't recommend a single entry, mailbox type queue to store and forward incoming CAN messages. If the CAN protocol stack is busy there's an excellent chance RX messages can be dropped when the RX FIFO overflows. I use FreeRTOS and a queue with multiple entries to avoid this. FreeRTOS queues also support inserting new messages at the head of the queue.
Keep in mind some complexities when using prioritized messages. For example, you can receive an emergency shut down for a pump, followed by an earlier normal status message from the same node.
Also, if you have two writers to a single queue, you might want to set the interrupt priority for both RXFIFO interrupts to the same level, preventing a queue write from being pre-empted. In FreeRTOS you can set up two queues to avoid this problem, but the protocol task has to check both queues when unblocked, and an event group has to be used to wake up the task. If you expand your application to fault tolerance, with dual CAN buses, there are some advantages to multiple queues.
And no, mailboxes are not like the TX and RX buffers on the CAN peripheral. The CAN FIFOs are hardware specific; a mailbox is a type of inter-task queue.
Jack Peacock
2022-10-04 10:00 AM
A mailbox is a type of first in-first out queue, suitable to most CAN protocols. Mailboxes can be limited to a depth of one, so a fast response is required for the CAN protocol stack on the receiving side.
A mailbox is not ideal for some CAN protocols, notably CANopen, where priority messages arriving out of order take precedence over messages already arrived but not yet processed. One of the reasons the CAN peripheral has two RX FIFos is to route high priority, safety related messages (i.e. EMCY and SRDO) to a separate, high priority message queue, or inserting messages into the head of the single CAN RX message queue.
Short answer, if there are no priority or performance issues then yes, use a mailbox.
Jack Peacock
2022-10-04 10:30 AM
Hello,
Thank you for your reply! Two follow-up questions:
1) So there is no difference between a 'mailbox' and an 'RX/TX FIFO'?
2) I can define filters where high priority messages are sent to, say, FIFO0 and then send lower priority messages to FIFO1 and write the software such that, if FIFO0 has a message, it will process it, even though there are messages that arrived first in FIFO1?
2022-10-04 04:12 PM
In a multi-core controller, a hardware mailbox peripheral is used to pass messages between cores. In your case, with a single M7 core, there are no hardware mailboxes. A software-based mailbox is essentially a single-entry queue. For a CAN protocol stack, incoming RX messages are removed from the CAN hardware RX FIFO and placed in the queue during the RXFIFOx interrupt. The CAN protocol task unblocks when a message is placed in the queue. The task removes the message and processes it through the protocol services.
The CAN RX and TX buffers are based on hardware and have a fixed size and functionality. If you set up the CAN filters properly you can route incoming CAN messaged to either FIFO0 or FIFO1, a two-level priority scheme. Depending on what RTOS you use any message in the high priority FIF00 buffer is inserted at the head of the CAN message queue, so it is handled out of sequence. FIFO1 message are inserted at the queue tail and are handled in the order they arrive.
I don't recommend a single entry, mailbox type queue to store and forward incoming CAN messages. If the CAN protocol stack is busy there's an excellent chance RX messages can be dropped when the RX FIFO overflows. I use FreeRTOS and a queue with multiple entries to avoid this. FreeRTOS queues also support inserting new messages at the head of the queue.
Keep in mind some complexities when using prioritized messages. For example, you can receive an emergency shut down for a pump, followed by an earlier normal status message from the same node.
Also, if you have two writers to a single queue, you might want to set the interrupt priority for both RXFIFO interrupts to the same level, preventing a queue write from being pre-empted. In FreeRTOS you can set up two queues to avoid this problem, but the protocol task has to check both queues when unblocked, and an event group has to be used to wake up the task. If you expand your application to fault tolerance, with dual CAN buses, there are some advantages to multiple queues.
And no, mailboxes are not like the TX and RX buffers on the CAN peripheral. The CAN FIFOs are hardware specific; a mailbox is a type of inter-task queue.
Jack Peacock
2022-10-05 11:38 AM
This is extremely helpful! Thank you so much for the detailed response.
I intend to have a fairly large FIFO queue limit (~20-50, based on experimental results).
My CAN load doesn't seem particularly high. I have 4 nodes that send about 3-5 messages each. All fast-acting fault responses are handled by the local node's controller. The main purpose of this code is to control some peripherals and display the gathered data on a display, which can be updated somewhat infrequently (250 - 1000 ms) and a baud rate between 250 - 500 kBit/s.
Given this criteria, I can't imagine bus load will be too high that messages will be dropped often, correct?
2022-10-05 03:11 PM
Though I haven't used a dual core, I am pretty sure it can out do an STM32F105 I used as a gateway between a radio and the rest of the vehicle. GM vehicles with 29 bit ID's have at least 100 messages on the infotainment system.
I am able to receive and transmit back and forth every CAN messages on CAN1 and CAN2 without CAN ID filters. I only looked for certain ID's and then would manipulate that data/or block the CAN message from passing. And that is using only one RXFIFO on either CAN controller. The key to handle that much data was the ring buffer I designed for CAN messages.
2022-10-05 09:42 PM
It all depends on your application. An M7 core should be more than enough to handle a small number of nodes on a single CAN bus. I've used a network of four STM32F4 based nodes with a far higher message rate with no problems.
I do recommend a good RTOS and a CAN protocol stack. My personal choice is FreeRTOS and the CANopen protocol, which is designed specifically for process control type environments rather than the somewhat messy J1939 automotive stack (the object dictionary on J1939 is a nightmare). CANopen has a well-defined range of services and excellent documentation on the object dictionary for each service. If you're connecting to a vehicle then, yeah, you have to use J1939, but be prepared for lots and lots of proprietary objects with no documentation other than what someone has reverse engineered.
CAN isn't Ethernet; messages are short and in a good design don't require point to point handshakes like TCP. Network overhead is tiny in comparison, which gives you lots of CPU cycles for application work.
The one drawback I've found for CAN, especially on ST controllers, is handling certain bus conditions at startup and if nodes fail during operation. CAN requires a minimum of two working nodes; otherwise, the CAN controller is flooded with errors. That's how it's supposed to work, but it still requires some finesse to power up one node at a time on a CAN network. Pay careful attention to the CAN status interrupt. Ignoring it is a common mistake and often leads to all kinds of frustration.
Jack Peacock
2022-10-06 06:46 AM
Hello,
Thank you for this! I will try to be mindful when I am creating my code.
Forgive my ignorance on the topic, but what do you mean by a good RTOS and CAN protocol stack? I know that there are multiple stacks in any software, but how does one implement a stack?
I apologize if these are rookie questions but, well.. I am definitely a rookie at this haha.
2022-10-06 10:08 PM
If you're using the ST supplied code then you are restricted to what they provide. I have never used the Cube, HAL or (woefully incomplete) LL libraries so I can't offer you any help. Application reliability precludes the use of code generators. Maybe someone who has used the ST CAN setup can answer? Umm, does the ST Cube code generator support any kind of CAN protocol stack?
I can tell you that at the hardware level the ST CAN peripheral is robust, reliable and works quite well. If you have issues it's not likely to be on the hardware side. Sorry I can't provide any code, don't own it. I can tell you I use the old ST SPL library ported to the L4 series, and a proprietary version of CANopen V4.
You might want to look at CANFestival, an open-source protocol stack (there are undoubtedly better choices out there by now). It has some simple examples for basic CANopen services, though I don't think it supports STM32 out of the box.
2022-10-07 07:07 AM
Hello,
As far as I know, the ST CubeMX only generates the code to initialize the CAN (Frame format, auto retransmission, transmission pause, baud rate, FIFO element size, etc.). It can also enable interrupts if a CAN message is received.
Other than that, everything else must be generated by the user.
I will create a separate post about about finding an open-source protocol stack for reference.
Thank you for the help!