Description
API component
CAN
Description
Clarify the order in which CAN.write()
will send frames with the same priority. Specifically, define whether buffered frames will be sent in transmit order, ordered by priority, or without an ordering guarantee.
if the frames are not buffered by the API implementation then there is no issue. However, if they are the behaviour is currently undefined. I'm raising this as an issue for the API as it's part of the contract between the user and an implementation.
This affects protocols such as RV-C or NMEA2000 where messages may require multiple frames to transmit. Mechanisms such as ISO-TP or NMEA's Fast Packet transmit message segments using the same CAN ID with sequencing information contained in the frame's data. Some devices are known to require segments be received in order, effectively requiring the sender to ensure they are transmitted in order. CAN's inherent prioritization by ID does not help as the ID is the same for all message segment frames.
There are a few ways this could be addressed:
- Define the transmit API to be unbuflfered placing the application in control.
- Only support in-order transmission
- Extend the API to allow the transmit ordering to be configured
- Extend the API to allow the application to manage the state of buffered messages to control ordering
The first is the simplest option and matches the current behaviour of the Renesas core. The API change would simply be to define that behaviour in documentation so application code can rely on it.
The second would allow an implementation to use buffering providing the transmission order can be guaranteed. This could be achieved with a software ring buffer or hardware transmit FIFO. The downside is that it would not support pre-emption, allowing a higher priority CAN message to be transmitted ahead of those that are buffered. However, an application that needs that could still implement it by handling the queues itself.
The third and fourth add complexity to this API that probably can't be justified as it would be closely coupled to hardware capabilities anyway; an application that needs it would be better served using the underlying hardware APIs directly.
Proposal
Add documentation to the API class that states:
-
CAN.write()
will always send messages in the order in which is called. -
CAN.write()
may buffer messages providing it ensures that they are transmitted in order (e.g. using a hardware FIFO). The number of messages that can be buffered is implementation defined.
Is this a breaking change?
No. Any API changes would be additive.
The current Renesas cores are unbuffered using a single mailbox for transmission and return an error if that mailbox is busy.
I don't know of other cores using this part of the API especially as it's a fairly recent addition.
Additional information
Many CAN controllers allow multiple frames to be buffered for transmission, for example, by providing:
- transmit mailboxes
- transmit FIFOs
- transmit priority queues
Problems can occur when an implementation uses multiple transmit mailboxes and where the hardware implicitly prioritizes transmission by mailbox number. For example, if the hardware has three mailboxes and the message requires more than three frames, the following sequence can occur
- First frame is queued in mailbox 0 and transmission is started
- Second frame is queued in mailbox 1
- Third frame is queued in mailbox 2
- First frame send completes, freeing mailbox 0
- Hardware starts send of mailbox 1 as that is the highest priority one with pending data
- Fourth frame is queued in mailbox 0
- Second frame send completes, freeing mailbox 1
- Hardware starts send of mailbox 0 (now containing the fourth frame) as that is higher priority than mailbox 2
As a result segment 4 will be send ahead of segment 3.
This would not occur if the mailboxes were used in FIFO mode as the hardware would then send mailbox 2 ahead of mailbox 0.